Repository navigation
Description
Context
Tier 1 of the agentic-engineering hardening has landed (lint policy in the manifest, clippy.toml,
rustfmt.toml, deny.toml + cargo-deny CI, #![forbid(unsafe_code)] on deckard-core, closed CI
gaps, CLAUDE.md/AGENTS.md). The full rationale and the deliberately-rejected rules are in
docs/AGENTIC-ENGINEERING.md.
This issue tracks the Tier 2 / Tier 3 backlog. Each item was researched against paradigm Rust
repos (reth, alloy, Zed) and adversarially challenged by a cross-model (codex GPT-5.5) review —
that verdict is recorded per item below.
⭐ Promoted to "do now" (highest leverage)
Both models rank these above the rest because they harden the wallet engine and make the Tier-1
unused_must_use = "deny" actually bite.
1. Restriction lints in deckard-core
Clippy rules that make the security engine's production code unable to .unwrap() / panic! on
bad input (tests still unwrap freely, via the allow-*-in-tests keys already in clippy.toml).
Two paths — pick one:
- Safe (zero code change, lands green):
# crates/deckard-core — via lib.rs inner attrs or a non-workspace [lints] block unwrap_used = "deny" # clean: all real unwraps are in #[cfg(test)] get_unwrap = "deny" mem_forget = "deny" expect_used = "allow" # 2 non-test expects in eth.rs panic = "allow" indexing_slicing = "allow"
- Hardened (codex-preferred, ~3 small edits): also
denyexpect_used/panic/
indexing_slicing, and fix the real sites rather than blanket-allow — those sites (the keystore
byte-parser + RPC decode) are exactly where future agent-written indexing should be reviewed:eth.rs:48/eth.rs:97— startupexpect()s → documented fatal boundary or fallible spawn.keystore.rsReader(~492–505) — raw slice indexing → bounds-checked.get()+ explicit error.balances.rs:80—results[0]→.first().ok_or(...)?.
codex verdict: MODIFY → PROMOTE. "Promote the corrected core lint set now, with
expect_used,
panic, andindexing_slicingdenied and the current indexing/expect sites fixed rather than exempted."
2. #[must_use] audit on secret types
Tag the secret-bearing types/methods so the compiler errors if a caller creates one and ignores it:
Vault, UnlockedVault, Vault::unlock, account_signer, account_address, primary_address,
reveal_phrase.
codex verdict: PROMOTE. Low churn, directly useful;
unused_must_use = denyonly fully bites
once these are annotated.
Tier 2 — high value, some effort
3. cargo-nextest
A faster, nicer test runner than cargo test (parallel, clear per-test output, per-test timeouts).
Add .config/nextest.toml, install via a pinned taiki-e/install-action, run
cargo nextest run --locked --workspace; keep a separate cargo test --locked --doc (nextest skips
doctests).
codex verdict: MODIFY — use
retries = 0, NOT 2. Retries normalize flaky security tests,
which is dangerous for a wallet.fail-fast = false. Pin the install action version.
4. profile.dev tuning (faster debug crypto)
Make debug builds optimize the slow crypto so wallet create/unlock and tests aren't painful at
opt-level = 0.
codex verdict: MODIFY — do NOT optimize all deps (
opt-level=2for*slows the first
gpui/alloy compile and the agent feedback loop). Target just the crypto crates:[profile.dev.package.argon2] opt-level = 3 [profile.dev.package.blake2] opt-level = 3Drop
[profile.dev.build-override]unless measured.
5. Dependency + spelling hygiene
cargo-machete— find unused dependencies. Start manual / non-blocking: it false-positives the
cfg-gatedobjc2*+gpui-component-assets, but it correctly flags that the app's root
Cargo.tomllistsalloy-signer-local/alloy-primitivesas direct deps it may not use directly
(they're re-exported fromdeckard-core) — worth investigating.typos(crate-ci) in CI with a crypto-jargon allow-list +extend-exclude = ["Cargo.lock"].lefthookpre-commit hooks (fmt/clippy/typos) — local convenience only, NOT a CI gate (agents
bypass with--no-verify; CI is the real gate).
codex verdict: MODIFY/SPLIT (as above).
6. Doctests + rustdoc warnings
RUSTDOCFLAGS="-D warnings" cargo doc --locked --no-deps -p deckard-core
cargo test --locked --doc -p deckard-core
Catches broken intra-doc links and ensures any future doc examples compile.
codex verdict: KEEP — sensible, not urgent (no doc examples exist yet).
Tier 3 — revisit later
- Typed errors (
thiserror) for the keystore. Structured errors instead ofanyhow.codex verdict: MODIFY, do LAST.
⚠️ Keep one opaqueUnlockFailed— distinguishing
"wrong passphrase" vs "tampered" is an attacker oracle (surfaced viashort_errin
shell.rs). Only the keystore; keep network/provider errors asanyhowuntil there's real
programmatic handling. - proptest round-trips for the keystore binary format (
to_bytes/from_bytes, wrong-passphrase
rejection). Reuse the existingKdfParams::FAST_TESTprofile. - MSRV / toolchain-drift CI job —
cargo +1.95.0 build --locked+rust-version = "1.95.0"in
both manifests, to catch abump-gpuithat silently needs a newer compiler. - Automated monthly
bump-gpuiPR bot + Dependabot for the registry deps (serde, alloy,
argon2, tray-icon); Dependabot/Renovate handle git deps poorly. - Scheduled
cargo-auditcron (decouples the advisory time-signal from PR CI). merge_group+ a required aggregated check for branch protection (one-time repo-admin action).- cargo-vet / cargo-semver-checks / coverage gates — deferred (heavy / premature for a pre-1.0 app
with no external consumer).
Deliberately NOT recommended
See the table in docs/AGENTIC-ENGINEERING.md:
forbid(unsafe_code) at the workspace root, clippy::pedantic/nursery/full restriction,
indexing_slicing = deny workspace-wide, edition 2024, nightly rustfmt/build flags, panic = abort,
multiple-versions = deny, mold/lld linker config (1.95 already defaults to the fast linkers).
Activity
hellno commentedon Jun 6, 2026
✅ Promoted "do-now" items (1 & 2) are implemented — path B (hardened) — and verified green.
deckard-core/src/lib.rs:#![deny(clippy::unwrap_used, expect_used, get_unwrap, indexing_slicing, panic, mem_forget)]on top of the existing#![forbid(unsafe_code)].Reader::take→.get(range),::u8→.first().copied(),::u32→try_into(),parse_exact_32→iter_mut().zip(),balancesresults[0]→.first().ok_or(...).eth.rsexpects keep a scoped#[allow(clippy::expect_used)]+ documented reason (the 'documented fatal boundary' pattern).#[must_use]onVault/UnlockedVault(not theResult-returning methods — avoidsclippy::double_must_use).clippy.tomlallow-indexing-slicing-in-tests = true.Verified:
cargo clippy -D warningsclean on default and--features tray;cargo test --workspace13/13;cargo fmt --checkclean.A cross-model (codex GPT-5.5) adversarial pass found no semantics regression in the parser rewrites (checked empty/truncated buffers, exact-boundary reads, the 64-hex path). CLAUDE.md / AGENTS.md / docs now state these as enforced (no longer 'convention pending').
Remaining scope of this issue: Tier 2 items 3–6 (nextest, profile.dev, hygiene tools, doctests) + Tier 3.
hellno commentedon Jun 7, 2026
Speed-ideas adversarial review — outcome (do-later + dropped) & bonus findings
The "go 10× faster without breaking wallet trust" brainstorm was reviewed by two independent adversarial passes (codex GPT-5.5 cross-model + a repo-grounded per-idea workflow); they converged. Full draft + reconciled verdict:
.context/agentic-speed-ideas.md.Already done (separate from this issue, on
hellno/rust-agent-lint-rules): the three do-first items — the unlock no-oracle fix + test (a real shipping leak:read→from_bytesparse errors were distinguishable from wrong-passphrase at the UI; now collapsed viaVault::open/open_bytes), thejust corefast loop, and the #5b decode-compat fixtures (one per kind).Do-later
sccache≠ shared target dir; sccache can't cache build-scripts / proc-macros / linking (this tree has many). Local-only (sccache, or APFScp -cwarm-target-per-worktree); never remote (a network cache breaks the Cargo.lock reproducibility guarantee for key-material builds). It self-cannibalizes withjust core(Set up the deckard-contract crate + Cargo workspace (freeze-first wire) #2) — to the extent agents live in-p deckard-core, they stop paying the gpui build. Sequence Set up the deckard-contract crate + Cargo workspace (freeze-first wire) #2 first, then measure full-build frequency before investing.Vault::from_bytes(deckard-signerd — process-isolated signer daemon + policy gate (operator spine) #4) — defer. The parser is already the most-defended code in the repo (bounds-checkedReader, pre-alloc cap atMAX_CT_ENTROPY, adversarial tests) → low bug-yield.cargo-fuzzneeds nightly (toolchain-pin tension); evenproptestis a new dev-dep (needs Cargo.lock approval). The genuinely fragile surfaces are alloy/bip39 input handling and the AEAD round-trip, which this idea doesn't touch.Dropped
deckard-coreisn't pure (keystore fs I/O,std::thread, tokio runtime, alloy HTTP) → won't compile towasm32; miri ≈ nil value under#![forbid(unsafe_code)]. Reconsider only if adeckard-crypto/deckard-netsplit happens for other reasons.#[cfg(test)]-onlyseal_with_rngthat is compile-absent from release, plus extending clippydisallowed-methodsto ban seeded constructors (StdRng::from_seed, …).#8 capability firewalls — reshaped
Cheap tier already done (secret types don't derive
Debug— verified; the new no-oracle test even provesUnlockedVault: !Debugvia.err()vs.unwrap_err()). Drop the dylint tier — custom lints track rustc/clippy internals and would rot against the ~monthly gpui toolchain bumps.Bonus trust findings (real, actionable — surfaced by both reviewers)
account_signeris a public API returning aPrivateKeySigner(keystore.rs) — "transient signer, never stored" is a comment, not an enforced boundary. Consider sign-by-request so a raw signer never escapes the core.alloy-signer-local/alloy-primitiveslook like unused direct deps (re-exported fromdeckard-core) — acargo-machetecleanup.cargo-denyis not yet a real gate (continue-on-error: true+ the licenses allow-list is still a starting superset). Don't call the supply chain "gated" until: runcargo deny check licenseslocally to seed the list, confirm the AGPLcrate =exception key on the action's cargo-deny version, then dropcontinue-on-errorand mark it a required check.Agentic engineering: lint/CI/supply-chain policy + deckard-core harde…
build: agentic lint/CI/supply-chain policy + harden deckard-core
ADR 0004: pivot to "evaluated, deferred" — drop the anchor + prototype
ADR 0004: vault rollback resistance — evaluated, deferred (#71) (#119)