Skip to content

Remove the inherited Protofire audit PDFs: rain.factory.deploy is not audited - #1

Merged
thedavidmeister merged 2 commits into
mainfrom
2026-07-25-remove-inherited-protofire-audit
Jul 25, 2026
Merged

Remove the inherited Protofire audit PDFs: rain.factory.deploy is not audited#1
thedavidmeister merged 2 commits into
mainfrom
2026-07-25-remove-inherited-protofire-audit

Conversation

@thedavidmeister

Copy link
Copy Markdown
Contributor

rain.factory.deploy has never been externally audited. It has been publishing
someone else's audit record as its own since it was created yesterday.

What is removed

Two Protofire PDFs, carried across verbatim by the genesis split
(598906a — "genesis: deploy half split out of rain.factory
(rain.factory#46)"), which is the only commit that has ever touched audit/
in this repo:

file size
audit/protofire/rain.factory.1a92a86.feb-2026.pdf 1,760,851 B
audit/protofire/rain.factory.v0.1.1-r2.0.may-2026.pdf 1,761,685 B

Nothing else lived under audit/, so audit/protofire/ and audit/ go with
them.

Why: both PDFs are audits of a different repo, at refs that do not exist here

The filenames say rain.factory, and the anchors they encode resolve in
rain.factory but not here:

anchor in rain.factory.deploy in rain.factory
commit 1a92a86 git cat-file -tnot a valid object name; GET /repos/rainlanguage/rain.factory.deploy/commits/1a92a86…HTTP 422 "No commit found for SHA" resolves → 1a92a8688249aa5a8f4e82d5ed584604515f1ea0, 2026-02-10, "Merge pull request #25 from rainlanguage/2026-02-05-audit"
tag v0.1.1 absent from git ls-remote --tags (the only tag in this repo is sol-v0.1.6); GET …/git/ref/tags/v0.1.1HTTP 404 resolves → 08fecb985efbc811cde85c73f18e2e658884e5b6

rain.factory still carries both files on main at byte-identical blobs
(84d57a5d…, 6829af27…), so nothing is lost — the audit record stays with
the repo it audits.

Before / after, in rain-org-health scanner terms

Live protofireAudits entry for this repo (from
https://rainlanguage.github.io/rain-org-health/health.json, generatedAt
2026-07-25T18:16:00Z):

{
  "name": "rain.factory.deploy",
  "hasProtofireAudit": true,
  "externalAudit": "stale",
  "auditedRef": "v0.1.1",
  "anchorKind": "tag",
  "auditedDate": "2026-07-24T08:42:11Z",
  "isStale": true,
  "sourceLocChangedSinceAudit": null,
  "filesChangedSinceAudit": null,
  "commitsSinceAudit": null,
  "codeLocAddedSinceAudit": null,
  "driftFullyClassified": false,
  "compareUrl": "https://github.com/rainlanguage/rain.factory.deploy/compare/v0.1.1...main",
  "daysSinceAudit": 1
}

Every one of those numbers is wrong for this repo:

  • daysSinceAudit: 1 — the freshest-looking audit in the org. It is not an
    audit date at all: auditedDate is 2026-07-24T08:42:11Z, the genesis
    commit. The tag anchor did not resolve, so the scanner fell back to the
    commit that added the PDF. The underlying audit is Protofire's May 2026
    review of rain.factory.
  • compareUrl 404s. …/rain.factory.deploy/compare/v0.1.1...main → HTTP
    404 (the same URL shape against rain.factory → HTTP 200). The one link that
    would let a reader check the drift is dead.
  • All drift fields null, driftFullyClassified: false. This is the only
    audited-looking repo in the org whose drift is entirely unmeasurable — and
    nothing on the panel says so.

After this PR the repo has no audit/protofire/, hasProtofireAudit goes
false, and it reports honestly as never externally audited.

Note the removal cannot affect consumers: .soldeerignore already excludes
/audit, so the published rain-factory-deploy Soldeer package never contained
these PDFs. The false claim was only ever on the repo and the dashboard.

Why it failed silently

classify_anchor in
plugins/rain-org-health-check/roh-scan/src/protofire.rs (rain-org-health)
early-returns a tag anchor without ever calling the resolver it is handed:

pub fn classify_anchor<F: FnOnce(&str) -> bool>(filename: &str, resolve: F) -> AuditAnchor {
    if let Some(tag) = parse_audited_tag(filename) {
        return AuditAnchor::Tag(tag);   // <- never checks the tag exists
    }
    if let Some(sha) = parse_commit_candidate(filename) {
        if resolve(&sha) {              // commit anchors ARE resolution-checked
            return AuditAnchor::Commit(sha);
        }
    }
    AuditAnchor::Unanchored
}

A hex commit anchor that does not resolve degrades to Unanchored; a vX.Y.Z
tag anchor is trusted unconditionally. That asymmetry is why an audit PDF for a
different repo landed here and the dashboard reported it as fresh. Tracked in
rainlanguage/rainix#287 ("Static check: enforce the Protofire audit-record
convention (audit/protofire/ + an anchor that resolves)"). This PR fixes the
record; #287 fixes the detector.

Inheritance sweep

Everything else the genesis split carried across that makes a claim untrue of
this repo.

Fixed here (CLAUDE.md, second commit) — plainly false:

  • The Architecture section documented src/interface/ICloneableV2.sol,
    src/interface/ICloneableFactoryV2.sol,
    src/interface/ICloneableFactoryV3.sol and src/interface/deprecated/. There
    is no src/interface/ in this repo — src/ is concrete/, generated/,
    lib/. The interfaces stayed in rain.factory and arrive here as the
    rain-factory Soldeer dependency. Replaced with a pointer to where they
    actually are, plus the entries that were missing (src/generated/<tag>/,
    script/BuildPointers.sol, script/Deploy.sol).
  • "the interfaces use ^0.8.18" — no file in this repo uses ^0.8.18. Library
    and generated files float ^0.8.25; concrete, scripts and tests pin
    =0.8.25.
  • The Soldeer dependency list omitted rain-factory, which foundry.toml
    declares.

Checked, clean:

  • README.md makes no audit claim, has no audit link and no badge. It already
    describes the split correctly.
  • No CHANGELOG, no SECURITY.md, no badges anywhere in the repo.
  • No stale references to rain.factory's tags. src/generated/0_1_3|0_1_4|0_1_5
    are this repo's own frozen deploy pins (real on-chain addresses/codehashes,
    exercised by LibCloneFactoryDeployTaggedConstants.t.sol), not inherited
    claims.

Deliberately left alone:

  • REUSE.toml's "audit/**/" annotation, .soldeerignore's /audit, and
    .coderabbitai.yaml's !audit/**. These are the org audit-record
    convention, not a claim that an audit exists — and they stay correct for the
    day this repo is audited. reuse lint passes clean with the annotation
    matching nothing (verified: 28/28 files, "compliant with version 3.3 of the
    REUSE Specification").

Proposal, not done here: an honest README line

Recommend adding it. Not included in this diff — it is an editorial call for
the owner, and this PR is a factual correction.

Suggested wording under a short ## Audit heading:

This repo has not been externally audited. Its dependency
rain.factory has a Protofire
audit; that audit covers the ICloneable* interfaces in that repo and does
not extend to the CloneFactory implementation or the deploy pins here.

Reasoning for: removing the PDFs makes the dashboard correct, but a reader
arriving at the repo sees only an absence, and absence is ambiguous — "not
audited yet" and "audit lives elsewhere" look identical. This repo is unusually
exposed to the confusion because its own README points at rain.factory as the
other half, and rain.factory is audited; the natural inference is that the
audit covers both halves. It does not: the audited artefact is the interface
set, and the concrete CloneFactory plus the address/codehash pins are exactly
what an integrator would most want audited. One line closes that gap at
essentially zero maintenance cost, and it is the same claim the dashboard will
now make, so the two cannot drift.

Reasoning against (weaker): most Rain repos are unaudited and none of them
carry such a line, so this is inconsistent with the org norm and could read as
implying the other repos have been audited. If the owner finds that
persuasive, the alternative is to leave the README silent and let the dashboard
be the single source of truth on audit status.

Verification

nix develop github:rainlanguage/rainix/53e96a7d0a97d7c7c75c3b2412521324776fdac6#sol-shell -c bash -c 'forge soldeer install && forge build && forge test'

  • Build: 48 files compiled with Solc 0.8.25, clean.
  • Tests: 15/15 non-fork tests pass. The 5 LibCloneFactoryDeployProd.t.sol
    fork tests fail locally only on vm.createSelectFork: environment variable ARBITRUM_RPC_URL / BASE_RPC_URL / BASE_SEPOLIA_RPC_URL / FLARE_RPC_URL / POLYGON_RPC_URL not found — no RPC secrets in the local shell. CI has them.
  • forge fmt --check: clean.
  • reuse lint (what rainix-sol-legal runs): clean.
  • The repo's generated pre-commit hooks ran on both commits; denofmt rewrapped
    one new CLAUDE.md line to 80 cols and that is included.

No Solidity was touched. The only code-adjacent change is markdown.

The genesis split carried rain.factory's two Protofire PDFs across verbatim.
Both are audits of rain.factory, anchored at refs that do not exist here:
commit 1a92a86 is not an object in this repo, and there is no v0.1.1 tag (the
only tag is sol-v0.1.6). rain.factory.deploy has never been externally audited,
so it cannot present another repo's audit record as its own.

rain.factory retains both files at byte-identical blobs, so nothing is lost.

REUSE.toml keeps its audit/** annotation and .soldeerignore keeps /audit: those
are the org audit-record convention, still correct if this repo is audited.
The genesis split copied rain.factory's CLAUDE.md, whose Architecture section
documents src/interface/ICloneableV2.sol, ICloneableFactoryV2/V3.sol and
src/interface/deprecated/ — none of which exist in this repo. The interfaces
stayed in rain.factory and arrive here as the rain-factory Soldeer dependency.

Also: no file here uses ^0.8.18 (library and generated files float ^0.8.25,
everything else pins =0.8.25), and the dependency list omitted rain-factory.
@thedavidmeister thedavidmeister self-assigned this Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fbed607a-4e41-4baf-b543-873740f9309c

📥 Commits

Reviewing files that changed from the base of the PR and between 685bb2b and 3f81924.

⛔ Files ignored due to path filters (2)
  • audit/protofire/rain.factory.1a92a86.feb-2026.pdf is excluded by !**/*.pdf
  • audit/protofire/rain.factory.v0.1.1-r2.0.may-2026.pdf is excluded by !**/*.pdf
📒 Files selected for processing (1)
  • CLAUDE.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-07-25-remove-inherited-protofire-audit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

CI note: rainix-sol / test is red on one test, testProdDeployArbitrum, and it is an RPC provider outage rather than anything in this diff:

[FAIL: vm.createSelectFork: could not instantiate forked environment with provider
lb.drpc.live; server returned an error response: error code -32001: You've reached
the usage limit for your current plan ...] testProdDeployArbitrum()

19/20 tests pass; static and legal are both green. ARBITRUM_RPC_URL is pointed at drpc and that plan has hit its usage limit — the same class of failure as the Retrigger CI (post drpc swap) commit on main yesterday. This PR touches no Solidity at all (two PDF deletions plus CLAUDE.md), so it cannot influence a fork test. Needs an RPC swap on the org secret, not a retry.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

Reviewed 3f81924: approve

Removes two Protofire PDFs that arrived in the genesis split and belong to rain.factory, not to this repo — which has never been audited. Premise verified rather than assumed: commit 1a92a86 returns HTTP 422 'No commit found for SHA' and tag v0.1.1 returns 404 in THIS repo, while both resolve in rain.factory, which retains byte-identical blobs — so nothing is lost. The live health.json confirmed the wrong output first-hand: daysSinceAudit 1, auditedDate set to the genesis commit rather than an audit date, every drift field null, and a compareUrl that 404s. Root cause is classify_anchor returning AuditAnchor::Tag without ever calling the resolver (roh-scan protofire.rs:179-189), tracked in rainix#287. After this, the repo correctly reports never-externally-audited.

The inheritance sweep also caught CLAUDE.md copied wholesale from rain.factory: it documented ICloneableV2/ICloneableFactoryV2/ICloneableFactoryV3 and src/interface/deprecated/, none of which exist here (they stayed upstream and arrive as the rain-factory soldeer dep), plus a pragma claim matching no file here. Fixed. Correctly left alone: REUSE.toml/soldeerignore/coderabbitai audit globs are org convention, not audit claims, and stay correct for the day this repo IS audited.

Red check verified and NOT caused by this diff: rainix-sol/test fails only on testProdDeployArbitrum with 'vm.createSelectFork ... lb.drpc.live ... error code -32001: You've reached the usage limit for your current plan' — an RPC provider quota error, 19/20 passing, on a diff that touches zero Solidity. Same drpc exhaustion hitting rain.extrospection today. Not blind-retried; needs a human RPC swap on the org secret. static + legal green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant