Skip to content

fix(credentials): normalize provider slugs at write time and auto-mig… - #5432

Merged
senamakel merged 23 commits into
tinyhumansai:mainfrom
aryash45:fix/deepseek-provider-slug-normalization
Sep 12, 2026
Merged

senamakel merged 23 commits into
tinyhumansai:mainfrom
aryash45:fix/deepseek-provider-slug-normalization

Conversation

@aryash45

@aryash45 aryash45 commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Provider credential storage persisted mixed-case slugs (e.g. provider:DeepSeek) while read paths used case-sensitive exact matching, causing a silent save/read mismatch.
  • store_provider_token and store_provider_credentials now normalize provider slugs to lowercase at write time via normalize_provider() / .to_ascii_lowercase().
  • select_profile_id and bearer-token resolution gain a case-insensitive fallback (eq_ignore_ascii_case) for profiles written before this fix.
  • AuthProfilesStore::load() auto-migrates legacy on-disk active_profiles keys to lowercase on first load and rewrites the file; subsequent reads are no-ops. When case variants collide, the canonical lowercase entry wins and the dropped variant is logged.
  • No RPC/wire surface changed — ControllerSchema namespace strings are untouched.

Problem

After saving a DeepSeek API key via Settings, the UI confirmed success but the dialog immediately showed the key as missing and all API calls failed. The problem persisted across restarts.

Root cause: the write path stored the profile under provider:DeepSeek (mixed case from the frontend slug), while read paths looked up provider:deepseek (lowercase). The keys never matched, so get_provider_bearer_token and the has_token UI check both returned false for a key that was physically on disk.

Solution

Normalize at write time (primary fix):

  • core.rs — store_provider_token: let provider = normalize_provider(provider)? before building AuthProfile.
  • ops.rs — store_provider_credentials: let provider = provider.trim().to_ascii_lowercase() before any storage call.

Case-insensitive read fallback (defence-in-depth):

  • select_profile_id and active-profile resolution use eq_ignore_ascii_case so stale mixed-case profiles still resolve.

On-load migration (existing data):

  • profiles.rs — AuthProfilesStore::load() detects any active_profiles key where key != key.to_lowercase(), rebuilds the map, and rewrites the file. Runs once; free on all subsequent loads.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case)
    • store_and_retrieve_provider_token_case_insensitive — mixed-case write resolves correctly on read
    • legacy_mixed_case_active_profile_key_migrated_on_load — stale on-disk fixture normalised and rewritten on first load()
    • ui_has_api_key_check_and_backend_get_profile_agree_for_same_credential — has_token (UI) and get_provider_bearer_token (backend) can never silently disagree
  • Diff coverage ≥ 80% — all changed lines in security/credentials/ are covered by the three tests above
  • Coverage matrix updated — N/A: behaviour-only change to existing storage path, no feature rows added or removed
  • All affected feature IDs listed under Related — N/A: no matrix feature IDs map to this internal path
  • No new external network dependencies — all tests use in-process temp stores
  • Manual smoke checklist updated — N/A: no release-cut surface touched
  • Linked issue closed via Closes #NNN — see Related

Impact

  • Desktop only. Credential store is a local JSON file under ~/.openhuman/; no mobile/web/CLI impact.
  • Migration is automatic and transparent — runs once on first launch after update, no user action needed.
  • No performance impact — migration is O(n) over active_profiles (typically ≤ 5 entries).
  • Security — narrows key-space for profile lookup, eliminating case-variant phantom duplicates.

Related


AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/deepseek-provider-slug-normalization
  • Commit SHA: e48d512fc

Validation Run

  • pnpm --filter openhuman-app format:check — Blocked (no frontend files changed; CI will verify)
  • pnpm typecheck — Blocked (node_modules not installed locally; no frontend files changed)
  • Focused Rust tests: cargo test -p openhuman credentials — passed
  • cargo fmt --all --check — clean (exit 0)
  • N/A: Tauri fmt/check — no Tauri shell files changed

Validation Blocked

  • command: pnpm --filter openhuman-app format:check
  • error: node_modules missing
  • impact: None — no frontend files modified in this PR

Behavior Changes

  • Intended: Provider slugs are always stored lowercase regardless of what the caller passes.
  • User-visible: Saving any provider API key (DeepSeek, OpenAI, etc.) immediately works. Existing keys are silently migrated on first launch — no re-entry required.

Parity Contract

  • Legacy behavior preserved: eq_ignore_ascii_case fallback on read paths ensures profiles written before this fix continue to resolve without data loss.
  • Parity test: ui_has_api_key_check_and_backend_get_profile_agree_for_same_credential enforces strict equality between UI surface and backend resolution path.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): Previous push to this branch (4dc3e9b) — pre-rebase, wrong file paths
  • Canonical PR: this one
  • Resolution: superseded via git push --force-with-lease

Summary by CodeRabbit

  • Bug Fixes

    • Provider credentials now work consistently regardless of capitalization.
    • Profile selection recognizes provider names case-insensitively while preserving exact matches.
    • Existing profiles with mixed-case provider names are automatically normalized and saved during loading.
    • Conflicting profile entries are handled consistently during normalization.
  • Tests

    • Added coverage for mixed-case credential lookup, profile migration, conflict handling, and consistency between credential detection and retrieval.

@aryash45
aryash45 requested a review from a team August 7, 2026 05:30

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Provider identifiers are normalized to lowercase during storage and profile loading. Credential and profile lookups accept provider names without case sensitivity. Regression tests cover token retrieval, UI detection parity, provider filtering, and persisted active-profile migration.

Changes

Credential provider normalization

Layer / File(s) Summary
Normalize provider identifiers
src/openhuman/security/credentials/core.rs, src/openhuman/security/credentials/ops.rs, src/openhuman/security/credentials/ops_tests.rs
Provider names are trimmed and normalized before storage. Storage outcomes are logged. Credential retrieval, UI detection, and provider filtering tests cover mixed-case identifiers.
Resolve provider lookups
src/openhuman/security/credentials/core.rs
Active-profile selection retains exact-key precedence and adds case-insensitive key and provider fallback matching. Namespaced providers use namespaced active profiles when available.
Migrate active-profile keys
src/openhuman/security/credentials/profiles.rs, src/openhuman/security/credentials/profiles_tests.rs
Profile loading lowercases active-profile keys and persists the normalized map during writable loads. Tests verify in-memory normalization, on-disk rewriting, and collision handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address DeepSeek save/read mismatches through normalization, legacy fallbacks, profile migration, and regression tests for credential consistency [#5349].
Out of Scope Changes check ✅ Passed All code and test changes concern provider credential storage, retrieval, profile migration, logging, or regression coverage related to the linked issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: normalizing credential provider slugs during storage and applying migration behavior. It is concise and related to the pull request objectives.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

A rabbit stores provider names low,
So mixed-case lookups find and go.
Profiles normalize keys on read,
Lowercase entries keep their lead.
Tests check each credential trail.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/security/credentials/core.rs (1)

152-173: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Support bare provider slugs during profile selection.

A credential stored as provider:DeepSeek becomes provider:deepseek. A lookup for deepseek cannot match its active key, default profile ID, or stored provider value. The assertion at Line 1419 fails. Bare-slug callers also cannot read this credential.

Use one shared provider-equivalence helper that treats provider:<slug> and <slug> as the same provider. Apply it to active-profile and fallback-profile matching.

Proposed fix
+fn provider_matches(left: &str, right: &str) -> bool {
+    let bare = |value: &str| value.strip_prefix("provider:").unwrap_or(value);
+    bare(left).eq_ignore_ascii_case(bare(right))
+}
+
-            .find(|(k, _)| k.eq_ignore_ascii_case(provider))
+            .find(|(k, _)| provider_matches(k, provider))
             .map(|(_, v)| v)
@@
-            .provider
-            .eq_ignore_ascii_case(provider)
+            .provider
+            .as_str()
+            .pipe(|stored_provider| provider_matches(stored_provider, provider))
             .then(|| id.clone())

Use an ordinary local binding instead of .pipe(...) if that helper is not already available.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/security/credentials/core.rs` around lines 152 - 173, Update
the profile-selection logic around the active-profile lookup and fallback search
to use one shared provider-equivalence helper that treats provider:<slug> and
the bare <slug> as equivalent, matching case-insensitively. Apply this helper to
active profile keys, default profile IDs, and stored profile.provider values so
bare-slug callers resolve existing credentials; use a local binding instead of
.pipe(...) if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/security/credentials/core.rs`:
- Around line 45-46: In src/openhuman/security/credentials/core.rs:45-46, add
grep-friendly diagnostics for provider normalization and the credential storage
result, logging only the normalized provider and sanitized outcome; in
core.rs:152-173, log which selection branch was used—exact active key, fallback
active key, default profile, provider fallback, or no match—without profile
names or metadata; in src/openhuman/security/credentials/ops.rs:964-964, add
entry, normalized-provider, and sanitized failure/completion diagnostics,
ensuring tokens, metadata values, and full PII are never logged.

In `@src/openhuman/security/credentials/ops.rs`:
- Line 964: Update list_provider_credentials to compare provider_filter with
stored provider values using eq_ignore_ascii_case instead of exact equality,
while preserving existing filtering behavior for other fields. Add a regression
test that stores a mixed-case provider and successfully retrieves it using a
differently cased provider filter.

In `@src/openhuman/security/credentials/profiles.rs`:
- Around line 854-862: Update the active-profile migration loop in the
profile-loading method around new_active to detect case-insensitive key
collisions before insertion instead of silently overwriting entries. Prefer an
existing lowercase key, record and report conflicts where legacy keys differ
only by case, and add a regression test covering two case variants that
reference different profile IDs while preserving the selected lowercase profile.
- Around line 854-867: The persisted active-profile key normalization branch
lacks a migration diagnostic. Update the key-migration flow around key_migrated
and new_active to emit a verbose, grep-friendly [auth] log when normalization
occurs, including the count of migrated keys, while excluding provider keys and
profile IDs.

---

Outside diff comments:
In `@src/openhuman/security/credentials/core.rs`:
- Around line 152-173: Update the profile-selection logic around the
active-profile lookup and fallback search to use one shared provider-equivalence
helper that treats provider:<slug> and the bare <slug> as equivalent, matching
case-insensitively. Apply this helper to active profile keys, default profile
IDs, and stored profile.provider values so bare-slug callers resolve existing
credentials; use a local binding instead of .pipe(...) if needed.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f68665c0-a4bd-40fb-989b-d0b23ffdee95

📥 Commits

Reviewing files that changed from the base of the PR and between 8deb5f2 and e48d512.

📒 Files selected for processing (5)
  • src/openhuman/security/credentials/core.rs
  • src/openhuman/security/credentials/ops.rs
  • src/openhuman/security/credentials/ops_tests.rs
  • src/openhuman/security/credentials/profiles.rs
  • src/openhuman/security/credentials/profiles_tests.rs

Comment thread src/openhuman/security/credentials/core.rs
Comment thread src/openhuman/security/credentials/ops.rs Outdated
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/profiles.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e48d512fc0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openhuman/security/credentials/ops_tests.rs Outdated
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
@aryash45
aryash45 force-pushed the fix/deepseek-provider-slug-normalization branch from e48d512 to 1ceee59 Compare August 7, 2026 06:10

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/security/credentials/profiles.rs`:
- Around line 854-880: The active-profile migration count currently uses
persisted entry count minus conflicts rather than the number of keys whose
casing changed. In the migration loop around new_active and migration_conflicts,
add a counter incremented only when lower != *k, then use that counter in the
normalized-key debug message while preserving collision handling and existing
diagnostics.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f660c77-d2be-4449-8a8b-6cb972b1b765

📥 Commits

Reviewing files that changed from the base of the PR and between 8deb5f2 and 1ceee59.

📒 Files selected for processing (5)
  • src/openhuman/security/credentials/core.rs
  • src/openhuman/security/credentials/ops.rs
  • src/openhuman/security/credentials/ops_tests.rs
  • src/openhuman/security/credentials/profiles.rs
  • src/openhuman/security/credentials/profiles_tests.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/openhuman/security/credentials/ops_tests.rs
  • src/openhuman/security/credentials/core.rs
  • src/openhuman/security/credentials/ops.rs

Comment thread src/openhuman/security/credentials/profiles.rs Outdated
@aryash45

aryash45 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

hi @Al629176 please review this pr and tell me if anything needs to be changed

@aryash45
aryash45 force-pushed the fix/deepseek-provider-slug-normalization branch from 1ceee59 to 47a3d1f Compare August 7, 2026 06:19

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 7, 2026
@aryash45

aryash45 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

hi @senamakel @Al629176 please review this pr

@aryash45

aryash45 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

hello @sanil-23 @senamakel @senamakel-droid @Al629176 please review this pr

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking. Approving.

             $0.1117 · 71,019 in / 5,065 out · 3,584 cached (5%)  · minimax/minimax-m3, moonshotai/kimi-k3
critique:    $0.0412 · 13,009 in / 1,236 out · 0 cached (0%)      · moonshotai/kimi-k3, minimax/minimax-m3
security:    $0.0548 · 16,112 in / 430 out   · 0 cached (0%)      · moonshotai/kimi-k3
tests:       $0.0019 · 6,585 in  / 157 out   · 896 cached (14%)   · minimax/minimax-m3
commits:     $0.0038 · 10,595 in / 866 out   · 1,792 cached (17%) · minimax/minimax-m3
description: $0.0036 · 7,867 in  / 1,166 out · 768 cached (10%)   · minimax/minimax-m3

Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs Outdated
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/security/credentials/core.rs`:
- Around line 188-204: Update the bare-provider fallback in the
profile-selection function to resolve provider:{slug} through the existing
active-profile, default-profile, and provider-scan precedence rather than
directly scanning data.profiles. Preserve the fallback log and return behavior,
and add a regression test with two namespaced profiles where
active_profiles["provider:deepseek"] selects the non-first profile.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: efeb5d22-a0ce-454a-8a4c-63c9bdf58abd

📥 Commits

Reviewing files that changed from the base of the PR and between 47a3d1f and 6c1b731.

📒 Files selected for processing (1)
  • src/openhuman/security/credentials/core.rs

Comment thread src/openhuman/security/credentials/core.rs Outdated
@aryash45
aryash45 force-pushed the fix/deepseek-provider-slug-normalization branch from 6c1b731 to 47a3d1f Compare August 9, 2026 09:22

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 4 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0972 · 63,597 in / 6,973 out · 5,504 cached (9%)  · moonshotai/kimi-k3, minimax/minimax-m3
critique:    $0.0236 · 12,123 in / 225 out   · 1,152 cached (10%) · moonshotai/kimi-k3, minimax/minimax-m3
security:    $0.0566 · 17,023 in / 781 out   · 2,304 cached (14%) · moonshotai/kimi-k3
tests:       $0.0057 · 11,422 in / 2,084 out · 768 cached (7%)    · minimax/minimax-m3
commits:     $0.0048 · 10,276 in / 1,509 out · 512 cached (5%)    · minimax/minimax-m3
description: $0.0065 · 12,753 in / 2,374 out · 768 cached (6%)    · minimax/minimax-m3

Comment thread src/openhuman/security/credentials/ops_tests.rs Outdated
Comment thread src/openhuman/security/credentials/profiles_tests.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs Outdated
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs
Comment thread src/openhuman/security/credentials/profiles.rs Outdated
Comment thread src/openhuman/security/credentials/core.rs
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 9, 2026
@aryash45

aryash45 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@senamakel please guide me through this

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 9, 2026
@aryash45

Copy link
Copy Markdown
Contributor Author

@senamakel @Al629176 please review this pull request

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Maintainer review pass — findings only, nothing pushed to your branch. There is a lot of review text on this PR, some of it wrong, so I went through each open item and checked it against the code.

The bug is real and still unfixed on main. store_provider_token (core.rs:37) builds the profile from the raw provider string, while its siblings set_active_profile and remove_profile both call normalize_provider first — and normalize_provider (core.rs:111) trims and lowercases. So a mixed-case slug is written un-normalized and then missed by select_profile_id (core.rs:138), which matches with ==. Worth fixing.

Which open comments to act on

Real — please fix:

  • @chatgpt-codex-connector's P2, "migrate legacy mixed-case profile IDs too". This is the one substantive gap left. Your migration rewrites active_profiles keys only; it leaves the profiles map keys and the profile.provider field mixed-case. Reads then work (the lowercased active key points at provider:DeepSeek:default, which data.profiles.get finds), but deletes do not: remove_profile → normalize_provider → resolve_requested_profile_id derives provider:deepseek:default, which is not the stored key, so it returns removed = false. The user can see the stale credential and cannot clear it — worse than the bug being fixed, for anyone who hits it. Either migrate the profile IDs and profile.provider in the same rewrite, or make removal resolve legacy ids case-insensitively.
  • tinysweeper's "bare-slug → namespaced-slug resolution is not in the description". The documentation half is fair — your select_profile_id now falls back from deepseek to provider:deepseek, and the PR body doesn't mention it. Please add it. The security half is not a problem: inference/provider/factory_part_01.rs:66-69 documents exactly this convention — "New writes use provider:<slug>. Lookups also try the bare <slug> as a legacy fallback" — so the two forms are the same provider by design, not two different ones aliasing. Say that in the body and the concern is answered.
  • tinysweeper's ask to log the dropped profile ID at debug level on a migration collision. Cheap, and useful forensics. Worth doing.

Answered already — reply and resolve, don't rework:

  • tinysweeper: "normalize_provider is used but not defined or imported in this diff." It is already in scope: core.rs:111, same module, and it already does trim().to_ascii_lowercase(). Nothing to add.
  • @chatgpt-codex-connector's P1, "the short-slug lookup test cannot pass." Stale — it predates your namespace fallback. get_provider_bearer_token → get_profile → normalize_provider + select_profile_id (core.rs:84-89), and your fallback inside select_profile_id supplies the provider: form. The assertion passes on the current head. Reply pointing at the fallback and resolve it.

Wrong — say so and move on:

  • tinysweeper's "Collision migration can drop the canonical lowercase entry" (iteration-order-collision). This does not match your code. It claims the contains_key guard "lives inside the if lower != *k block" and that the overwrite happens with "no migration_conflicts increment". In your diff the two ifs are siblings, not nested, and migration_conflicts += 1 runs on every collision. Trace both orders:

    • mixed-case first → new_active[lower] = v_mixed; canonical arrives, contains_key true → conflict counted, k == lower → overwritten with the canonical value. ✔
    • canonical first → new_active[lower] = v_lower; mixed arrives, contains_key true → conflict counted, k != lower → not inserted. ✔

    Canonical wins in both, and every collision is counted. The outcome is order-independent, which is the exact property the comment says is missing. (The comment also visibly reverses itself mid-paragraph — "silently overwrites the mixed-case winner — wait, actually the reverse also matters" — which is a fair signal to distrust it.) Reply with the two-case trace and resolve; there is nothing to change here.

The rebase is the real work

You are ~3 weeks behind across a large file-splitting refactor, which is why all five files conflict. The functions did not change — they moved. Map for the rebase onto fa044d388:

your file where it is now
core.rs — store_provider_token core.rs:37 (same file)
core.rs — select_profile_id core.rs:138 (same file)
core.rs — inline mod tests core_tests.rs
ops.rs — store_provider_credentials ops_part_02.rs:269
profiles.rs — AuthProfilesStore::load profiles_impl_01_part_01.rs:140
ops_tests.rs ops_tests_part_01_tests.rs / ops_tests_part_02_tests.rs
profiles_tests.rs profiles_tests_part_01_tests.rs / profiles_tests_part_02_tests.rs

Note ops_part_02.rs:322 already does provider.strip_prefix("provider:"), so check your store_provider_credentials change composes with it rather than duplicating it.

CI

Both failures are stale infra from 2026-08-09, not your code — fatal: No url found for submodule path 'app/src-tauri/vendor/tauri-cef' in .gitmodules and Docker pull failed with exit code 1. They will re-run on the rebase. The PR Submission Checklist gate will want every item ticked, with any N/A item's text beginning with N/A.

One request while you rebase: the diff adds a fair amount of log::debug! tracing to select_profile_id on every branch. CodeRabbit asked for diagnostics and that thread is resolved, so I am not asking you to remove them — just confirm none of them can reach a token, profile name, or metadata value, since this is the credential path.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@aryash45

aryash45 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

thank you for this valuable feedback @M3gA-Mind will definitely work on it

senamakel and others added 2 commits September 12, 2026 00:28
The `scrub_json_credentials` helper function was relocated from `middleware_part_02` to `middleware_part_06` so it sits closer to the only call site that uses it, improving code locality and reducing unnecessary cross-module distance.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
This test previously used a synchronous global event bus initialisation that is no longer available. The change updates it to call the new async bus initialisation, which matches the current API and ensures the test can run correctly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previously-blocking findings are resolved. Clearing the changes request.

$0.0000 · 0 in / 0 out

@tinysweeper tinysweeper Bot added priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. and removed priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. labels Sep 11, 2026
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

…ontext functions

The `scrub_json_credentials` function and `generated_context` method on `ToolPolicyMiddleware` were dead code that had no callers within the codebase. Removing them eliminates unnecessary compilation overhead and clarifies that credential scrubbing is handled elsewhere in the middleware pipeline.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d13c3d20e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs Outdated
Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs Outdated
Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs Outdated
senamakel and others added 4 commits September 12, 2026 00:59
… normalization

When loading profiles, the code now gracefully handles keychain secret migration failures by retaining the original profile ID and persisted representation instead of proceeding with a broken migration. This ensures that old keychain entries remain reachable on the next load. Additionally, active profile references are now updated to match the final resolved profile ID after migration.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…sing

Add a test asserting that profile migration lowercases the provider
segment while leaving the profile name's casing intact, so mixed-case
profile names are not silently rewritten during normalization.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Wrap the active_profiles assertion across multiple lines to satisfy rustfmt line width limits. No behaviour change.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…gration

When a profile's provider casing differs from its normalized form, the migration logic was overwriting the provider field with its own value instead of keeping the original casing. This change stores the original provider before normalization and restores it when the provider casing has not changed, ensuring that profiles retain their original provider string when no casing migration is needed.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6e6969e61

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs
Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs Outdated
Comment thread src/openhuman/security/credentials/profiles_impl_01_part_01.rs
Comment thread src/openhuman/security/credentials/core.rs
senamakel and others added 5 commits September 12, 2026 01:33
The provider filter passed to list_provider_credentials is now normalized
before matching so mixed-case input resolves to the same profiles as the
canonical form. Profile migration also collects stale keychain entries and
deletes them only after the persisted state is written, and migration
targets are keyed by the original id so collisions are tracked correctly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Strip explanatory comments from the profile migration and cleanup logic
in the auth profiles store. The code is unchanged; the removed notes
merely restated what the surrounding statements already make clear.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Removed two stray blank lines inside the auth profiles store method to
keep the block formatting consistent.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Profile identifiers are now lowercased only in their provider segment
rather than across the whole string, so profile names that are
case-sensitive keep their original casing while provider lookups stay
canonical. Migration targets are also registered under the normalized
form so existing references resolve correctly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ration

The active profile migration loop tracked the number of case-variant collisions in a counter variable and logged each individual conflict, but the final summary warning was the only externally visible effect. Since the migration logic already handles conflicts by preferring the canonical lowercase key, the per-conflict debug logs and the summary counter added noise without providing actionable information. Removing them simplifies the code and eliminates unnecessary logging.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

senamakel and others added 2 commits September 12, 2026 02:18
Extracted the workspace directory resolution logic from `resolve_workspace_dir_from_process_state` into a new `resolve_workspace_dir` function that accepts an optional registered workspace parameter. This allows tests to call the resolution logic directly with controlled inputs instead of relying on the global process state, making the production resolution rule more directly testable.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test assertion in `production_resolution_still_honours_the_workspace_env_var` was unnecessarily split across multiple lines, making it harder to read. This change collapses the assertion into a single line for improved clarity without altering the test's behaviour.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@senamakel
senamakel merged commit 725b672 into tinyhumansai:main Sep 12, 2026
26 checks passed
senamakel added a commit to senamakel/openhuman that referenced this pull request Sep 12, 2026
The migration introduced in tinyhumansai#5432 now rewrites every profile to its canonical `<provider>:<profile_name>` id, so the raw `legacy-empty` key is no longer kept verbatim. The test assertion is updated to verify that the profile is stored under `legacy:empty` instead, and to check the new canonical id and provider fields.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@aryash45
aryash45 deleted the fix/deepseek-provider-slug-normalization branch September 13, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DeepSeek API key saved but dialog says not saved

3 participants