Skip to content

feat: add sync_backup() method to force a vault backup on first backup#296

Closed
thomas-waite wants to merge 13 commits intomainfrom
feat/expose-sync-backup
Closed

feat: add sync_backup() method to force a vault backup on first backup#296
thomas-waite wants to merge 13 commits intomainfrom
feat/expose-sync-backup

Conversation

@thomas-waite
Copy link
Copy Markdown
Contributor

@thomas-waite thomas-waite commented Mar 12, 2026

Add sync_backup(), to allow for a first time backup upload before vault mutations

When a user first creates a backup in a host app, it's an explicit action taken by a user to make a backup. It is not in response to a vault mutation. So, we need a method that can force a backup of the vault to be made if the host app needs one.

Added sync_backup() to do this. Also done a slight refactor of the internal logic to propagate errors, similar to how the existing backup system works.


Note

Medium Risk
Touches core credential storage synchronization by replacing std::sync::Mutex with parking_lot::Mutex and removing poison-error handling, which could affect concurrency behavior. Adds a new backup-trigger path (sync_backup) that exports plaintext vault snapshots on demand, so backup integrations should be revalidated.

Overview
Adds CredentialStore::sync_backup() to explicitly export the current vault and invoke the registered WalletKitBackupManager::on_vault_changed callback even when no vault mutation occurred (e.g., first-time backup setup), with new tests covering empty and non-empty vault cases.

Refactors storage locking to use parking_lot::Mutex (new optional dependency under the storage feature), simplifying APIs by removing Result from storage_paths/paths and eliminating poisoned-lock error paths; related authenticator tests and integration tests are updated accordingly. Backup export/callback failures remain best-effort and are now more explicitly logged/documented as non-propagated.

Written by Cursor Bugbot for commit 7b86e91. This will update automatically on new commits. Configure here.

@thomas-waite thomas-waite requested a review from Copilot March 12, 2026 21:55
@thomas-waite thomas-waite self-assigned this Mar 12, 2026
@thomas-waite
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an explicit, host-invokable backup trigger to the credential vault storage layer so apps can perform an initial backup upload before any further vault mutations.

Changes:

  • Added CredentialStore::sync_backup() to trigger the backup notification flow without mutating the vault.
  • Added tests covering sync_backup() behavior for both non-empty and empty vaults.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

ℹ️ 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".

@thomas-waite
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

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

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

ℹ️ 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".

///
/// Returns an error if no backup manager is configured, if the vault
/// export fails, or if the backup manager callback fails.
pub fn sync_backup(&self) -> StorageResult<()> {
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.

Hmm this is creating a cyclical pattern of Foreign -> Rust -> Foreign (and potentially more bindings after). Is this initial sync necessary? If there are no credentials there should be nothing to backup right?

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.

Just to be clear - it's the same case with regular credential store calls - they're also Foregin -> Rust -> Foregin

Copy link
Copy Markdown
Contributor Author

@thomas-waite thomas-waite Mar 16, 2026

Choose a reason for hiding this comment

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

Yep, the existing backup solution in Oxide is already doing this. I'm following the same pattern. The initial sync is necessary to backup whatever v4 credentials have already been put into the credential vault when the user enables backups (the callback based backup logic is only triggered when the vault is mutated)

/// does not affect the vault mutation that triggered this call. Returning
/// `Result` (rather than `()`) ensures that host-side exceptions are
/// translated into a Rust `Err` by `UniFFI` instead of panicking.
/// Returning `Err` propagates the error to the caller of the vault
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.

It's unrelated to this PR but I'm realizing this could lead to very weird states where a credential has been saved to the vault, backup fails and an error is returned. The native app won't know the credential is saved and retry which will error. We should split the backup failures as error logs and/or return a separate status for this, but not fail the entire original call

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah agree, should have a seperate status for this/error logs. Will do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Dependency not gated behind optional storage feature
    • Made parking_lot optional and added it to the storage feature list, matching the pattern of other storage-only dependencies.

View PR

Or push these changes by commenting:

@cursor push ecdb2e7875
Preview (ecdb2e7875)
diff --git a/walletkit-core/Cargo.toml b/walletkit-core/Cargo.toml
--- a/walletkit-core/Cargo.toml
+++ b/walletkit-core/Cargo.toml
@@ -46,7 +46,7 @@
 strum = { version = "0.27", features = ["derive"] }
 subtle = "2"
 thiserror = "2"
-parking_lot = "0.12"
+parking_lot = { version = "0.12", optional = true }
 tokio = { version = "1", features = ["sync"] }
 tracing = "0.1"
 tracing-log = "0.2"
@@ -95,6 +95,7 @@
 storage = [
     "dep:ciborium",
     "dep:hkdf",
+    "dep:parking_lot",
     "dep:rand",
     "dep:sha2",
     "dep:uuid",

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@thomas-waite
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ 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".

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.

4 participants