Skip to content
This repository was archived by the owner on Aug 17, 2026. It is now read-only.

Fix Keychain read-failure recovery - #71

Merged
100yenadmin merged 2 commits into
mainfrom
fix/66-keychain-present-read-failure
Jul 28, 2026
Merged

Fix Keychain read-failure recovery#71
100yenadmin merged 2 commits into
mainfrom
fix/66-keychain-present-read-failure

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

  • handle macOS Keychain Present + unreadable/cancelled reads without fatal boot retry
  • boot the existing non-signing KeyringLocked recovery state without writing, deleting, or rotating identity
  • preserve the pre-migration identity.key fallback when no migration marker exists
  • split focused regression coverage out of the already-ratcheted app_state_tests.rs file

Scope

This is an Internal Canary blocker fix for #66. It does not change OAuth server authority, relay policy, ATRIS/Hermes runtime behavior, native Buzz collaboration, or the existing durable identity/session grant contract.

Focused local proof

  • cargo test --manifest-path desktop/src-tauri/Cargo.toml present_keyring_read_failure --features evaos-teams-managed
  • pnpm -C desktop exec node --import ./test-loader.mjs --experimental-strip-types --test src/features/evaosTeams/api.test.mjs src/features/evaosTeams/loginSuccess.test.mjs src/features/evaosTeams/managedRecovery.test.mjs
  • pnpm -C desktop check
  • pnpm -C desktop typecheck
  • git diff --check

Proof boundary

Local source proof only until this PR's exact-head CI and independent auth/identity review pass. Installed primary operator/Benjamin/ATRIS canary resumes only after merge and a rebuilt cumulative artifact.

Fixes #66
Blocks #60
Part of #1

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 58ed7119-5157-48ef-9962-18547e16c37e

📥 Commits

Reviewing files that changed from the base of the PR and between d4b08bf and 99fbbb8.

📒 Files selected for processing (3)
  • desktop/scripts/check-file-sizes.mjs
  • desktop/src-tauri/src/app_state.rs
  • desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs
📝 Walkthrough

Walkthrough

Keyring identity read failures now use legacy-file recovery when migration is incomplete, or locked recovery with an ephemeral key otherwise. New tests simulate failed keyring reads and verify both paths. The file-size override documents and permits the added regression handling. Confidence: 99%.

Changes

Keyring recovery behavior

Layer / File(s) Summary
Keyring failure recovery path
desktop/src-tauri/src/app_state.rs, desktop/scripts/check-file-sizes.mjs
resolve_identity_with_store selects legacy identity fallback or KeyringLocked recovery after keyring read failure; the file-size threshold and related comment are updated.
Recovery behavior regression tests
desktop/src-tauri/src/app_state.rs, desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs
A failing in-memory keyring store tests locked recovery, legacy fallback, and the absence of unintended writes or deletions.

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

Suggested reviewers: wpfleger96, wesbillman

Sequence Diagram(s)

sequenceDiagram
  participant Resolver as resolve_identity_with_store
  participant Keyring as IdentityKeyStore
  participant Legacy as identity.key
  participant Ephemeral as Ephemeral identity
  Resolver->>Keyring: load identity
  Keyring-->>Resolver: read failure
  Resolver->>Legacy: inspect legacy file and migration marker
  Legacy-->>Resolver: legacy keys or unavailable
  Resolver->>Ephemeral: generate key when legacy fallback is unavailable
  Ephemeral-->>Resolver: ephemeral identity with KeyringLocked
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed Clearly names the main change: Keychain read-failure recovery; concise and specific. Confidence 98%.
Description check ✅ Passed Describes the recovery fix, fallback behavior, and regression tests; clearly matches the diff. Confidence 99%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/66-keychain-present-read-failure

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

@coderabbitai coderabbitai 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.

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 `@desktop/src-tauri/src/app_state.rs`:
- Around line 479-500: Keep legacy fallback errors within locked recovery: in
desktop/src-tauri/src/app_state.rs lines 479-500, handle load_key_file failure
without propagating it, leave the legacy file untouched, and fall through to the
existing ephemeral RecoveryState::KeyringLocked path. In
desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs lines 71-98, add a
corrupt legacy-file test asserting KeyringLocked, no keyring writes or deletes,
and no legacy-file deletion.
🪄 Autofix (Beta)

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: ASSERTIVE

Plan: Pro Plus

Run ID: 2353e956-da9d-42f4-be10-1e337bd84fd0

📥 Commits

Reviewing files that changed from the base of the PR and between e4565f4 and d4b08bf.

📒 Files selected for processing (3)
  • desktop/scripts/check-file-sizes.mjs
  • desktop/src-tauri/src/app_state.rs
  • desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (13)
  • GitHub Check: Desktop E2E Integration (2/2)
  • GitHub Check: Desktop E2E Integration (1/2)
  • GitHub Check: Windows Rust (x86_64-pc-windows-msvc)
  • GitHub Check: Desktop Smoke E2E (3)
  • GitHub Check: Desktop Smoke E2E (1)
  • GitHub Check: Desktop Build (macOS)
  • GitHub Check: Desktop Smoke E2E (4)
  • GitHub Check: Desktop Smoke E2E (2)
  • GitHub Check: Rust Lint
  • GitHub Check: Desktop Core
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Do not use unsafe code.
Do not introduce new unwrap() or expect() calls in production paths; use ? and proper error types instead.
New public Rust APIs must have doc comments.

Files:

  • desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs
  • desktop/src-tauri/src/app_state.rs
🔇 Additional comments (3)
desktop/src-tauri/src/app_state.rs (1)

1099-1101: LGTM!

desktop/scripts/check-file-sizes.mjs (1)

417-420: LGTM!

desktop/src-tauri/src/app_state_keyring_read_failure_tests.rs (1)

1-68: LGTM!

Comment thread desktop/src-tauri/src/app_state.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: d4b08bf6db

ℹ️ 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 desktop/src-tauri/src/app_state.rs Outdated
"buzz-desktop: keyring identity present but unreadable ({error}); \
using legacy identity.key fallback for this boot"
);
let keys = load_key_file(legacy_path)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enter recovery when the fallback file is invalid

When a pre-migration identity.key exists without a marker but is unreadable, empty, or corrupt, this ? propagates the file error instead of continuing into KeyringLocked. The setup caller treats any identity-resolution error as fatal and exits the process, so users who cancel the keychain read in this state remain in the boot loop this change is intended to avoid. Handle the file-read failure by using the non-signing locked-recovery path rather than returning it.

Useful? React with 👍 / 👎.

Comment thread desktop/src-tauri/src/app_state.rs Outdated
let loaded = match store.load(IDENTITY_KEY_NAME) {
Ok(value) => value,
Err(error) => {
if legacy_path.exists() && !migration_marker_path(data_dir).exists() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a valid fallback file even when the marker exists

When migration successfully writes the marker but fails to delete identity.key, a valid copy of the identity remains alongside the marker. If the subsequent keychain load is cancelled or otherwise fails, this marker check ignores that usable copy and boots locked recovery unnecessarily; the existing KeyringProbe::Unreachable path explicitly uses a present valid file regardless of the marker for this same inaccessible-keyring state. Attempt the file fallback whenever it exists, while falling back to locked recovery if it cannot be parsed.

Useful? React with 👍 / 👎.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: OAuth login on a new device must recover the bound Hive identity

1 participant