anchor audit PDFs under audit/protofire/ so the org health scan sees them - #56
anchor audit PDFs under audit/protofire/ so the org health scan sees them#56thedavidmeister wants to merge 2 commits into
Conversation
Both Protofire reports sat loose at the audit/ top level with names that encode no audited ref. The org health scanner reads audit/protofire/ only, and dates an audit from the commit anchor in the filename, so cyclo.sol published "externalAudit": "never" despite two real audits. Each PDF now sits under audit/protofire/ and carries the commit of this repo the report states it reviewed: - Protofire v1.0 (November 2024, through Report Update 3) reviewed 2ee2b15. - Protofire December 2025 reviewed 63d1155. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
🤖 ai:vetter |
|
🤖 ai:producer |
This repo carries two real Protofire audit reports, and the org health
scanner counts neither of them.
health.json(generated2026-07-25T18:16:00Z)currently publishes:
{ "name": "cyclo.sol", "org": "cyclofinance", "hasProtofireAudit": false, "externalAudit": "never", "auditPdfs": [], "auditedRef": null, "anchorKind": null }so cyclo.sol is one of the 16 of 42 repos sitting in the org's external-audit
coverage gap, despite having been audited twice.
What moved
audit/Cyclo audit report dev v.1.0.pdfaudit/protofire/cyclo.sol.2ee2b15fa8daa81e6eb432822f570f363c111415.nov-2024.pdfaudit/report-cyclo-dec-2025-1.2.pdfaudit/protofire/cyclo.sol.63d11553006bf24421c033b19f6dab0ba1bc4573.dec-2025.pdfBoth files are byte-identical to what was there; only the path and name changed.
Anchor evidence
…nov-2024.pdf→2ee2b15fa8daa81e6eb432822f570f363c111415Protofire,Version: 1.0,November, 2024; thedisclaimer names Protofire. The commit that added it is
4e9755c"addprotofire audit".
audited commit
34074b93e912dce11415cb464cc0c8b4f9bd2493, and then threeupdate sections re-review later states — Update 1
6d6ea0c8ee27b07597472d60f6cb0de26e21f695, Update 28d1ad33044076e0cea75b6e25e285b8174cd590e, Update 32ee2b15fa8daa81e6eb432822f570f363c111415(all cited ashttps://github.com/cyclofinance/cyclo.sol/commit/…). The anchor is the laststate actually reviewed, Update 3. That is consistent with the file's history:
the PDF was last updated in
0546ef8"updated audit" on 2025-01-30, and2ee2b15is dated 2025-01-13.gh api repos/cyclofinance/cyclo.sol/commits/2ee2b15fa8daa81e6eb432822f570f363c111415→
2ee2b15f 2025-01-13T18:32:55Z "fix tests", andgit merge-base --is-ancestor 2ee2b15… origin/mainpasses.…dec-2025.pdf→63d11553006bf24421c033b19f6dab0ba1bc4573does not name the vendor; the logo does) over "Smart contract audit / Cyclo",
dated December 2025.
18/12/25 | cyclo | 63d11553006bf24421c033b19f6dab0ba1bc4573. Cross-checks against history: thatis the merge commit of ethgild bump #38, and it is the base the audit branch
2025-12-22-auditwas cut from.gh api repos/cyclofinance/cyclo.sol/commits/63d11553006bf24421c033b19f6dab0ba1bc4573→
63d11553 2025-11-28T11:20:43Z "Merge pull request #38 …", ancestor ofmain.Nothing was invented: every anchor is a commit the report itself names, and both
resolve in this repo. This repo has zero tags (
gh api …/tags→[]), sothe commit form is the only applicable anchor kind — there is no tag for the
tag-wins rule to prefer.
Naming mirrors the known-good example
rainlanguage/rain.solmem@audit/protofire/rain.solmem.228b35c6725877e7fbcd2432b4c692357f16f510.jan-2026.pdf:<repo>.<audited sha>.<month>-<year>.pdf, where the date token is the report'sdate rather than the anchor commit's date (same as solmem, whose
jan-2026report anchors a 2025-12-06 commit, and
rain.math.float'sfeb-2026anchoring2025-12-01).
Before / after in scanner terms
roh-scanwalksaudit/protofireat depth 2 (main.rs~1024) and deliberatelynot all of
audit/— a non-Protofire report elsewhere underaudit/must notbe counted as a Protofire audit (
protofire.rs~5-8). A PDF ataudit/*.pdfistherefore invisible, which is exactly why this repo reports
never.hasProtofireAudit: false,externalAudit: "never",auditPdfs: [],counted in the org's coverage gap.
(
anchorKind: "commit"), the newest audit by audited date — the Dec 2025 one —becomes the reference, and drift is measured
compare/63d1155…...main: 10commits, 8 files, 0 changed lines of
src/**.sol. Because the repo has notags,
classify_external_auditreturnsna(has a PDF, no tags to compare) —not
never. It leaves the coverage gap and gains a real, honest drift figure.Why a bare
git mvwould not have been enoughNeither old filename encodes an anchor:
parse_audited_tagfinds novX.Y.Z(
Cyclo audit report dev v.1.0.pdfhasv.1.0, which is notv<major>.<minor>.<patch>)and
parse_commit_candidatefinds no 7–40 hex token in either name. Both wouldclassify
Unanchoredeven sitting in the right directory.Unanchored means the audit's date falls back to the commit that last touched the
file (
main.rs~757-773,commits?path=…&per_page=1, newest first) — and a moveis a commit touching the file. A
git mvalone would have made a November 2024audit and a December 2025 audit both report as freshly audited today, with
zero drift. That is worse than invisible: it would launder stale coverage into
apparent currency. The rename is the substantive half of the fix; the directory
is only what makes it visible.
Also
README.mdgains an## Auditssection naming both reports and the commiteach one reviewed, so the anchor is discoverable without opening the PDFs.
REUSE.toml's existingaudit/**/annotation still covers the new paths —verified with
reuse lint-fileon both new files andREADME.md(exit 0).Related: rainlanguage/rainix#287 proposes the static check that would have caught
this (enforce
audit/protofire/+ an anchor that resolves).