Skip to content

chore: roll up security migration changes - #124

Merged
M3gA-Mind merged 320 commits into
tinyhumansai:mainfrom
senamakel:epic/8369-security-migration
Nov 3, 2026
Merged

M3gA-Mind merged 320 commits into
tinyhumansai:mainfrom
senamakel:epic/8369-security-migration

Conversation

@senamakel

@senamakel senamakel commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Prerequisite: TinyBus PR #116 must merge and provide its connection APIs before this PR is ready to merge. This roll-up pins that TinyBus head so its storage adapter can compile.

Upstream roll-up required before OpenHuman can advance its gitlink. Carries commit 077bc2e referenced by tinyhumansai/openhuman#8487. Validation on this head: cargo test -p tinywallet-bus, cargo test -p tinywallet-x402 --features ledger ledger_and_bus_declare_the_same_collections, cargo test -p tinywallet-module every_stored_item_is_wallet_owned_and_module_scoped, cargo check -p tinywallet-module, cargo test --manifest-path proof-workspaces/storage-contract/Cargo.toml, and cargo fmt --all -- --check passed.

Summary by CodeRabbit

  • New Features
    • Added a typed wallet client for account derivation, signing, key export, mnemonic operations, and ERC-20 transfer encoding, with support for attested calls.
    • Added checks to match wallet execution requests against prepared quotes, plus chain-to-RPC endpoint identification.
  • Improvements
    • Ledger storage now handles migration of existing payment and budget data when opened with host-provided storage.
    • Payment records from the previous release remain available after migration.
  • Compatibility
    • The ledger reports an error when host-provided storage is unavailable.

Contract boundary follow-up

The bus now owns a name-only CollectionDeclaration for wallet storage. The host translates it into its own storage-driver type, keeping tinywallet-bus free of the tinystoragedrivers-types implementation dependency. The downstream storage-contract proof still verifies the two exported collection names, and the ledger test compares those names with its declarations.

Validation on the updated head:

  • cargo test -p tinywallet-bus (61 unit tests and 1 doctest)
  • cargo test -p tinywallet-x402 --lib --features ledger (141 tests)
  • cargo test --locked --manifest-path proof-workspaces/storage-contract/Cargo.toml
  • cargo clippy -p tinywallet-bus --all-targets -- -D warnings
  • python3 scripts/test_native_e2e_topology.py (7 tests)
  • cargo fmt --all -- --check

This PR remains draft pending TinyBus PR #116, which supplies the required connection APIs.

The all-feature CI compile also exercised the module-level ownership test. Updated it to compare the portable collection names directly, avoiding a test-only dependency on the removed storage-driver collection type. bash scripts/test-features.sh passes on this head.

…ested calls

Attested calls now surface the detailed failure through `ClientError::Remote` instead of a separate `Attested` variant, so callers can inspect the wire classification while `Debug` and `Display` still redact untrusted names and prose. The pending test was promoted to a real integration test and the test support fixtures were reindented.

Auto-committed-on: macbook
The expected_module_unavailable helper now checks the Remote variant and
inspects the failure kind instead of matching the Attested variant, keeping
the assertion in line with how the client surfaces module call errors.

Auto-committed-on: macbook
…oker on drop

Test support items are now crate-visible instead of fully public, and the
fixture's broker task is aborted by a Drop implementation rather than an
explicit shutdown helper. The unused fixture_cache helper was removed, so
callers no longer need to remember to shut the broker down manually.

Auto-committed-on: macbook
Add the ModuleCallError import to the client test module so tests can
reference the error type.

Auto-committed-on: macbook
… requests

Replace the generic wipe-observer stub with real SignRequest, SignMessageRequest and ExportRequest fixtures so the guard is exercised against the actual request types, and assert that each one has its mnemonic cleared after both success and error as well as when the waiting call is cancelled.

Auto-committed-on: macbook
…client wrappers

The guard tests now drive sign_transaction, sign_message and export_key through the real client against a pending module, recording wipes via an observer hook, so the error and cancellation paths are verified end to end rather than by constructing request structs directly.

Auto-committed-on: macbook
Added a comment explaining how the strict release record fixture is configured so the strict call reaches preparation while the fake access prevents any attestation or request from succeeding.

Auto-committed-on: macbook
…d cancellation

Add tests verifying that the mnemonic request guard zeroizes the mnemonic after both successful and failed completion, and also when the waiting task is cancelled mid-flight.

Auto-committed-on: macbook
Sign, sign-message, and export-key requests now wrap their payloads in a guard that zeroizes the mnemonic once the attested call returns, matching the existing derive path. This keeps recovery phrase material from lingering in memory after signing or key export.

Auto-committed-on: macbook
The strict record fixture now returns an option instead of panicking when the host has no module platform candidate, and the cancellation test returns early in that case so the suite no longer fails on unsupported hosts.

Auto-committed-on: macbook
Update the tinybus dependency and vendored submodule from 0.2.2 to 0.3.2
across the workspace and the tinywallet-module crate, and point the release
workflow at the matching reusable workflow revision.

Auto-committed-on: macbook
Update the lockfile for the tinybus, tinybus-macros, and tinybus-module
crates from 0.2.2 to 0.3.2, and pin tempfile's getrandom dependency back
to 0.3.4.

Auto-committed-on: macbook
…xtures

Each integration-test crate compiles the shared support module independently, so items unused by one crate triggered dead code warnings; an expect attribute now documents and suppresses them. The error-matching and map closures were also tidied into let-else and unit-pattern forms.

Auto-committed-on: macbook
Replace the no-op closure with the drop function when discarding the
loaded value, which is clearer and avoids a redundant closure.

Auto-committed-on: macbook
Replaced the trivial closure mapping to unit with the drop function in the test support helper, which is equivalent but more idiomatic.

Auto-committed-on: macbook
…w test

Bump the pinned reviewed release workflow commit and the tinybus revision to their current values so the test asserts against the versions actually in use.

Auto-committed-on: macbook
The release version test now globs every crate manifest instead of listing them by hand, so newly added crates are covered automatically, and the expected version is bumped to 0.25.0.

Auto-committed-on: macbook
Updates the tinybus and tinybus-module dependencies from 0.3.2 to 0.3.3, moving the pinned git revision to 207a9a7 across the workspace manifest, the module crate, and the vendored submodule. The release workflow test's expected revision is updated to match so the pinned-rev check keeps passing.

Auto-committed-on: macbook
The end-to-end scripts now also execute the attested_errors test
target alongside the existing attested and unattested suites, so the
detailed attested error path is covered by the same environment setup.

Auto-committed-on: macbook
Add a test asserting that both the shell and PowerShell end-to-end
scripts invoke the detailed attested_errors target, so the native e2e
runs keep exercising that path.

Auto-committed-on: macbook
Updates the lockfile to reflect the 0.3.3 release of the tinybus, tinybus-macros, and tinybus-module crates, and pulls in getrandom 0.4.3 as a transitive dependency.

Auto-committed-on: macbook
…o.json,proof-workspaces/storage

Auto-committed-on: macbook
The mnemonic zeroization test asserts emptiness with `assert!` rather than
`assert_eq!` so a regression would not print the secret phrase in the failure
output. An `expect` attribute documents the deliberate lint suppression.

Auto-committed-on: macbook
Delete the cached .pyc file for the bus boundary checker so generated
bytecode is no longer tracked in the repository.

Auto-committed-on: macbook
Added __pycache__/ to .gitignore so Python bytecode caches stay out of version control.

Auto-committed-on: macbook
…sts/attested_errors.rs,crates/t

Auto-committed-on: macbook
…rates/tinywallet-client/Cargo.t

Auto-committed-on: macbook
@tinysweeper tinysweeper Bot removed the priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. label Oct 30, 2026
@senamakel
senamakel marked this pull request as draft October 30, 2026 12:16
senamakel and others added 22 commits October 30, 2026 16:16
Keep upstream's CollectionSpec-based storage declarations and canonical
tinytools pin alongside the epic's payment schema, TinyBus and TSD work.
Version conflicts take the higher (0.27.0).

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The x402 runtime now reports a ledger migration failure as an error instead of leaving the previous process-wide ledger in place, and its docs clarify that the host must provision the wallet collections before calling it. The lifecycle e2e test was trimmed to assert that an unprovisioned artifact fails x402 closed, and the contributor docs now explain that the feature runners exclude the native client integration tests in favour of the e2e scripts.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The MSRV contract check now requires the bus manifest to stay free of the tinystoragedrivers-types dependency instead of requiring it, and the failure message reflects the corrected expectation.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Remove the stale tinybus 0.1.2 entry and its transitive zip, arbitrary, and zopfli dependencies from the lockfile now that all crates resolve to the single tinybus 0.3.12 source. Also reformat the legacy budget holds migration in the ledger schema for readability.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The v1 payment wire record and its conversion to stored data are no longer needed, so the module is deleted. The RFC 3339 parsing helper it carried goes with it.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinybus submodule to the latest upstream commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…orts

The end-to-end lifecycle test now invokes X402Configure through a typed X402ServiceHandle proxy instead of an untyped call, and removes the base64 imports that were no longer used.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The crate now takes its version from the workspace manifest instead of pinning its own, so releases are bumped in one place.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The version check now substitutes the workspace version when a crate manifest inherits it via `version.workspace = true`, so crates that don't pin an explicit version no longer fail the assertion.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The MSRV contract check now expects the bus manifest to depend on tinystoragedrivers-types rather than forbidding it, and the failure message was updated to describe the TSD v2 type contract at Rust 1.88.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Bumps tinywallet-bus to 0.27.0 and pulls in the new tinystoragedrivers-types dependency it now requires, keeping the workspace lockfile in sync with the updated dependency graph.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the workspace-inherited version with an explicit 0.27.0 so the client crate can be published independently of the workspace version.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the locked tinywallet-client version from 0.25.1 to 0.27.0 to pick up the latest published release.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ection declaration

The bus crate now defines its own CollectionDeclaration type instead of depending on tinystoragedrivers-types, so hosts can read collection declarations without pulling in the storage driver implementation. The schema test compares collection names rather than the concrete spec type to keep the cross-crate check working.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The MSRV contract check now flags the bus manifest when it contains the
tinystoragedrivers-types dependency rather than when it is missing, so the
portable collection declarations stay free of storage-driver dependencies at
Rust 1.88. The failure message was updated to match the new expectation.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Remove the tinystoragedrivers-types package and its dependency edge from tinywallet-bus in the storage-contract workspace lockfile, since the crate is no longer referenced.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now maps the storage collections to their names and compares the full list against the expected wallet.budgets and wallet.migrations entries, replacing the looser check that only verified a budgets collection existed.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the assertion macros and expected collections vector in the wallet ownership test to match rustfmt output. No test behaviour changed.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ipients case-insensitively

The TRC-20 arm accepted any well-formed hex parameter, so a quote for 25
units approved a transfer of any amount to anyone. It also required the
intent's expected_to to equal the quote's recipient, but a TRC-20
transaction pays the token contract, so every real TRC-20 intent failed.

Bind expected_to to the quote's token contract and require the parameter
to equal transfer(recipient, amount) built from the quote. Compare EVM
native recipients ignoring EIP-55 case, as token transfers already do.
The MSRV 1.88 lanes build and test on the restored versions
(cargo +1.88 check --locked --workspace --all-targets --all-features;
cargo +1.88 test --locked -p tinywallet-x402 --features ledger), so the
downgrade was not needed.
@M3gA-Mind

Copy link
Copy Markdown
Contributor

I've pushed two review commits on top of 73c212f:

fix(intent): TRC-20 is now bound to the quote. native_intent_matches_quote accepted any well-formed hex as a TRC-20 parameter, so a quote for 25 units approved a transfer of any amount to anyone. It also required the intent's expected_to to equal the quote's recipient. A TRC-20 transaction pays the token contract, though (build_transaction sets expected_to to the contract), so every real TRC-20 intent was refused once an approval was active.

The arm now:

  • requires expected_to == quote.token_address;
  • requires parameter_hex == transfer(recipient, amount), built from the quote. The recipient's base58check address is decoded in-crate, because the bus boundary allows only serde and thiserror.

Tests use real vectors (USDT TR7NH…, recipient TUEZS…) and cover wrong amount, wrong recipient, wrong token or target, a missing token_address, and malformed hex. EVM native recipients are now compared ignoring EIP-55 case, as token transfers already were.

OpenHuman carried an identical host copy of these matchers. #8512 now calls tinywallet_bus::intent instead, so the fix reaches the host with the next vendor/tinywallet bump.

Follow-ups, not in this PR

  • Solana token messages are still unbound (SolanaMessage checks only well-formed hex). Binding the recipient needs the SPL associated-token-account derivation (sha256 plus an ed25519 off-curve check), which the contract-only bus crate cannot link. That check belongs at the signer in tinywallet-crypto, the way Tron's verify_contract checks the node-built transaction.
  • EVM swap/bridge matching accepts any known chain when the quote has no network, so the chain id is not bound to the quote.
  • tests/lifecycle_e2e.rs lost the artifact-level x402 money-flow cases (prepare, deny, too-expensive, record, stale, budget, close). Unit tests still cover the ledger in-crate, but nothing exercises it over host-provided storage at the artifact boundary.
  • a25807e downgraded elliptic-curve, sha2, the icu* crates, idna_adapter, wasip2 and wit-bindgen without a stated reason. The last commit restores them: the MSRV 1.88 check and the wallet-ledger-msrv tests pass on the restored lock.
  • Response secrets (ExportedKey, the mnemonic seed and phrase) are returned without a zeroizing wrapper. Adding one changes tinywallet-client's public types, so it is left for a deliberate API change.
  • The tinybus and tinystoragedrivers dependencies point at personal-fork URLs (senamakel/*). This is the same pattern across modules and is being raised separately.

@M3gA-Mind
M3gA-Mind marked this pull request as ready for review November 3, 2026 06:44
@M3gA-Mind
M3gA-Mind merged commit 5271560 into tinyhumansai:main Nov 3, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants