A Rust workspace audit that emits a signed, replayable receipt alongside its findings. Eighteen rules across three tiers, append-only identifiers, and a receipt that pins the commit, the manifest hash, the advisory snapshot, the pattern set and the toolchain. Nothing is fetched during a run. Verification is offline.
How it works · The receipt · Signing · Rule set · Docs
Status: in development, not released. The library crates exist and are tested. There is no published binary, no container image on any registry, and no receipt has been signed by a released build. Do not depend on the receipt format yet — it is versioned, but it has not had to survive anything.
Rule identifiers are not stable before v1.0.0. From that tag onward they are
permanent and append-only: changed detection mints a new id and the old one is deprecated
rather than edited. Until then a rule may be corrected in place, because the point of
releasing early is to find out which rules were wrong. Receipts always record the manifest
version and hash, so a pre-1.0 receipt stays checkable against the manifest it names — what
it does not carry is a promise that R001 still means today what it meant then.
Static analysis of a Rust workspace against a versioned, append-only rule set. The output is a findings set plus a receipt that pins everything needed to re-run it: the commit SHA, the manifest hash, the advisory database snapshot, the secret pattern set version, and the toolchain.
The rules live in probecrux.rules.yaml. That file is the
product; the runner is plumbing.
Every pin is resolved before a single rule runs. A receipt assembled from what a run happened to use is a description; one assembled from what a run was told to use is a constraint. The three tiers stay in separate sections all the way to the output, because a blended total lets an unreproducible finding inherit the credibility of a reproducible one.
More detail: docs/architecture.md.
Reproducibility is the product. Where reproducibility and coverage conflict, reproducibility wins. That is why the deterministic tier ships first and alone.
Say what was checked, and what was not. Rules that did not run are listed with a reason. The absence of a finding only means something if you know the rule executed.
Never overstate the claim. ProbeCrux reports findings for triage. It does not issue assurance, certification, or a legal opinion, and it will not be worded as though it does.
Be honest about where the rules lie. Every rule carries a false_positives field
describing where it produces noise. It is written before the detection logic, not
appended afterwards — a rule whose failure modes cannot be described is not ready.
Full statement in docs/goals.md, including non-goals, which are the more useful half.
These rules, at this version, were evaluated against this commit at this time, and produced this findings set.
That the repository is secure, correct, fit for purpose, or free of defects outside the scope of these rules.
ProbeCrux reports findings for triage. It does not issue assurance. It is not an audit in any regulatory sense, it is not a legal opinion, and a passing run is not evidence that a codebase is safe.
Retroactive provenance is not a thing. A report tells you what a tool found; it does not let a third party check that the tool was run the way you say it was. Pinning the manifest hash, the commit, and the advisory snapshot means someone else can re-run the same rules against the same code and get the same answer — or fail to, which is also useful information.
Receipts are signed with an Ed25519 key, and the receipt records which class of key signed it. The distinction matters more than it first appears, and choosing the wrong one produces a receipt that does not say what you need it to say.
project — the key published in keys/, used by default when ProbeCrux runs
as a hosted tool. Its public half is in this repository, so anyone can verify a receipt
offline without arranging anything with anyone. What such a receipt establishes is:
an unmodified ProbeCrux build produced this findings set, for this commit, under this manifest
It does not establish who ran it. The same key signs everyone's runs, so it is tamper-evidence, not attestation of a party.
operator — your own key, which ProbeCrux never generates and never holds. A receipt
signed with it binds the findings to whoever controls that key. If you have an evidence
obligation — an audit, a procurement questionnaire, a customer asking what you check and
when — this is the one you want, because it is the only one that says you produced the
result.
probecrux run <repo> --signing-key <path> --key-class operator
The key may also be supplied as base64 in PROBECRUX_SIGNING_KEY, which is the shape
secret stores want and avoids the material touching disk.
If the configured key cannot be loaded, the run fails. ProbeCrux does not generate a replacement, and there is no code path that can. A tool that quietly invents a key still emits receipts, and they still verify against themselves — a signature that attests to nothing, produced by a run reporting success. See D010.
Verification is offline in both cases. A verifier that fetches a key can be given a different answer by whoever controls the network, so ours does not fetch.
Eighteen rules across three tiers.
| Tier | Count | Reproducible | Ships |
|---|---|---|---|
deterministic |
15 | Byte-identical on re-run | v1 |
heuristic |
2 | Only with thresholds pinned | v2 |
advisory |
1 | No — model-assisted | v2 |
Advisory findings are reported in their own section and are never merged into the deterministic set.
Being in the manifest and being implemented are different things. The manifest is the specification; the binary states which rules it actually implements, and every rule that did not run appears in the report with a reason. A rule left out of a report would read as one that ran and found nothing, and those are opposite statements.
- Append-only. Rules are never deleted or edited in place. A receipt pins rule
IDs, so if
R001means something different at v0.4 than it did at v0.1, every v0.1 receipt becomes unreplayable. - Changed logic means a new ID. Only prose fields —
rationale,remediation,false_positives— may be edited in place, because they do not change what was detected. - Nothing is fetched live. The advisory database and the secret pattern set are pinned snapshots. A live lookup would make every run unreplayable, which would defeat the point of the exercise.
probecrux.rules.yaml |
The rule set. The specification, not a description of one. |
| docs/goals.md | What this is for, what it is not for, and what counts as done. |
| docs/architecture.md | Pipeline, components, invariants, first-release scope. |
| docs/decisions.md | Decision record. Append-only; superseded entries stay. |
Not yet — there is nothing to contribute to until the manifest crate exists. When there is, the constraints in CLAUDE.md apply to human and machine contributors alike, and the append-only rules in D002 are the ones most easily broken by accident.
Apache-2.0. See LICENCE.