fix(auth-profiles): tolerate legacy kind values on load#2439
Conversation
## Summary - Updated the function to log a warning and drop profiles with unrecognized kinds instead of failing the entire loading process. This change ensures that legacy profiles do not prevent users from accessing their other authentication profiles. ## Impact - Users with older profile formats can still load their profiles without being locked out due to unrecognized kinds.
- Introduced a new test to ensure that profiles with unrecognized kinds do not prevent the loading of valid profiles. Instead, these entries are dropped, allowing users to access their other authentication profiles without issues. - This change addresses legacy profile formats and enhances the robustness of the profile loading mechanism.
📝 WalkthroughWalkthroughThis PR improves resilience of auth profile loading by handling malformed profile kind values gracefully. Instead of failing the entire store load when an unrecognized kind is encountered, the code now logs a warning, collects the profile ID for removal, and continues loading valid profiles. A test validates the complete behavior including state cleanup and persistence. ChangesProfile Kind Parsing Resilience
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/openhuman/credentials/profiles.rs (1)
329-335: ⚡ Quick winUse
debug/tracelevel for this recovery-path diagnostic log.Line 329 logs a recoverable branch with
warn; repo policy for Rust diagnostics/error-path tracing requiresdebugortrace.♻️ Suggested change
- log::warn!( + log::debug!( "[auth] dropping profile with unrecognized kind={:?} provider={}: {e}. \ This usually means the profile was written by an older version of \ OpenHuman. Re-authenticate to restore the session.", p.kind, p.provider );As per coding guidelines "Use
log/tracingatdebugortracelevel on RPC entry and exit, error paths, state transitions, and any branch that is hard to infer from tests alone."🤖 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/credentials/profiles.rs` around lines 329 - 335, The log call that warns about dropping an unrecognized profile should be lowered to a diagnostic level; replace the log::warn! invocation that references p.kind and p.provider with log::debug! (or log::trace! if you prefer more verbosity) so this recoverable branch is logged at debug/trace level; update the logging macro at the line where the message "dropping profile with unrecognized kind={:?} provider={}: {e}..." is emitted (the call that interpolates p.kind and p.provider) to use the chosen debug/trace macro and keep the exact message and interpolated variables unchanged.
🤖 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.
Nitpick comments:
In `@src/openhuman/credentials/profiles.rs`:
- Around line 329-335: The log call that warns about dropping an unrecognized
profile should be lowered to a diagnostic level; replace the log::warn!
invocation that references p.kind and p.provider with log::debug! (or
log::trace! if you prefer more verbosity) so this recoverable branch is logged
at debug/trace level; update the logging macro at the line where the message
"dropping profile with unrecognized kind={:?} provider={}: {e}..." is emitted
(the call that interpolates p.kind and p.provider) to use the chosen debug/trace
macro and keep the exact message and interpolated variables unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f5cfce59-1672-4b4b-8667-11cca0bfed7f
📒 Files selected for processing (2)
src/openhuman/credentials/profiles.rssrc/openhuman/credentials/profiles_tests.rs
graycyrus
left a comment
There was a problem hiding this comment.
Looks good, nice work!
Summary
AuthProfilesStore::load_lockedno longer bails the entire load when a single persisted profile has akindvalue that the current parser can't interpret (e.g. legacy"OAuth"written before the kebab-case rename, or"api_key"from an older code path).warn, pushed into the existingdropped_idsset, and purged fromauth-profiles.json(along with any staleactive_profilespointer) on the same load — matching the established decrypt-failure recovery pattern in the same function.auth-profiles.json" to "one provider needs a fresh login; everything else keeps working."load_drops_profiles_with_unrecognized_kind_instead_of_failing_loadreproducing both real-world Sentry payloads ("api_key"and legacy"OAuth") and asserting in-memory drop + on-disk purge + cleared active-pointer.Problem
Unsupported auth profile kind: api_key(370 events / 14d).Unsupported auth profile kind: OAuth(258 events / 14d).src/openhuman/credentials/profiles.rs:parse_profile_kindonly accepts"oauth"/"token". When any persisted row has a different string (legacy variant-name serialization, older code path writing"api_key"), the?propagates the error out ofload_locked, which means every caller ofAuthProfilesStore::load()—set_active_profile,update_profile,app_state_snapshotpolls,inference_statuspolls, every credential read — fails for that user.app_state_snapshot/inference_statusroughly once per second, so a single bad row produces hundreds of identical Sentry events per session and locks the user out of all their providers, not just the one with the malformed kind. The only user-facing recovery path was "manually deleteauth-profiles.json," which also wipes every working profile.Solution
?with amatchthat, onErr, logs the unrecognizedkind+provideratwarn, pushes the id intodropped_ids, andcontinues — the same shape already used for decrypt failures at lines 287–300 of the same function.dropped_idsfrompersisted.profiles, clears anyactive_profilesentry that pointed at them, bumpsupdated_at, and rewrites the file under the lock that's already held. So the bad row is purged on this load and can't keep retriggering on subsequent loads.parse_profile_kinditself is unchanged — the public/private API surface, struct shapes, serde reprs, and trait impls are all untouched. The only behavioural delta is thatload_lockednow degrades gracefully on one malformed row instead of failing closed on all of them.log::warn!plus a single Sentry breadcrumb tells the user exactly what happened.Submission Checklist
load_drops_profiles_with_unrecognized_kind_instead_of_failing_loadcovering both real Sentry payloads ("api_key"+ legacy"OAuth"); existingstore_roundtrip_with_encryption/corrupt_store_is_quarantined_and_reset/load_drops_profiles_whose_decryption_fails_under_rotated_keycontinue to cover the happy and adjacent-failure paths.profiles.rs(the newmatcharm) is exercised by the new test, which asserts both the in-memory and on-disk outcome. Verified locally viacargo test --lib openhuman::credentials::profiles(34/34 pass).N/A: behaviour-only fix to an existing code path; no new/removed/renamed feature rows.## Related—N/A: no matrix rows touched (see above).docs/RELEASE-MANUAL-SMOKE.md) —N/A: internal load-path resilience fix, no UI/release-cut surface changes.Closes #NNNin the## Relatedsection —N/A: no GitHub issue filed; links to Sentry issues TAURI-RUST-123 and TAURI-RUST-2605 included instead.Impact
openhumanlib crate) loaded in-process by the Tauri shell; the mobile/web/CLI surfaces don't read this store.O(1)extramatchon the load hot path, no extra I/O for healthy stores; on stores with bad rows, one additionalwrite_persisted_lockedper load — already paid by the existing decrypt-failure recovery, so no new write semantics.kind(the unrecognized string) andprovider(the slug) appear in the warn line.auth-profiles.json(including malformed legacy rows), writes a clean current-schema version on next save. No schema version bump needed; no manual user action beyond re-authenticating the affected provider.Related
Unsupported auth profile kind: api_key(370 events / 14d)Unsupported auth profile kind: OAuth(258 events / 14d)Summary by CodeRabbit