Skip to main content

max / makenotwork

Make cargo_audit and cargo_deny run, and triage what they found Both gates failed their first run on the host with "error: no such command". cargo-audit and cargo-deny were not installed for the sando user, whose ~/.cargo/bin is first on sandod's PATH. Installed there; that part is not in this commit, but it is why the gates reported nothing rather than something. Three of the four failures were configuration, not risk. Licenses: deny.toml already carried exceptions for makenotwork and tagtree, spelt "PolyForm-Noncommercial-1.0.0", while both crates declare "LicenseRef-PolyForm-Noncommercial-1.0.0". The prefix is mandatory because PolyForm is not on the SPDX list. So the exceptions matched nothing — cargo-deny reported license-exception-not-encountered for both while rejecting the very crates they existed to cover. Bans: mnw-assumptions is internal-only and carries a path dep, but had no publish = false, so cargo-deny could not treat it as private and allow-wildcard-paths did not apply. crates.io would reject it anyway. Advisories drift: deny.toml's ignore list calls itself a mirror of .cargo/audit.toml and was already missing RUSTSEC-2026-0173. The one real decision is RUSTSEC-2026-0222 — wasmtime 43.0.2, "stores can mix up type indices between engines", 3.8 low, published 2026-07-31. It arrives via yara-x 1.19.0, the current release, which pins the 43 line; the fixed ranges are 24.0.12+, 36.0.13+, 46.0.2+ and 47.0.3+ and skip 43 entirely. Nothing we control can bump to a fixed version. Ignored, because the precondition does not exist here: the bug needs a store to cross between two wasmtime Engines, and production stands up exactly one. scanning/mod.rs:499 compiles the rules once while building the ScanEngine, and every other yara_x::Compiler::new() in the tree is under #[cfg(test)]. That claim is the whole justification, so compile_rules_from_dir now documents that a second production call site invalidates a recorded security posture rather than merely costing memory. Deliberately not claiming the scanner is isolated. yara-x runs in-process in the server's address space (scanning/mod.rs:192). What bounds it is that scanning runs on a dedicated worker pool off the request path, a panicking CPU layer is caught and converted to a fail-closed scan_panic verdict instead of unwinding the worker, and the CPU layers carry a wall-clock deadline. Defense in depth, not a sandbox. It monitors itself: cargo-deny reports an unreachable ignore as advisory-not-detected, so the entry announces its own obsolescence when yara-x moves to a fixed wasmtime. cargo audit exits 0; cargo deny reports advisories ok, bans ok, licenses ok, sources ok.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-03 18:51 UTC
Signed with PGP, not checked
Commit: 829d833373c4c0f1c11d7f4baed9d1ce7a09f14c
Parent: 9a8bf2b
4 files changed, +57 insertions, -2 deletions
M server/deny.toml +14 -2
@@ -21,6 +21,13 @@
21 21 "RUSTSEC-2020-0095", # difference unmaintained, via a dev/test dep.
22 22 "RUSTSEC-2024-0436", # paste unmaintained, via proc-macro deps.
23 23 "RUSTSEC-2025-0134", # rustls-pemfile unmaintained, via AWS SDK TLS.
24 + "RUSTSEC-2026-0173", # proc-macro-error2 unmaintained, via a macro dep. Was in .cargo/audit.toml but never mirrored here.
25 + # wasmtime "Stores can mix up type indices between engines" (3.8 low), via
26 + # yara-x 1.19.0, which pins the 43 line while the fixes skip it. Not
27 + # applicable: the bug needs two wasmtime Engines and production builds
28 + # exactly one (scanning/mod.rs:499). Full rationale + the condition that
29 + # would invalidate it: .cargo/audit.toml.
30 + "RUSTSEC-2026-0222",
24 31 ]
25 32
26 33 [bans]
@@ -68,7 +75,12 @@
68 75 confidence-threshold = 0.9
69 76 # First-party product crates carry the product license; allow it for exactly
70 77 # these, not tree-wide.
78 + # The identifier must carry the `LicenseRef-` prefix, because PolyForm is not on
79 + # the SPDX list and `license = "PolyForm-Noncommercial-1.0.0"` is not a valid
80 + # expression. These exceptions were written without it and so matched nothing —
81 + # cargo-deny reported both as `license-exception-not-encountered` while
82 + # simultaneously rejecting the crates they were meant to cover.
71 83 exceptions = [
72 - { name = "makenotwork", allow = ["PolyForm-Noncommercial-1.0.0"] },
73 - { name = "tagtree", allow = ["PolyForm-Noncommercial-1.0.0"] },
84 + { name = "makenotwork", allow = ["LicenseRef-PolyForm-Noncommercial-1.0.0"] },
85 + { name = "tagtree", allow = ["LicenseRef-PolyForm-Noncommercial-1.0.0"] },
74 86 ]
@@ -26,4 +26,31 @@
26 26 "RUSTSEC-2024-0436", # paste (unmaintained), via proc-macro deps
27 27 "RUSTSEC-2025-0134", # rustls-pemfile (unmaintained), via AWS SDK TLS
28 28 "RUSTSEC-2026-0173", # proc-macro-error2 (unmaintained), via a macro dep
29 +
30 + # wasmtime 43.0.2, "Stores can mix up type indices between engines"
31 + # (3.8 low, published 2026-07-31), reached only through yara-x 1.19.0, which
32 + # is the current release and pins the 43 line. The fixed ranges are 24.0.12+,
33 + # 36.0.13+, 46.0.2+ and 47.0.3+ — they skip 43 entirely, so there is no
34 + # version reachable by bumping anything we control. Waiting on yara-x.
35 + #
36 + # Not applicable as we run it. The precondition is a store crossing between
37 + # two wasmtime Engines, and production builds exactly one: scanning/mod.rs:499
38 + # calls yara::compile_rules_from_dir once while constructing the ScanEngine,
39 + # and every other yara_x::Compiler::new() in the tree is under #[cfg(test)].
40 + # One engine for the process lifetime means two engines never exist to
41 + # confuse. THAT is the load-bearing claim here — if a second compile ever
42 + # lands in a production path, this ignore stops being justified and has to be
43 + # re-argued (see the note in scanning/yara.rs).
44 + #
45 + # Worth being precise about the blast radius rather than calling it isolated:
46 + # yara-x runs IN-PROCESS, in the server's address space (scanning/mod.rs:192).
47 + # What does bound it is that scanning happens on a dedicated worker pool off
48 + # the request path, a panic in a CPU layer is caught and converted to a
49 + # fail-closed scan_panic verdict rather than unwinding the worker, and the
50 + # CPU layers carry a wall-clock deadline. Defense in depth, not a sandbox.
51 + #
52 + # Monitoring: cargo-deny reports an unreachable ignore as
53 + # `advisory-not-detected`, so this entry announces its own obsolescence once
54 + # yara-x moves to a fixed wasmtime. Prune it then.
55 + "RUSTSEC-2026-0222",
29 56 ]
@@ -3,6 +3,11 @@
3 3 version = "0.1.0"
4 4 edition = "2024"
5 5 license = "MIT"
6 + # Internal shared crate, never published: it carries a path dep on `subst`, and
7 + # crates.io rejects path dependencies. cargo-deny's allow-wildcard-paths exempts
8 + # a versionless path dep only for a crate it can see is private, so without this
9 + # the `wildcards = "deny"` ban fails on every consumer.
10 + publish = false
6 11
7 12 [dependencies]
8 13 subst = { path = "../subst" }
@@ -21,6 +21,17 @@
21 21 /// (or `None` when the directory is absent / empty) alongside the count of rule
22 22 /// files that compiled successfully, the caller uses that count to enforce an
23 23 /// optional health floor (see `ScanPipeline::assert_live`).
24 + ///
25 + /// **Call this exactly once per process.** `yara_x::Compiler::new()` stands up a
26 + /// wasmtime `Engine`, and the single live engine is what makes RUSTSEC-2026-0222
27 + /// ("stores can mix up type indices between engines", unfixed on the wasmtime 43
28 + /// line that yara-x 1.19 pins) inapplicable to us — the bug needs two engines to
29 + /// confuse, and there is only ever one. That reasoning is written down as the
30 + /// justification for ignoring the advisory in `.cargo/audit.toml` and
31 + /// `deny.toml`, so a second production call site does not just add overhead: it
32 + /// invalidates a documented security posture and the ignore has to be re-argued.
33 + /// Today the only caller is `ScanEngine` construction (`scanning/mod.rs`);
34 + /// everything else is under `#[cfg(test)]`.
24 35 pub fn compile_rules_from_dir(dir: &str) -> Result<(Option<yara_x::Rules>, usize), String> {
25 36 let path = Path::new(dir);
26 37 if !path.exists() {