Skip to content

Introduce Credential Activity History Store - #481

Open
ketzusaka wants to merge 1 commit into
mainfrom
credential-activity-history
Open

Introduce Credential Activity History Store#481
ketzusaka wants to merge 1 commit into
mainfrom
credential-activity-history

Conversation

@ketzusaka

@ketzusaka ketzusaka commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Introduces a sharable on-device store for Android and iOS to retain credential activity. We're re-using some components from the Wallet storage here, while maintaining a separate database for the local activity as it is a separate concern and should never be backed up with the existing systems.

I've modeled the changes after how I typically use rust; mod.rs is mainly imports with most of the code in dedicated files, and tests in their related files.

This system is expected to evolve over time so i've prioritized a sensible migration strategy as part of these changes.

Tested integration on iOS. Will do Android later and follow up with any PRs that might be necessary for their integration. No runtime differences until the host apps are updated to use the new system.


Note

Medium Risk
Touches account teardown (destroy_storage API change), shared encryption key lifetime, and destructive DB rebuild paths; host apps must wire activity open/record/reconcile and pass the store on destroy.

Overview
Adds a device-local credential activity history layer: a separate encrypted SQLite database (account.activity.sqlite) keyed with the same K_intermediate as vault/cache, exposed to host apps via UniFFI as ActivityStore.

Hosts can record proof-share lifecycle (start → finalize with outcomes/failure reasons), list paginated history, read metadata, and reconcile stale pending rows to Incomplete (with optional client_id exclusions). Schema migrations are reported on first open; open retries transient lock contention and can wipe/rebuild on corruption or wrong key. Native builds get an ActivityChangedListener (background thread, same pattern as vault changes).

Credential storage now exposes intermediate_key() through a shareable IntermediateKeyHandle, refactors StorageKeys for shared/destroyable keys, and explicitly zeroizes keys on destroy_storage. Authenticator::destroy_storage takes an optional ActivityStore and deletes the activity DB on logout/account deletion (native only; wasm ignores it).

New activity-specific StorageError variants and walletkit-db query_row_optional on transactions support finalize-by-client_id.

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

@ketzusaka
ketzusaka force-pushed the credential-activity-history branch from a003298 to c53e3ff Compare August 25, 2026 21:46
@ketzusaka
ketzusaka marked this pull request as ready for review August 25, 2026 22:25
Comment thread crates/walletkit-core/src/storage/activity/activity_store.rs
Comment thread crates/walletkit-core/src/storage/credential_activity/schema.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/activity_store.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/schema.rs Outdated
Comment on lines +90 to +91
credential_type INTEGER NOT NULL,
credential_source INTEGER NOT NULL,

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.

isn't that basically included in issuer_schema_id?

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.

Sorta! The issuer_schema_id could request one type, but we could provide a higher assurance credential instead. So they may request a document, but we provide a PoH.

Comment on lines +90 to +92
credential_type INTEGER NOT NULL,
credential_source INTEGER NOT NULL,
proof_kind INTEGER NOT NULL,

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.

maybe just a metadata json column?

Comment thread crates/walletkit-core/src/storage/credential_activity/schema.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/activity_store.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/activity_store.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/activity_store.rs Outdated
Comment thread crates/walletkit-core/src/storage/credential_activity/activity_store.rs Outdated
Comment thread crates/walletkit-core/src/authenticator/with_storage.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
Comment thread crates/walletkit-core/src/storage/types.rs Outdated
@ketzusaka
ketzusaka force-pushed the credential-activity-history branch from c53e3ff to 57a7ff5 Compare August 31, 2026 19:49

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 57a7ff5. Configure here.

Comment thread crates/walletkit-core/src/storage/activity/maintenance.rs
Comment thread crates/walletkit-core/src/storage/activity/maintenance.rs
@ketzusaka
ketzusaka force-pushed the credential-activity-history branch 2 times, most recently from 828b94b to e2490d0 Compare August 31, 2026 20:15
Introduces a sharable on-device store for Android and iOS to retain credential activity. We're re-using some components from the Wallet storage here, while maintaining a separate database for the local activity as it is a separate concern and should never be backed up with the existing systems.

I've modeled the changes after how I typically use rust; mod.rs is mainly imports with most of the code in dedicated files, and tests in their related files.

This system is expected to evolve over time so i've prioritized a sensible migration strategy as part of these changes.

Tested integration on iOS. Will do Android later and follow up with any PRs that might be necessary for their integration. No runtime differences until the host apps are updated to use the new system.
@ketzusaka
ketzusaka force-pushed the credential-activity-history branch from e2490d0 to d44b0b2 Compare September 1, 2026 00:01
//! ```text
//! account.cache.sqlite # sqlite3mc-encrypted cache DB (keyed by K_intermediate)
//! account.vault.sqlite # sqlite3mc-encrypted vault DB (keyed by K_intermediate)
//! account.activity.sqlite # sqlite3mc-encrypted activity DB (keyed by K_intermediate)

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.

high. the account.cache is probably the best suited place for this functionality. it's meant to store things that are per-device only. in fact, depending on how we'd query this, we may not even need a new table (haven't gotten there in the review yet)

};

/// Storage handle for credential-activity history: a device-local,
/// chronological log of proof-share request outcomes.

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.

Suggested change
/// chronological log of proof-share request outcomes.
/// chronological log of [`ProofRequest`] outcomes.

nit. don't forget to import ProofRequest

/// Storage handle for credential-activity history: a device-local,
/// chronological log of proof-share request outcomes.
#[derive(uniffi::Object)]
pub struct ActivityStore {

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.

one thing that would be very helpful is to document in the doc comments here the expected flow. how is this intended to work? how are logs stored? how are they expected to be consumed?

/// chronological log of proof-share request outcomes.
#[derive(uniffi::Object)]
pub struct ActivityStore {
activity: Mutex<Option<OpenActivity>>,

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.

(see previous comment), with the change to using the cache db, this won't be necessary


/// A single row of credential activity history.
#[derive(Debug, Clone, PartialEq, Eq, uniffi::Record)]
pub struct ActivityEntry {

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.

high (from live discussion). proposal is to keep only this and one-shot insert an entry once its state is resolved (either in success or failure)

activity_store.destroy_storage(paths)?;
}
#[cfg(target_arch = "wasm32")]
let _ = activity_store;

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.

@Dzejkop what should we do in wasm?


/// Version range applied by a schema migration run during [`super::ActivityStore::open`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Record)]
pub struct ActivitySchemaMigration {

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.

might not be needed if we use the existing cache table

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.

3 participants