Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions packages/rs-platform-wallet-storage/SECRETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ respectively (`Io`'s inner OS error boxed as the source).
`keyring_core::Error` is safe to `Display` (`{ }`-format), but
`{:?}`-format embeds `BadEncoding(Vec<u8>)` / `BadDataFormat(Vec<u8>, _)`
payloads — those variants are NEVER constructed by our backends with
secret bytes, and `tests/secrets_guard.rs` enforces that no debug-format
secret bytes, and `tests/integration/secrets_guard.rs` enforces that no debug-format
pairs with `keyring_core::Error` inside `src/secrets/`.

## What the SQLite backend WILL refuse to store
Expand All @@ -549,21 +549,21 @@ secret-free.

## Audit hooks

- **`tests/secrets_scan.rs`**: greps every file under
- **`tests/integration/secrets_scan.rs`**: greps every file under
`src/sqlite/schema/` and `migrations/` for the substrings `private`,
`mnemonic`, `seed`, `xpriv`, `secret`. A new column, blob field, or
comment that uses any of those words breaks the test — forcing the
author to either rename, or add their phrase to the file's
allow-list with a rationale. The `src/secrets/` directory is exempt
by design (its own positive guard below covers it).
- **`tests/secrets_guard.rs`**: positive secret-leak guard for
- **`tests/integration/secrets_guard.rs`**: positive secret-leak guard for
`src/secrets/`. Forbids logging/formatting sinks that pair with
`expose_secret(...)` on the same logical statement, AND forbids
`{:?}`-debug-format paired with `keyring_core::Error`.
- **`tests/secrets_api.rs`**: shape guards — `CredentialApi::get_secret`
- **`tests/integration/secrets_api.rs`**: shape guards — `CredentialApi::get_secret`
re-wraps through `SecretBytes::new`, redacting `Debug` on
`SecretBytes`/`SecretString`, no `Box<dyn Error>` in `src/secrets/`.
- **`tests/secrets_default_on_compiles.rs`**: build-time guard
- **`tests/integration/secrets_default_on_compiles.rs`**: build-time guard
(gated `#![cfg(feature = "secrets")]`) that the default feature set
exposes the secrets surface as public re-exports. It names
`EncryptedFileStore`, `SecretBytes`, `SecretString`,
Expand All @@ -575,7 +575,7 @@ secret-free.
alone. No test file and **no CI job** cover it: that invocation is a
local/manual check, so a regression in the off-state build reaches
`main` unnoticed.
- **`tests/sqlite_persist_roundtrip.rs::tc082_no_box_dyn_error_in_src`**:
- **`tests/integration/sqlite_persist_roundtrip.rs::tc082_no_box_dyn_error_in_src`**:
all public method signatures use concrete error types
(`WalletStorageError`, `PersistenceError`) — never
`Box<dyn Error>` — so a future leak is caught by `grep`.
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-platform-wallet-storage/src/secrets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
//! [`CredentialStoreApi`]: keyring_core::api::CredentialStoreApi
//!
//! This `src/secrets/` tree is the sole secret-bearing module:
//! `tests/secrets_scan.rs` exempts it, so it owns its own review
//! discipline via `tests/secrets_guard.rs`.
//! `tests/integration/secrets_scan.rs` exempts it, so it owns its own review
//! discipline via `tests/integration/secrets_guard.rs`.
//!
//! Cryptographic wire format lives in [`mod@wire`]: the Tier-2
//! envelope (`wire::envelope`) and the three AAD constructions
Expand Down
6 changes: 3 additions & 3 deletions packages/rs-platform-wallet-storage/src/secrets/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl SecretString {
/// be a vulnerability rather than a simplification.
///
/// Takes the text rather than a `SecretString` so it never calls
/// `expose_secret` itself, keeping `tests/secrets_guard.rs`'s
/// `expose_secret` itself, keeping `tests/integration/secrets_guard.rs`'s
/// sink-near-plaintext scan honest instead of merely quiet.
fn check_edit_range(text: &str, start: usize, end: usize) {
assert!(
Expand Down Expand Up @@ -1096,7 +1096,7 @@ mod tests {
let long = "x".repeat(DEFAULT_CAPACITY + 500);
let mut one_shot = SecretString::new("seed:");
one_shot.replace_range(5.., &long);
// Built in its own statement: `tests/secrets_guard.rs` rejects a
// Built in its own statement: `tests/integration/secrets_guard.rs` rejects a
// formatting sink sharing a statement with `expose_secret`.
let expected = format!("seed:{long}");
assert_eq!(one_shot.expose_secret(), expected);
Expand Down Expand Up @@ -1186,7 +1186,7 @@ mod tests {
fn replace_range_panic_message_carries_no_plaintext() {
// Bound as a literal, never read back out of the secret: pairing
// `expose_secret` with an assertion here would trip
// `tests/secrets_guard.rs`.
// `tests/integration/secrets_guard.rs`.
let plaintext = "correct-horse-battery-staple";
let mut s = SecretString::new(plaintext);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ impl SqlitePersister {
/// every subsequent `store()` call on this persister until overwritten
/// or cleared. A test that wants it to fire exactly once (the common
/// case) needs its own latch — see `release_at_store_seam` in
/// `tests/common` for the pattern.
/// `tests/integration/common` for the pattern.
#[doc(hidden)]
#[cfg(any(test, feature = "__test-helpers"))]
pub fn set_store_flush_seam_for_test(&self, seam: Arc<dyn Fn() + Send + Sync>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//! DashPay state is rehydrated from the identities `entry_blob`, which is the
//! authoritative load source. They exist for future per-profile/per-payment
//! indexed queries. Round-trip pinned by
//! `tests/sqlite_dashpay_overlay_contract.rs`.
//! `tests/integration/sqlite_dashpay_overlay_contract.rs`.
//!
//! # …which is why the payment overlay is also PATCHED into `entry_blob`
//!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
//! git worktree add --detach /data/git-worktrees/<name>-base origin/v4.2-dev
//! cargo build -p platform-wallet-storage --bin platform-wallet-storage --features cli
//! <target>/debug/platform-wallet-storage --db <dir>/v42.db migrate --no-auto-backup
//! V4_2_DEV_DB=<dir>/v42.db cargo test -p platform-wallet-storage --test fixture_gen -- --ignored
//! V4_2_DEV_DB=<dir>/v42.db cargo test -p platform-wallet-storage --test integration fixture_gen:: -- --ignored
//! ```
//! The parent directory chain of `<dir>/v42.db` must not be group- or
//! world-writable, or the persister refuses it as an insecure parent.

mod common;
use crate::common;

use std::path::{Path, PathBuf};

Expand Down
85 changes: 85 additions & 0 deletions packages/rs-platform-wallet-storage/tests/integration/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! The crate's integration tests, built as one test binary.
//!
//! Each file in this directory is a module of a single test crate rather than
//! a test crate of its own. Every separate integration-test binary links the
//! crate's whole dependency graph, and with one binary per file the links
//! dominated CI build time. A new test file must be declared here, or it is
//! not compiled.

mod common;

mod fixture_gen;
mod persistence_error_kind_mapping;
mod review_4651_concurrent_payment;
mod secrets_api;
mod secrets_default_on_compiles;
mod secrets_guard;
mod secrets_mock_store_test_util;
mod secrets_scan;
mod sqlite_account_zero_attribution;
mod sqlite_accounts_reader;
mod sqlite_asset_locks_filter;
mod sqlite_auto_backup;
mod sqlite_backup_restore;
mod sqlite_blob_roundtrip_coverage;
mod sqlite_blob_size_gate_on_load;
mod sqlite_buffer_semantics;
mod sqlite_check_constraints;
mod sqlite_cli_smoke;
mod sqlite_commit_writes_lock_poison_shortcircuit;
mod sqlite_compile_time;
mod sqlite_contacts_keys_rehydration;
mod sqlite_core_pool_writer;
mod sqlite_core_state_reader;
mod sqlite_dashpay_overlay_contract;
mod sqlite_delete_buffer_reconcile;
mod sqlite_delete_cross_process_exclusion;
mod sqlite_delete_partial_commit_window;
mod sqlite_delete_real_apply_failure;
mod sqlite_delete_wallet;
mod sqlite_delete_wallet_constraint_carveout;
mod sqlite_deleted_wallet_residue;
mod sqlite_error_classification;
mod sqlite_fk_changeset_ordering;
mod sqlite_foreign_db_rejection;
mod sqlite_foreign_keys;
mod sqlite_identity_hard_delete;
mod sqlite_identity_index_concurrency;
mod sqlite_identity_index_uniqueness;
mod sqlite_identity_keys_reader;
mod sqlite_identity_scan_state;
mod sqlite_legacy_state_migration;
mod sqlite_load_reconstruction;
mod sqlite_load_wiring;
mod sqlite_migration_execution;
mod sqlite_migrations;
mod sqlite_money_column_overflow_on_read;
mod sqlite_object_metadata;
mod sqlite_open_integrity_check;
mod sqlite_open_version_gate;
mod sqlite_permissions;
mod sqlite_persist_roundtrip;
mod sqlite_pool_reader;
mod sqlite_provider_key_accounts;
mod sqlite_qa_identity_removal;
mod sqlite_recovery_mode;
mod sqlite_recovery_mode_write_block;
mod sqlite_restore_cross_process_exclusion;
mod sqlite_restore_open_path_guard;
mod sqlite_restore_staged_validation;
mod sqlite_schema_pinning;
mod sqlite_second_open_guard;
mod sqlite_sent_payment_verdict_durability;
mod sqlite_shielded_viewing_keys;
mod sqlite_store_flush_seam;
mod sqlite_store_generation;
mod sqlite_structural_hardening;
mod sqlite_trait_dispatch;
mod sqlite_transaction_sweeps;
mod sqlite_unowned_identities;
mod sqlite_used_core_addresses;
mod sqlite_v008_isolation;
mod sqlite_v008_migration;
mod sqlite_version_bump;
mod sqlite_wallet_db_identity;
mod tracked_masternodes_roundtrip;
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ fn tc_code_004_b_source_preserves_inner_display_chain() {
/// outer `WalletStorageError` match.
#[test]
fn tc_code_004_e_is_transient_outer_match_is_wildcard_free() {
let src = include_str!("../src/sqlite/error.rs");
let src = include_str!("../../src/sqlite/error.rs");
let outer = extract_outer_match_self_body(src, "pub fn is_transient(&self) -> bool")
.expect("is_transient outer match body must be present");
assert_no_wildcard(&outer, "is_transient");
Expand All @@ -385,7 +385,7 @@ fn tc_code_004_e_is_transient_outer_match_is_wildcard_free() {
/// match over `ErrorCode` may have its own wildcard.
#[test]
fn tc_code_004_e_error_kind_str_is_wildcard_free() {
let src = include_str!("../src/sqlite/error.rs");
let src = include_str!("../../src/sqlite/error.rs");
let outer = extract_outer_match_self_body(src, "pub fn error_kind_str(&self) -> &'static str")
.expect("error_kind_str outer match body must be present");
assert_no_wildcard(&outer, "error_kind_str");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Review regression: a concurrent payment must survive an adapter snapshot.
mod common;
use crate::common;

use std::collections::BTreeMap;
use std::sync::atomic::AtomicBool;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Positive secret-leak guard for `src/secrets/` (SEC-REQ-4.5.1).
//!
//! `tests/secrets_scan.rs` deliberately exempts `src/secrets/`, so this
//! `tests/integration/secrets_scan.rs` deliberately exempts `src/secrets/`, so this
//! module needs its own string-level guard: no `tracing::*` /
//! `println!` / `eprintln!` / `format!`-family call may take an
//! `expose_secret()` result as an argument. Same spirit as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! carries. Value-level safety is a separate guarantee via the sealed
//! `PersistableBlob` trait in `src/sqlite/schema/blob.rs`. Files outside
//! `schema/` define no columns and are not scanned; `src/secrets/` is
//! exempt by design and covered by its own `tests/secrets_guard.rs`.
//! exempt by design and covered by its own `tests/integration/secrets_guard.rs`.
//! Legitimate uses inside doc comments are allow-listed via `ALLOWLIST`.

use std::path::Path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Genesis-rescan regression for UTXO attribution when a freshly-derived
//! gap-limit-edge address has no persisted pool row.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! into a keyless [`AccountRegistrationEntry`] manifest, bit-exact,
//! fail-hard on a corrupt blob, and never mints a `Wallet`.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use key_wallet::account::{AccountType, StandardAccountType};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! rows so a spent one-shot lock never resurrects as actionable on
//! rehydration, while the historical row stays on disk.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use dashcore::hashes::Hash;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

//! TC-050..TC-055 — automatic backups.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use platform_wallet_storage::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

//! TC-031..TC-039 — online backup, restore source validation, retention.

mod common;
use crate::common;

use std::fs;

Expand Down Expand Up @@ -381,7 +381,7 @@ fn tc_code_009_b_backup_to_non_already_exists_maps_to_io() {
/// invoked in `backup.rs`.
#[test]
fn tc_code_014_a_backup_calls_parent_fsync() {
let src = include_str!("../src/sqlite/backup.rs");
let src = include_str!("../../src/sqlite/backup.rs");
let calls = src.matches("fsync_parent_dir(").count();
assert!(
calls >= 3,
Expand All @@ -394,7 +394,7 @@ fn tc_code_014_a_backup_calls_parent_fsync() {
/// aren't misled about durability guarantees.
#[test]
fn tc_code_014_b_atomicity_doc_mentions_fsync() {
let src = include_str!("../src/sqlite/backup.rs");
let src = include_str!("../../src/sqlite/backup.rs");
let lower = src.to_lowercase();
assert!(
lower.contains("fsync") || lower.contains("sync_all"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! variant, not a partial/empty one) is what makes this a guard that would
//! actually have caught the bug.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use dashcore::hashes::Hash;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! directly via raw SQL so the production encode path (which enforces the cap
//! on writes) is bypassed — simulating a tampered / corrupted local wallet DB.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use rusqlite::params;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! `persister.rs::lock_conn_for_test`; tests that need to inject a
//! failure poison the DB through that handle and verify rollback.

mod common;
use crate::common;

use std::collections::BTreeMap;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! row carrying a label outside the const array is rejected by SQLite
//! with `SqliteFailure(ConstraintCheck, _)`.

mod common;
use crate::common;

use common::{fresh_persister, wid};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

//! CLI smoke tests for the maintenance binary.

mod common;
use crate::common;

use std::process::Command;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! `force_next_flush_to_fail` injector. The permanence test poisons the real
//! connection mutex from a panicking thread.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister_with_mode, wid};
use platform_wallet::changeset::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! TC-P1-003 — every writer call site uses `prepare_cached`.
//! TC-P4-011 — `ClientStartState` keeps the base public shape.

mod common;
use crate::common;

use std::sync::Arc;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! afterwards. store → drop → reopen → `load()` → assert on the
//! `ManagedIdentity` fields directly.

mod common;
use crate::common;

use std::collections::{BTreeMap, HashSet};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! Covers pool rows with their `used` flags, the pool-resolved account index,
//! idempotent per-changeset pool state, and `key_class` survival.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use key_wallet::account::{AccountType, StandardAccountType};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! `CoreChangeSet` (UTXOs, records, IS-locks, sync watermarks), and the
//! no-silent-zero balance contract holds end-to-end.

mod common;
use crate::common;

use common::{ensure_wallet_meta, fresh_persister, wid};
use dashcore::hashes::Hash;
Expand Down
Loading
Loading