fix(hive): recover explicitly when a managed identity key is lost - #73
Conversation
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 31 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds explicit managed identity replacement for lost devices, including strict challenge validation, local key staging, server rotation or recovery, atomic credential promotion, login coordination, and a confirmation-based desktop recovery flow. ChangesManaged identity rotation
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant EvaosTeamsAuthGate
participant replace_lost_evaos_teams_identity
participant ManagedKeychain
participant IdentityRotationServer
EvaosTeamsAuthGate->>replace_lost_evaos_teams_identity: invoke replacement command
replace_lost_evaos_teams_identity->>ManagedKeychain: stage replacement key
replace_lost_evaos_teams_identity->>IdentityRotationServer: submit signed rotation challenge
IdentityRotationServer-->>replace_lost_evaos_teams_identity: active entitlement or recovery state
replace_lost_evaos_teams_identity->>ManagedKeychain: persist promoted credentials
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
|
Exact-head gate summary for
Proof boundary: source, CI, deployment, and review are proven. No artifact, installed identity rotation, internal canary, or customer rollout is claimed by this PR gate. |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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/evaos_teams/identity_rotation.rs`:
- Around line 77-81: Update the timestamp validation in the identity rotation
flow around created_at and now.timestamp() to use overflow-safe arithmetic, such
as checked subtraction followed by checked absolute-value handling. Convert any
arithmetic failure into the existing “managed identity replacement timestamp is
invalid” error, preserving fail-closed validation without panics.
- Around line 184-188: Update the recovery validation call in the identity
rotation flow to use the same relay-pinning validation as the success path,
passing the signed challenge’s relay host from the fallback call site instead of
calling bare validate_entitlement. Preserve the existing entitlement retrieval
and error propagation behavior.
In `@desktop/src-tauri/src/evaos_teams/tests.rs`:
- Around line 127-157: Extend the identity-rotation validation tests around
validate_identity_rotation_challenge and signed_identity_rotation_challenge to
cover every remaining rejection branch: mismatched expected_membership_id, a
replacement_public_key different from the locally staged key, expires_at both in
the past and beyond the allowed five-minute window, event_template.created_at
skewed by ten minutes, and relay_host values using http or embedded credentials.
Build each case from the existing identity_rotation_challenge helper and assert
signing returns Err, while preserving the current tag-canonicality and
valid-template tests.
In `@desktop/src/features/evaosTeams/EvaosTeamsAuthGate.tsx`:
- Around line 460-479: Update the recovery action panel around
replaceLostIdentity so both buttons are disabled whenever recoveryWorking,
recoveryStarted, or working is true, matching the ghost trigger’s guard and
preventing competing recovery writes. Also add role="alert" to the warning
paragraph and autoFocus to the “Keep existing identity” button so focus and
announcement are restored when the panel appears.
- Around line 275-279: Update replaceLostIdentity to use a synchronous ref-based
in-flight latch in addition to the working state guard, setting it before
invoking run(replaceLostEvaosTeamsIdentity) and clearing it in a finally path.
This must prevent rapid double invocation before React commits state while
preserving the existing success cleanup and allowing future attempts after
completion.
In `@desktop/src/features/evaosTeams/loginFallback.test.mjs`:
- Around line 27-37: Add a lib.rs source read in the “lost-device identity
replacement is explicit, consequential, and command-backed” test and assert that
generate_handler! includes replace_lost_evaos_teams_identity, alongside the
existing authGateSource and apiSource assertions.
🪄 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: 19a24158-1f85-44aa-8058-74ca3fe1eacc
📒 Files selected for processing (7)
desktop/src-tauri/src/evaos_teams.rsdesktop/src-tauri/src/evaos_teams/identity_rotation.rsdesktop/src-tauri/src/evaos_teams/tests.rsdesktop/src-tauri/src/lib.rsdesktop/src/features/evaosTeams/EvaosTeamsAuthGate.tsxdesktop/src/features/evaosTeams/api.tsdesktop/src/features/evaosTeams/loginFallback.test.mjs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Do not useunsafecode.
Do not introduce newunwrap()orexpect()calls in production paths; use?and proper error types instead.
New public Rust APIs must have doc comments.
Files:
desktop/src-tauri/src/lib.rsdesktop/src-tauri/src/evaos_teams/tests.rsdesktop/src-tauri/src/evaos_teams/identity_rotation.rsdesktop/src-tauri/src/evaos_teams.rs
desktop/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use rem-based Tailwind text tokens rather than arbitrary px, rem, or em text-size literals; prefer stock tokens,
text-2xs, ortext-3xs.
Files:
desktop/src/features/evaosTeams/EvaosTeamsAuthGate.tsxdesktop/src/features/evaosTeams/api.ts
desktop/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
desktop/src/**/*.{ts,tsx}: Chat body and author text must usetext-base; surrounding timeline elements should use deliberate steps on the stock text ramp.
When adding a community-scoped module-level cache, Map, or class instance, add its reset toresetCommunityState()indesktop/src/features/communities/useCommunityInit.ts.
Files:
desktop/src/features/evaosTeams/EvaosTeamsAuthGate.tsxdesktop/src/features/evaosTeams/api.ts
🔇 Additional comments (11)
desktop/src-tauri/src/evaos_teams/identity_rotation.rs (3)
3-25: LGTM!
86-137: LGTM!
248-297: LGTM!desktop/src-tauri/src/evaos_teams/tests.rs (2)
31-58: LGTM!
552-619: LGTM!desktop/src-tauri/src/evaos_teams.rs (3)
46-64: LGTM!
641-647: LGTM!
679-679: LGTM!desktop/src-tauri/src/lib.rs (1)
712-712: LGTM!desktop/src/features/evaosTeams/api.ts (1)
84-87: LGTM!desktop/src/features/evaosTeams/EvaosTeamsAuthGate.tsx (1)
17-17: LGTM!Also applies to: 46-46
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c0eac63846
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a536e11c95
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 94fae8c9f0
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e640a7ae1c
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1522b8032
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 04ca1bd36d
ℹ️ 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".
| let encoded = managed_store() | ||
| .store_if_absent(&staging_key, &candidate) |
There was a problem hiding this comment.
Preserve staged keys across all managed blob writes
When another Hive binary has a warm managed-store cache, the replacement key staged here can still be deleted by that binary's next verify_managed_store_writable, begin_managed_logout, or persist_signed_out_identities: each calls replace_all with a cached whole-blob snapshot, clearing the freshly locked map. If the rotating process has already verified the staged key and the server rotates before final persistence, a crash or Keychain write failure then loses the only replacement private key. Fresh evidence after the resolved scoped-promotion fix is that these remaining whole-blob writers were not converted to fresh scoped mutations.
AGENTS.md reference: AGENTS.md:L7-L10
Useful? React with 👍 / 👎.
|
Exact-head gate for |
Closes #72
Outcome
Adds an explicit lost-device fallback after Electric OAuth selects a membership whose durable Hive key is absent. Exact-key NIP-AB recovery remains the preferred path.
Focused proof
cargo test --manifest-path desktop/src-tauri/Cargo.toml --features evaos-teams-managed evaos_teams— 39 passednode --import ./test-loader.mjs --experimental-strip-types --test src/features/evaosTeams/loginFallback.test.mjs src/features/evaosTeams/api.test.mjs— 6 passedpnpm typecheck— passedgit diff --check— passedServer dependency: electricsheephq/electric-sheep-website-dashboard-6158a244#746 (merged; ordered production rollout tracked separately).
Proof boundary: source and focused tests only until exact-head CI, independent review, cumulative artifact, and installed canary complete.