Skip to content

Add audit-freeze CI gate and ENGAGEMENT.md template (#158) - #183

Merged
truthixify merged 5 commits into
wraith-protocol:developfrom
Jerryvic911:issue-158-audit-freeze
Aug 31, 2026
Merged

Add audit-freeze CI gate and ENGAGEMENT.md template (#158)#183
truthixify merged 5 commits into
wraith-protocol:developfrom
Jerryvic911:issue-158-audit-freeze

Conversation

@Jerryvic911

@Jerryvic911 Jerryvic911 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Closes (partially) #158
Closes #158

Scope note

Per the maintainer's scoping comment on #158, this PR covers only the
contributor-facing subset of the issue:

  • .github/workflows/audit-freeze.yml
  • audit-prep/ENGAGEMENT.md as a template (placeholders, not a signed SOW)
  • A demonstration that the gate fires (separate throwaway PR, link below)

audit-prep/README.md, audit-prep/AUDIT_FIRMS.md, and
stellar/MAINNET_READINESS.md are intentionally untouched — firm
selection, the signed SOW, and the real coordinator/technical-contact
names are the maintainer's to fill in, and no row in
MAINNET_READINESS.md should flip until a real engagement is signed.

Security design (maintainer asked to pick one approach and say which)

Two independent layers, not just one:

  1. Primary: the workflow checks out the PR's base ref
    (github.event.pull_request.base.sha), not the default PR-merge ref —
    so the gate script itself (scripts/audit-freeze/*.ts) cannot be
    modified by the PR it's judging. check.ts separately fetches
    ENGAGEMENT.md's content from that same base SHA via the GitHub
    Contents API, so a PR's edits to that file are simply invisible to the
    check.
  2. Secondary (defense in depth): ENGAGEMENT.md is always treated as
    a frozen path in its own right whenever a freeze is active, regardless
    of what freeze_paths lists — so even if (1) ever regressed, editing
    the file still requires the audit-approved label.

Full writeup in scripts/audit-freeze/README.md.

Testing

26 tests passing:

  • Unit tests for the front-matter parser, glob matcher, and decision logic
    (parse.test.ts, glob.test.ts, decide.test.ts) — no network.
  • A subprocess end-to-end suite (check.e2e.test.ts) that runs the real
    check.ts CLI against a local mock GitHub API server, covering: a
    blocked PR, the audit-approved label override, no active freeze, a
    missing ENGAGEMENT.md at the base ref, and the self-protection case.
cd scripts/audit-freeze
npm install
npm test

Demonstration that the gate fires


Update: fixes found via live demonstration

While putting together the required demonstration that the gate fires
(see below), two real bugs surfaced that only a live PR run — not local
mock tests — could catch:

  1. sparse-checkout in non-cone mode silently dropped
    scripts/audit-freeze/
    , causing ERR_MODULE_NOT_FOUND at runtime.
    Fixed by dropping sparse-checkout entirely in favor of a plain full
    checkout at the base ref (sparse-checkout was only ever a minor
    optimization, not load-bearing).
  2. The gate crashed instead of passing cleanly on the very first PR
    that introduces the audit-freeze system itself
    — since the base-ref
    checkout (by design) finds nothing at scripts/audit-freeze/check.ts
    on develop, because it doesn't exist there yet. Fixed by having the
    workflow check whether check.ts exists on the checked-out base ref
    first, and pass with an explanatory message if not. This isn't a
    security gap: if the system doesn't exist on base, there's nothing to
    enforce or bypass.

Both fixes are now included in this PR and verified against a real PR
run (see the demonstration below).

Demonstration that the gate fires

Jerryvic911#1

That PR (base: this branch, issue-158-audit-freeze) temporarily
activated the freeze and touched stellar/stealth-announcer/README.md
(an in-scope frozen path):

  • Without the audit-approved label: Audit Freeze Gate failed, as
    expected.
  • After adding the audit-approved label: the same check passed,
    confirming the override path works.

The freeze activation was reverted afterward (see the revert: commit)
audit-prep/ENGAGEMENT.md is back to the inactive "TBD" placeholder
on this branch.

…#158)

Scoped subset per maintainer's comment on wraith-protocol#158: the workflow, the
ENGAGEMENT.md template, and (separately, via a throwaway PR) a
demonstration that the gate fires. Firm selection, the signed SOW,
and README.md/AUDIT_FIRMS.md/MAINNET_READINESS.md remain untouched,
as those are explicitly the maintainer's to fill in.

- .github/workflows/audit-freeze.yml: runs on every PR, checks out
  the PR's base ref (not the default merge ref) so the gate script
  itself cannot be modified by the PR it is judging.
- scripts/audit-freeze/{parse,glob,decide,check}.ts: dependency-free
  front-matter parser, glob matcher, pass/fail decision logic, and a
  CLI that fetches PR metadata, changed files, and ENGAGEMENT.md's
  content (from the base SHA) via the GitHub REST API.
- audit-prep/ENGAGEMENT.md: template with the front-matter shape and
  section structure the gate expects, freeze_until defaulted to the
  literal "TBD" placeholder (inactive) until a real SOW is signed.

Security design (two independent layers, per the maintainer's ask to
choose one and say which): (1) primary -- the workflow checks out the
PR's base ref, and check.ts separately fetches ENGAGEMENT.md's content
from that same base SHA via the API, so a PR cannot alter the freeze
parameters it is judged against; (2) secondary -- ENGAGEMENT.md is
always treated as a frozen path in its own right whenever a freeze is
active, regardless of freeze_paths contents. Full writeup in
scripts/audit-freeze/README.md.

Tests: 26 passing -- unit tests for parse/glob/decide (no network),
plus a subprocess end-to-end suite that runs check.ts against a local
mock GitHub API server, covering blocked/approved-label/no-freeze/
missing-file/self-protection cases.
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@Jerryvic911 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Jerryvic911 added 2 commits August 30, 2026 14:34
Sparse-checkout in non-cone mode did not reliably include the full
scripts/audit-freeze directory contents, causing check.ts to be
missing at runtime (ERR_MODULE_NOT_FOUND) on a real PR run. A full
checkout is simpler and removes this failure mode; sparse-checkout
was only ever a minor optimization, not load-bearing.
@Jerryvic911 Jerryvic911 reopened this Aug 30, 2026
Jerryvic911 added 2 commits August 30, 2026 14:53
The freeze was temporarily activated to demonstrate the audit-freeze
gate firing on a real PR (see linked demo PR in wraith-protocol#158). Restoring the
inactive TBD placeholder now that the demonstration is complete.
The base-ref checkout is correct and intentional (see security note),
but means the very first PR that introduces scripts/audit-freeze/
will find nothing there, since the system did not exist at that
point in history. That is not a security gap -- if the system does
not exist on base, there is nothing to enforce or bypass -- but the
workflow crashed instead of recognizing that. Now it checks whether
check.ts exists on the checked-out base ref first, and passes
cleanly with an explanatory message if not.
@truthixify
truthixify merged commit 0cd8391 into wraith-protocol:develop Aug 31, 2026
14 checks passed
@truthixify

Copy link
Copy Markdown
Contributor

Merged @Jerryvic911, and you closed the hole I flagged rather than just noting it. Reading ENGAGEMENT.md from the base ref and treating it as an always-frozen path is belt and braces, which is right for a control whose whole job is to be un-bypassable. You also left MAINNET_READINESS.md alone as asked and kept the coordinator fields as placeholders for me. Exactly the split I described.

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.

Third-party audit engagement kick-off + in-audit change-freeze CI

2 participants