fix(fuzz): the crate was invisible to lint, dependabot, audit, deny, and osv - #453
Merged
Conversation
added 6 commits
August 21, 2026 04:48
`kanon lint` reported 15 findings in `fuzz/`, every one introduced when the crate landed in #428. None of them was ever going to be caught: the crate carries its own empty `[workspace]` table so a nightly sanitizer build stays out of the stable workspace, and that same detachment means `cargo clippy --workspace` and the CI gate never lint it. It is the only directory in the repo outside both. Manifest sections now follow the canonical order the rule encodes — workspace, package, bin, dependencies, package.metadata — and the expanded `[dependencies.kerykeion]` block folds into `[dependencies]`, where a single-key sub-table belonged anyway. A LICENSE sits at this crate's own workspace root, which is what `MANIFEST/license-spdx-match` was asking for: an `[workspace]` table makes `fuzz/` a root in its own right, so the repository LICENSE one directory up does not reach it. `message_parse` had an `.expect()` flagged as library code. Replacing it with `panic!` traded one rule for another, which is the tell that neither was the fix: the property wanted is that a message this parser produced decodes again to the same bytes, and that is one comparison, not a match arm plus an assertion. It now reads as a single `assert_eq!` over `Option<&[u8]>`, which also states the decode-succeeds half that the previous shape left implicit. The unconditional `let _ = ToRadio::decode(data)` became `drop(..)`, since discarding is the intent and a bare `let _` on a Result reads as an oversight wherever it appears. The README's prose findings were em dashes and hedges, rewritten rather than suppressed. Verified: `kanon lint . --all` reports zero findings under `fuzz/` (repo total 48 to 33), and `cargo +nightly check --target x86_64-unknown-linux-gnu` still builds the crate.
`fuzz/` declares its own empty [workspace] table so a nightly sanitizer build stays out of the stable workspace. That detachment is deliberate and correct, and it also puts the crate outside every repo-wide check keyed to the root manifest: `cargo audit`, `cargo deny`, and dependabot's `directory: /` entry all resolve the root graph and never see it. So `libfuzzer-sys`, `prost`, `tokio-util` and `bytes` have had no dependency update coverage at all since the crate landed. A second cargo entry at /fuzz closes that. This is the same root cause as the lint debt in the preceding commit: one detached directory, invisible to four separate repo-wide checks, each of which looks like it covers the whole repository.
Dependabot updates a binary crate by moving its lockfile, so the /fuzz entry added in the previous commit needs one to act on. Committing it also makes the scheduled fuzz run reproducible and removes the untracked file any local `cargo check` in that directory leaves behind.
cargo-deny, cargo-audit and osv-scanner all ran against the root workspace only. `fuzz/` declares its own [workspace], so none of the three ever resolved its graph: cargo-deny follows the manifest it is given, cargo-audit reads one lockfile, and the osv step named `--lockfile=Cargo.lock` explicitly. The result was that `libfuzzer-sys`, `prost`, `tokio-util` and `bytes` had no vulnerability scanning at all -- three independent security checks, each looking like it covered the repository, and a directory none of them could see. Each is extended by a second invocation rather than a widened first one, because no flag on any of the three spans two workspaces. The comments say so at each site, since "why is this run twice" is the obvious question and collapsing them back into one is the obvious wrong answer. With the preceding commits this closes the whole class for `fuzz/`: kanon lint, dependabot, cargo audit, cargo deny, and osv-scanner. The detachment that makes it invisible is deliberate -- a nightly sanitizer build must stay out of a stable workspace -- so the fix is to name it in each check rather than to attach it.
The action always emits `--manifest-path` from its `manifest-path:` input,
defaulting to ./Cargo.toml, so supplying another one inside `arguments:` gave
cargo-deny the flag twice and it refused to run at all:
error: the argument '--manifest-path <MANIFEST_PATH>' cannot be used multiple times
A harness fault rather than a finding, and one only CI could surface — the flag
is correct on its own and the duplication lives in the action's plumbing.
The other two extensions in this branch worked first time: `cargo audit
--file fuzz/Cargo.lock` and the added `--lockfile=fuzz/Cargo.lock` both ran
green, which is the first vulnerability scan that dependency tree has ever had.
The first cargo-deny run that could see the fuzz workspace rejected libfuzzer-sys 0.4.13: it is `(MIT OR Apache-2.0) AND NCSA`, and NCSA was in no allow list. That is a real licensing fact about a dependency this repo has carried since #428 and nothing could report until now, which is the whole argument for extending the check. NCSA is the University of Illinois/NCSA Open Source License — permissive, OSI-approved, FSF Free/Libre, and compatible with this workspace's AGPL-3.0. libfuzzer-sys carries it because it wraps LLVM's libFuzzer, which predates LLVM's relicensing to Apache-2.0-with-LLVM-exception. Recorded as a per-crate exception rather than a twelfth entry in `allow`. The grant is sound for this dependency; a global entry would also accept NCSA from any future crate in the shipped runtime graph, which is a different and unexamined question. Nothing outside the detached fuzz workspace depends on libfuzzer-sys.
forkwright
pushed a commit
that referenced
this pull request
Aug 21, 2026
🤖 I have created a release *beep* *boop* --- ## [0.6.0](v0.5.0...v0.6.0) (2026-08-21) ### Features * **koinon,kryphos:** sign the audit log tip and verify which installation produced it ([#451](#451)) ([9b839bc](9b839bc)) ### Bug Fixes * **fuzz:** the crate was invisible to lint, dependabot, audit, deny, and osv ([#453](#453)) ([1cb6fc2](1cb6fc2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fuzz/was invisible to every repo-wide check. Five of them.I found this while producing lint evidence for #377: a
kanon lint . --allatorigin/mainreturned48 findings, and 15 were in
fuzz/— every one introduced when that crate landed in #428, earliertonight. Nothing was ever going to catch them.
Why nothing saw it
The crate declares its own empty
[workspace]table so a nightly sanitizer build stays out of thestable workspace. That is deliberate and correct. It also means every check keyed to the root
manifest resolves a graph that does not contain it:
fuzz/cargo clippy --workspace/ the CI gatekanon lintdirectory: /onlycargo auditcargo denyosv-scanner--lockfile=Cargo.lockexplicitlySo
libfuzzer-sys,prost,tokio-utilandbyteshave had no vulnerability scanning and nodependency updates since the crate was added. Three separate security jobs, each looking like it
covered the repository.
What changed
The lint debt is cleared —
kanon lint . --allnow reports zero findings underfuzz/, repototal 48 → 33. Manifest sections follow the canonical order the rule encodes (workspace, package,
bin, dependencies, package.metadata), the single-key
[dependencies.kerykeion]block folds into[dependencies], and a LICENSE sits at this crate's own workspace root — which is whatMANIFEST/license-spdx-matchwas asking for, since[workspace]makesfuzz/a root in its ownright and the repository LICENSE one directory up does not reach it.
One fix was worth more than the lint that prompted it.
message_parsehad an.expect()flaggedas library code; replacing it with
panic!traded one rule for another, which is the tell thatneither was the fix. The property wanted is a message this parser produced decodes again to the same
bytes — one comparison, not a match arm plus an assertion. It is now a single
assert_eq!overOption<&[u8]>, which also states the decode-succeeds half the previous shape left implicit.The coverage gap is closed at each site: a
/fuzzdependabot entry, a secondcargo denyrunwith
--manifest-path fuzz/Cargo.toml, a secondcargo auditwith--file fuzz/Cargo.lock, and--lockfile=fuzz/Cargo.lockadded to the osv step. Each is a second invocation rather than a widenedfirst one, because no flag on any of the three spans two workspaces — the comments say so at each
site, since "why is this run twice" is the obvious question and collapsing them is the obvious wrong
answer.
fuzz/Cargo.lockis now committed, because dependabot updates a binary crate by moving its lockfileand cannot act without one. It also removes the untracked file any local
cargo checkin thatdirectory leaves behind.
Verification
kanon lint . --allat this branch: zero findings underfuzz/.cargo +nightly check --target x86_64-unknown-linux-gnuinfuzz/:Finished, exit 0 — thereordered manifest and rewritten target still build.
pre-push-verify.shderives crates from the branch diff and finds none: this touches onlyfuzz/(outside the workspace) and two CI files. The real verification is the security jobs themselves
reporting on this PR, which is the thing that could not happen before it.