Skip to content

Bug-hunt round 7: guard quoting, redaction case-fold, site-generator and scaffold fixes - #439

Merged
REPPL merged 10 commits into
mainfrom
bughunt-b/round-7
Aug 23, 2026
Merged

Bug-hunt round 7: guard quoting, redaction case-fold, site-generator and scaffold fixes#439
REPPL merged 10 commits into
mainfrom
bughunt-b/round-7

Conversation

@REPPL

@REPPL REPPL commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Autonomous all-dimensions bug-hunt, round 7. Five parallel hunt dimensions (code, docs-vs-functionality, infrastructure, internal-record consistency, hardened-primitive sibling sweep), every candidate adversarially refuted before fixing, every behaviour change pinned by a test watched fail before the change and pass after. Baseline (make preflight + gofmt -l .) green before any change and on the final tree.

Fixed — substantive (11)

Security / code

  • Guard ANSI-C / locale quoting bypassinternal/core/guard/tokenize.go. The tokenizer implemented single/double/backslash quoting but not $'...'/$"...", so $'--force' tokenised to $--force and a Tier-1 blocker missed while bash handed the child byte-identical argv — contradicting the doc.go invariant that quoting affects tokenisation, not argument semantics. ANSI-C escapes are decoded so $'\x2d\x2dforce' resolves too. (iss-2608221456463223)
  • local_username redaction case-fold missinternal/adapter/scanner/identity.go:165. The hard-fail matcher for the caller's own login lacked the (?i) its home-path sibling carries, so a case variant of the login survived redaction and the blocking residual scan into the stored transcript. The system-dir exemption is lower-cased so iss-31 stays closed. (iss-2608221456469938)
  • Site build vs check disagreement on inlined SVGsinternal/core/site/assets.go. An XML prolog/comment/CDATA was inlined verbatim but the emitted-page reader refuses all three, so a normal exporter SVG made the build pass and the check refuse a page whose message named no asset. (iss-2608221456462677)
  • Site gate masking on an unparsed pageinternal/core/site/check.go:411. A page that failed to parse dropped out of the page-walking gates, which then printed ok for a page they never examined. (iss-2608221456469558)
  • Unscreened repository href schemeinternal/core/site/build.go LoadRepoMeta. .claude-plugin/plugin.json's repository reached an href on every page with no executableScheme check; a javascript: address (or scheme-less typo) passed every gate. (iss-2608221456466438)
  • Scaffold symlink path leak + ./internal/... race leginternal/core/launch/scaffold/scaffold.go, templates/release.yml.tmpl. A symlinked target leaf (ELOOP, not ErrNotRegular) leaked an absolute path into the --dry-run --json; and the hardcoded go test -race ./internal/... wedged every release of a bare adopter with no internal/ tree. (iss-2608221456599559, iss-2608221456597173)
  • Capture skipped[].error absolute-path leakinternal/core/capture/workflow.go. Scrubbed at the same choke point as skipped[].path. (iss-2608221456599229)
  • CODEOWNERS gap over the served install script.github/CODEOWNERS. site-src/ (incl. install.sh.tmpl, the byte source of the served /install.sh) and docs/requirements.txt now require code-owner review. (iss-2608221456593173)

Docs / record

  • Writing-style escape overclaimdocs/reference/writing-style.md. The docs-lint: allow line is honoured only by the banned-token families; links_resolve/stray_root_docs/citation_* ignore it. Also added the shipped names/* row. (iss-2608221456593814)
  • Site-build "exactly this set" driftcommands/site.md, brief 22-site.md. The exhaustive read/write set omitted record.js, install.sh.tmpl, CONTRIBUTING.md, ACKNOWLEDGEMENTS.md, install.sh. (iss-2608221457125132)
  • Shipped abcd site check still called a design target04-surfaces/README.md, 05-internals/10-site.md, and unpinned in release-gate/manifest.json (now pinned, checkerCount 28). (iss-2608221457122761)

Fixed — nitpick (4)

  • Site principle-id collision now refused loudly rather than silently overwriting a typed record in record.json; the history walk sets core.quotePath=false so a non-ASCII record path keeps its dates (iss-2608221457123924).
  • 03-invariants.md PLACEHOLDER banner over fourteen live invariants → LIVE; brief/README.md evidence-chapter "placeholders" → live (iss-2608221457127152, iss-2608221457128333).
  • 00-meta.md open-questions home clause reconciled with the deliberate inline-notes design; install.md planned-Windows sentence; ahoy.md dry-run --json wording; the --no-color help string is US-English (reference regenerated).

Recorded, not fixed (stays open)

  • Guard brace-expansion bypass{--force,} expands to byte-identical argv yet the guard reads the literal token and allows it. Distinct from the $'...' gap (expansion, not quoting; breaks no written invariant); a correct bounded brace-expander is larger than this round's scope. (iss-2608221457227161)

Considered and rejected / refuted

  • The commands/site.md "runs in CI" claim for the overflow audit — in-flight PR ci: screenshot audit fails on rendered overflow at phone and desktop widths #436 adds exactly that workflow; touching the line now would invert on merge.
  • Install-surface transport-pin (--proto) and -q deltas vs hooks/bootstrap.shdowngraded to nitpick / defence-in-depth: the pin closes no reachable path (the attacker who can inject a downgrade already holds a trusted cert; GitHub never redirects to http), and the .curlrc/proxy attacker already has code execution.
  • The iss-315 guard-warn citation (the record does not disclaim the design target); the CI record-lint job name (prior art iss-304); the prepare-this-repo template path (prior art iss-87).

Model routing: orchestration on Claude Fable 5; five parallel hunters and the per-finding adversarial refuters on Claude Opus 5. The dual pre-merge review (one Opus 5, one Fable 5) and CI status will be posted as a PR comment.

Round 7 — findings: 11 substantive, 4 nitpick, plus 1 recorded-open and several refuted.

Assisted-by: Claude:claude-fable-5

REPPL added 8 commits August 22, 2026 14:57
The tokenizer implemented single, double and backslash quoting but not
bash's $'...' (ANSI-C) or $"..." (locale) forms, so the leading $ fell
through to the default word branch and prefixed the token: $'--force'
tokenised to $--force. A Tier-1 blocker naming --force (or rm -rf, or
--no-verify) then missed while bash handed the child byte-identical argv,
contradicting the doc.go invariant that quoting affects tokenisation, not
argument semantics. ANSI-C escapes are decoded so an encoded spelling
($'\x2d\x2dforce') resolves to the same bytes.

Assisted-by: Claude:claude-fable-5
The hard_fail local_username matcher was built without the (?i) its
home-path sibling carries, though HomeUser is the last segment of that same
home path. On a case-folding filesystem a case variant of the caller login
(the natural prose spelling in a transcript) then resolved to the same
account but was neither redacted nor caught by the blocking residual scan,
leaking the login into the stored transcript. The system-directory
exemption is lower-cased so the iss-31 suppression still holds under
folding, and the encoded matcher folds with EqualFold.

Assisted-by: Claude:claude-fable-5
- checkInlinableSVG refuses an XML prolog, comment and CDATA section: all
  three are inlined verbatim and the emitted-page reader refuses them, so a
  normal exporter SVG made the build pass and the check refuse a page whose
  message named no asset.
- A page that fails to parse now denies every page-walking gate a pass
  rather than dropping out of their lists and letting them print ok, which
  had masked a genuine finding behind the parse fault.
- LoadRepoMeta screens the repository address for an executable scheme like
  the bibliography URLs are, so a javascript: address (or a scheme-less
  typo) fails the build instead of shipping an href on every page.
- BuildRecordExport refuses a frontmatter-free store id that collides with a
  typed record id rather than silently overwriting it in the export.
- isolatedGit sets core.quotePath=false so the history walk reads non-ASCII
  paths verbatim, not the C-quoted form that left a record undated.

Assisted-by: Claude:claude-fable-5
Two adopter-facing scaffold defects:

- classify folded a symlinked target leaf into the path-free non-regular
  reason: ReadGuarded fails a symlink with ELOOP, not ErrNotRegular, so the
  symlink case named first in the contract fell through and embedded a raw
  absolute path in the dry-run report and its --json success envelope.
- The race leg hardcoded go test -race ./internal/... outside the .Abcd
  guard, so a bare adopter module with no internal tree failed every release
  verify run and wedged the release. The bare profile now runs the race leg
  over the whole module; the abcd rendering is unchanged.

Assisted-by: Claude:claude-fable-5
capture list/status --json emitted skipped[].error carrying a raw absolute
path beside the deliberately-relativised skipped[].path, in an exit-0
success envelope the CLI error-path scrubber never sees. relativiseLedgerPaths
now scrubs the error string at the same choke point as the path field.

Assisted-by: Claude:claude-fable-5
site-src/ (including install.sh.tmpl, the byte source of the served
/install.sh) and docs/requirements.txt (the pip input to the deployed site
build) were outside CODEOWNERS, so a PR confined to them merged with no
required code-owner review while shipping the install script to users.

Assisted-by: Claude:claude-fable-5
…icks

- The shipped abcd site check was still called a design target in
  04-surfaces/README.md and 05-internals/10-site.md; 22-site.md is now
  pinned in the release-gate manifest (checkerCount 28) so Direction A reads
  the site chapter.
- commands/site.md and brief 22-site.md named an exhaustive site-build read
  set that omitted record.js, install.sh.tmpl, CONTRIBUTING.md and
  ACKNOWLEDGEMENTS.md, and an output list missing install.sh and record.js.
- The writing-style Escapes section overclaimed the docs-lint: allow line
  (only the banned-token families honour it) and its surface table omitted
  the names/* family.
- 03-invariants.md declared PLACEHOLDER over fourteen live invariants;
  brief/README.md still called the evidence chapter placeholders;
  00-meta.md named one home for open questions while nine live inline.
- install.md dropped a planned-Windows sentence; ahoy.md's dry-run --json
  wording; the --no-color help string is US-English (reference regenerated).

Assisted-by: Claude:claude-fable-5
Ledger records for the round: fifteen findings captured and resolved with
their fixing commits, and the guard brace-expansion bypass recorded open as
a scoped follow-up. CHANGELOG and DECISIONS updated for the round.

Assisted-by: Claude:claude-fable-5
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 22, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
abcd 0778f56 Aug 23 2026, 01:08 AM

The $'...' decoder handled \x and octal but not bash's \uHHHH / \UHHHHHHHH
unicode escapes (nor \cX control), so $'\u002d\u002dforce' still decoded to
--force in the shell while the guard read the literal bytes and allowed the
Tier-1 block — the same encoded-hazard class the \x form closes, and the one
the CHANGELOG claims is covered. All three encodings now decode to the same
bytes bash produces.

Assisted-by: Claude:claude-fable-5

REPPL commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator Author

Merge gate — CI green, dual review SHIP after remediation

CI status on the final head f9a6276: all checks green — ci (build + vet + gofmt + full test + race on macOS & Linux, record-lint drift, docs-lint, gitleaks, smoke, zizmor, govulncheck, dependency-review), attribution, external-review. The earlier attribution failure was the harness's auto-appended "Generated with" footer on the PR body; it was stripped and the re-run passed.

Two independent adversarial pre-merge reviews of the full diff (one Claude Opus 5, one Claude Fable 5):

  • First pass — both NO-SHIP, on the identical single blocker. The new guard ANSI-C $'...' decoder handled \x and octal but omitted bash's \uHHHH / \UHHHHHHHH unicode escapes, so git push $'--force' decoded to --force in bash while the guard read the literal bytes and allowed the Tier-1 block — the exact encoded-spelling class the fix targets, and one the CHANGELOG claimed complete. Both reviewers reproduced the bypass end-to-end. Everything else in the 53-file diff both verified clean: scaffold self-parity byte-identical, rendered release YAML valid, the bare race leg omits ./internal/... and runs ./..., record/docs-lint green, ledger records well-formed, manifest arithmetic (28 = 23 + 5) consistent, no privacy-hygiene regression.

  • Remediation — f9a6276 adds \u/\U/\c decoding (UTF-8 encoded, utf8.ValidRune-guarded) with watched-fail tests, making the CHANGELOG completeness claim accurate.

  • Re-verification — both SHIP. Opus 5 and Fable 5 independently confirmed on the final head: every unicode-escaped spelling of --force / --no-verify / -rf now blocks (exit 1), \x and plain forms still block, and benign unicode/multi-byte echoes (echo $'AB', echo $'é', echo $'\U0001F600', echo $'\cG') still allow (exit 0) with no crash or over-block — checked against real bash including the greedy-hex edge case where an allow is the correct verdict. The sole bash divergence found (\c immediately before the closing quote) fails closed as exit 2, never an allow, within the guard's documented mistake-filter scope. Guard suite, vet, gofmt, and full make preflight green; the remediation is confined to tokenize.go/tokenize_test.go.

Auto-merge is not authorised: leaving this open for a human to merge.

Assisted-by: Claude:claude-fable-5


Generated by Claude Code

The two site brief chapters conflicted where round 7's corrections met
main's newer website-ships rewrites (#440, #432): main's text supersedes
the round's fixes in every conflicted hunk and wins each one, while the
round's inputs-table rows in the surfaces chapter (record.js,
install.sh.tmpl, the credit sources) stay — main had not updated that
table. Preflight and gofmt green on the merged tree.

Assisted-by: Claude:claude-fable-5
@REPPL
REPPL added this pull request to the merge queue Aug 23, 2026
Merged via the queue into main with commit c354114 Aug 23, 2026
13 checks passed
@REPPL
REPPL deleted the bughunt-b/round-7 branch August 23, 2026 01:17

REPPL commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator Author

Merge gate resumed — conflict cleared, CI green, dual re-review SHIP

Main moved after the first merge-gate pass (#440, #441, #432), leaving this PR conflicted in the two site brief chapters. Merge commit 0778f56 brought main in: main's newer website-ships prose won every conflicted hunk (it postdates and subsumes this round's corrections of the same passages), while the round's inputs-table rows in 22-site.md (record.js, install.sh.tmpl, the credit sources) were kept — main had not updated that table. No history rewrite.

CI on 0778f56: all 13 checks green — both check legs, record-lint, attribution, external-review, gitleaks, zizmor, govulncheck, smoke, dependency-review, screenshots, Workers build.

Two independent adversarial re-reviews of the full diff (one Claude Opus 5, one Claude Fable 5): both SHIP. Both proved the merge lossless mechanically — the two-dot and three-dot diffs against origin/main are byte-identical, so the merge base is main and nothing from either side was dropped; a git merge-tree replay confirmed exactly the two expected conflicts and no stealth edits outside them. Both re-ran the gates locally (gofmt, build, vet, full test, race, the three lint gates; one reviewer also ran a live site build + site check on the merged tree — all seven gates ok — and confirmed none of main's 32 new livery SVGs trips this round's tightened SVG screen; the other confirmed TestSelfScaffoldParity still holds across main's workflow edits).

The PR was merged by the maintainer while the re-verification ran; git diff 0778f56 c354114 is empty, so both verdicts apply unchanged to what shipped. Follow-up material noted by the reviewers (none merge-gating): the commands/site.md writes-list and 04-surfaces/README.md row 22 now sit slightly narrower than the merged 22-site.md, and the record-id collision guard does not yet cover two frontmatter-free stores sharing an id — candidates for a future round.

Assisted-by: Claude:claude-fable-5


Generated by Claude Code

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