Skip to content

feat(keyring-controller): persist vault when keyring state changes during unlock#8415

Open
danroc wants to merge 5 commits intomainfrom
dr/keyring-migrations
Open

feat(keyring-controller): persist vault when keyring state changes during unlock#8415
danroc wants to merge 5 commits intomainfrom
dr/keyring-migrations

Conversation

@danroc
Copy link
Copy Markdown
Contributor

@danroc danroc commented Apr 9, 2026

Explanation

Currently, if a keyring runs a migration inside deserialize() during unlock, the updated in-memory state is never written back to the vault. On the next unlock the migration silently re-runs against the same stale data.

This PR fixes that by comparing each keyring's re-serialized state against the original data after #restoreKeyring. If any keyring's state differs — whether due to a migration or missing metadata — hasChanged is propagated up through #restoreSerializedKeyrings and #unlockKeyrings, and the existing vault upgrade path in submitPassword/submitEncryptionKey re-persists the vault.

As part of this change, a hasStateChanged helper function is introduced and reused in #persistOrRollback, removing the dependency on lodash isEqual for that comparison.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Touches the unlock flow and vault persistence logic; an incorrect change-detection signal could trigger unnecessary vault rewrites or miss persisting a migrated keyring state.

Overview
Ensures the vault is re-persisted after unlock when deserializing keyrings results in a different serialized state (e.g. keyring migrations running during deserialize() or missing keyring metadata being regenerated), preventing repeated migrations on subsequent unlocks.

This propagates a hasChanged flag through #restoreKeyring#restoreSerializedKeyrings#unlockKeyrings and uses it in submitPassword/submitEncryptionKey to conditionally call #updateVault. It also simplifies session-state change detection in #persistOrRollback by switching from lodash isEqual to direct JSON string comparison and drops the isEqual import.

Reviewed by Cursor Bugbot for commit 0fd1697. Bugbot is set up for automated code reviews on this repo. Configure here.

…ring unlock

Introduces `hasStateChanged` helper and uses it to detect when a
keyring's serialized state differs from what was stored in the vault.
If any keyring changed during deserialization (e.g. ran a migration,
or was missing metadata), the vault is re-persisted via the existing
upgrade path in `submitPassword`/`submitEncryptionKey`.

Also removes the now-redundant `isEqual` import from lodash.
@danroc danroc requested review from a team as code owners April 9, 2026 13:06
danroc added 4 commits April 9, 2026 15:06
…low serialize()

Eagerly stringify session state before the operation so that subsequent
mutations to keyring-internal arrays (e.g. MockShallowKeyring) cannot
retroactively change the snapshot used for comparison. Also removes the
now-unnecessary `hasStateChanged` helper.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant