Skip to content

cashu-cdk-seller: corrections for advisor findings F1-F6 - #988

Open
maxy-player wants to merge 17 commits into
MakePrisms:mainfrom
maxy-player:w/cashu-cdk-seller
Open

cashu-cdk-seller: corrections for advisor findings F1-F6#988
maxy-player wants to merge 17 commits into
MakePrisms:mainfrom
maxy-player:w/cashu-cdk-seller

Conversation

@maxy-player

@maxy-player maxy-player commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Correction commits addressing the six blocking findings (F1–F6) from the independent review of aa8e831. The original evidence from that commit is preserved unchanged; these are additions on top, not a re-fold.

What this branch adds

c15f0ad — F1, F2, F3, F6

  • F1 (runtime-pinned Rust/CDK cache). The previous image had no cargo/rustc at all — build-time cache mounts are not layers, so nothing survived. The mint-builder stage now copies the toolchain to /opt/rust/toolchain and the crate registry cache to /opt/rust/cargo/registry, with CARGO_HOME=/opt/rust/cargo and CARGO_NET_OFFLINE=true. bin/cashu-toolchain-check is the proof command: it asserts toolchain identity, ≥50 cached .crate archives, presence of cdk-0.17.2 / cashu-0.17.2 / cdk-sqlite-0.17.2, then compiles the shipped examples/wallet-roundtrip with cargo build --offline --locked.
  • F2 (container-reachable knowledge). Seat memory now references topics by absolute container path under /opt/cashu/knowledge/ (cashu-corpus.md, test-mint.md, cdk-wallet-api.md, known-drift.md); no wikilinks that resolve only on the host.
  • F3 (private test state outside the delivered workdir). State root is /var/lib/cashu-test-state, created mode 1777. test-mint refuses to run with state under /work (assert_state_not_delivered), and a new test-mint isolation subcommand is the evidence command: exit 0 only when state is outside /work and no mint artifacts appear inside it.
  • F6 (locked deps, immutable replay identity). Every FROM is digest-pinned; CDK_VERSION, CDK_COMMIT (6132607…, tag v0.17.2) and NUTS_COMMIT (49a909c…) are build ARGs; cdk-mintd is installed --locked; the three helper crates ship generated Cargo.lock files.

0ac777d — F4, F5

  • F4 (recovery semantics). The previous documentation was wrong about check_all_pending_proofs. Read back from cdk 0.17.2 src/wallet/proofs.rs:112-185: it filters out saga-managed proofs, removes spent ones, and returns the total still pending — it does not move survivors back to Unspent. The real recovery path is recover_incomplete_sagas (wallet/recovery.rs:302) plus revoke_send (wallet/send/mod.rs:275), which swaps proofs back and is what actually returns value to the spendable set. Corrected in the knowledge topic and asserted in the gate.

  • F5 (exact negative predicates, real residual spend). Two ways the old gate could pass without proving anything, both closed:

    • Negative legs accepted any error, so a transport failure would have read as a rejected double spend. They now match the exact cdk variant — matches!(e, Error::TokenAlreadySpent) and matches!(e, Error::PaymentFailed) — on the variant, not a message substring.
    • Post-restart "no loss" compared total_balance, which reads the wallet's own localstore (wallet/balance.rs:10-20) and says nothing about mint state. The restart leg now sweeps every wallet's entire residual balance into a fresh wallet through the restarted mint and reconciles swept + fees against the pre-restart total, so the mint has to sign for all of it. It also re-presents the pre-restart spent token and requires TokenAlreadySpent, catching duplicate credit from a rolled-back database.

    Recovery is exercised from a genuinely non-empty unresolved state across a wallet restart on a real sqlite file (create token, never redeem, drop the wallet, reopen the same file), not with in-memory stores that never reopen.

Containment (unchanged)

Fakewallet backend only — cdk-mintd is built --no-default-features --features fakewallet,sqlite, so no real payment backend is compiled in and it cannot be pointed at real money. Loopback-only bind, enforced on both the host argument and the rendered config, and checked from /proc/net/tcp in the gate. The test mint is never added to accepted_mints. Worthless test ecash throughout.

Status — read this before reviewing

  • Image maxplayer-cashu-sandbox:v0.5.9-fix builds clean, and the image now proves the offline CDK build at build time (Finished dev profile ... in 39.34s), so it cannot ship claiming an environment it lacks.
  • Real bind-mounted runtime evidence is captured in reports/cashu-cdk-seller/delta-*-20260909.txt, from a container run with a host directory bind-mounted at /work:
    • F1 offline compile: rustc/cargo 1.98.1, 557 cached .crate archives, cdk/cashu/cdk-sqlite 0.17.2 present, example built --offline --locked and then run against the mint (issued 32, sent 8, melted 4, fee 1).
    • F5 corrected gate: PASS, 39 assertions across 10 legs.
    • F3 isolation: state at /var/lib/cashu-test-state, state inside delivered dir: no, no mint artifacts in /work, seed mode 600.
    • F2 knowledge topics present under /opt/cashu/knowledge/.
  • The original aa8e831 evidence files are preserved untouched; the old 22/22 gate is not offered as proof of these corrections.
  • reports/cashu-cdk-seller/AUTH-PROVISIONING.md documents the exact supported credential path and the concrete human setup step. Live marketplace readiness remains blocked on that human decision; no discovery evidence is claimed.

Three defects found by actually running this, not by reading it

  1. Four source sites carried placeholder text instead of real prepared.confirm(None) calls — caught by the first build failing.
  2. bash -lc lost the toolchain: Debian's /etc/profile assigns PATH unconditionally, so rustc was "not found" in an image that had it. Fixed with /etc/profile.d/10-rust-toolchain.sh plus the script resolving its own toolchain, so the proof cannot report a false negative based on how its caller spawned a shell.
  3. The runtime image had no C linker at all (no cc, no gcc, no ld). A toolchain plus a warm registry is not a build environment; the offline build died at linker \cc` not foundafter resolving every dependency correctly. Fixed by installinggcc, libc6-dev, binutilsand recording their exact versions into/opt/rust/TOOLCHAIN.txt`.

The first evidence run reported F1 as passing when it had not, because ; separators let a failure scroll past. That is fixed too: the evidence run is set -e throughout.

@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the MakePrisms Team on Vercel.

A member of the Team first needs to authorize it.

w-cashu-cdk-seller added 7 commits September 9, 2026 14:58
…3/F5 (offline compile, knowledge paths, state isolation, 39/10 gate)
…oning path (claude setup-token -> daemon env -> per-job placeholder)
… recovery branches to complete value, quoted fees not derived, check reserved
…nded-reserve counterexample and proves the corrected oracles reject it
…ovenance bounds, non-root bound-workdir recipe, human-only selected-field VPS setup; bound AUTH claims and cross-link both ways
@maxy-player

Copy link
Copy Markdown
Contributor Author

Focused-review corrections F4/F5/F6 — seller-local, 2e3cab0

Three commits on top of 5413b84, addressing verdict 20260909-cashu-cdk-5413b84-focused-review (sha256 fec80136…62e9):

  • b8492cfF4/F5. Corrected the baked cdk-wallet-api topic: three distinct balance pools (wallet/balance.rs:7-40), and check_all_pending_proofs() is not recovery — it returns the residual pending total and does not restore proofs (wallet/proofs.rs:112-185). Real path documented as recover_incomplete_sagas()get_pending_sends()revoke_send() (send/mod.rs:275), with an honest scope note (wallet-object/store reopen in-process; not OS crash, seed-only restore, or melt). In the harness: both recovery branches now bound to one closing contract (full funded value spendable, pending 0, reserved 0, reclaimed == stranded_amount); send_everything()'s amount-search loop with a derived fee replaced by a single full-balance prepare returning CDK's quoted fee; zero-fee precondition asserted from the mint keyset; drain checks include reserved.
  • a3b6a70targeted predicate regression (acceptance/src/bin/predicate-regression.rs), the only new evidence run. F1–F3 and the 39-assertion gate stand as accepted and were not re-run.
  • 2e3cab0F6. RUNBOOK-ADDENDUM.md as the authoritative operational handoff; RUNBOOK.md banner-marked historical (its v0.5.8-local tag, eb91a9… id and "22/8" figure are stale).

Predicate regression result — PASS, 10 oracle requirements across 3 fixtures. It builds a real wallet with 42 of 43 sats stranded in Reserved, then requires the shipped oracles to accept it and the corrected oracles to reject it. Both defects reproduce: the old drain oracle reports "fully drained" with 42 sats reserved, and the old derived-fee conservation relabels the shortfall as a fee. Evidence: reports/cashu-cdk-seller/delta2-predicate-regression-20260909.txt.

Image sha256:7fe93019c0fedc08242b3ff9f80d95fafa2f7c9cf3a7d1af6257bddff4ebc4c0 (tag v0.5.9-fix2), source-commit label a3b6a700. Provenance stated with bounds: built locally, unpublished, unsigned, no SBOM or attestation, and the label is a self-asserted claim. What is genuinely pinned is digest-pinned FROMs, --locked installs, and a build-time offline compile.

No corrected full-gate assertion count is quoted anywhere: the corrected gate has more assertions than 39 and I deliberately did not run it for a number, so the addendum tells the reader to run it and read the output instead.

Not done, not claimed: the seat still refuses to advertise without a model credential (Authentication required), so there is no probe artifact and no kind-0/kind-30340 evidence. The §6 seat image change is human-only and unperformed.

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