Skip to content

ci: check fixture identifiers by allowlist instead of denylist - #1

Merged
boot-coco merged 3 commits into
mainfrom
fix/identifier-allowlist
Aug 4, 2026
Merged

ci: check fixture identifiers by allowlist instead of denylist#1
boot-coco merged 3 commits into
mainfrom
fix/identifier-allowlist

Conversation

@owen0x6f

@owen0x6f owen0x6f commented Aug 4, 2026

Copy link
Copy Markdown

The identifier guard added in the initial commit grepped for known-bad strings — which meant the workflow file had to spell out the customer and internal identifiers it was guarding against, publishing them in a public repo in order to prevent them being published. A fresh-clone scan of the new repo found exactly four hits, all of them on that one grep line.

Replaced with scripts/check-fixture-identifiers.mjs, which asserts that tenant_id / agent_id / kid values match neutral patterns. An allowlist cannot leak what it forbids, and it catches identifiers nobody thought to enumerate — a denylist only ever catches the names someone remembered to add.

Coverage note: it inspects both JSON fields and HTTP header values (X-Openmax-Tenant, X-Openmax-Agent) plus the keyid inside Signature-Input. A field-only first version passed while a real agent name sat planted in the header set, so the header path is there because a must-fire control caught its absence.

It also fails loudly when no fixture files or no matching fields are found, so it cannot pass vacuously if fixtures move or get emptied.

Must-fire controls, all four now caught, clean tree passes:

planted result
tenant_id -> customer name (vectors.json) caught
X-Openmax-Agent -> real agent name caught
keyid inside Signature-Input -> real kid caught
X-Openmax-Tenant -> customer name caught
clean tree passes

One of those controls initially read as "not caught" and was itself broken — the plant was applied with a plain string replace against JSON-escaped quotes, so nothing actually changed and the check was correctly reporting a clean file. Re-run JSON-aware, it is caught. Worth stating because "the mutation didn't fire" and "the mutation never applied" look identical in a log.

npm test 103/103 locally.

The previous check grepped for known-bad strings, which meant the workflow file
itself had to spell out the customer and internal identifiers it was guarding
against — publishing them in a public repo to prevent them being published.

Replaces it with scripts/check-fixture-identifiers.mjs, which asserts that
tenant/agent/kid values match neutral patterns. An allowlist cannot leak what it
forbids, and it also catches identifiers nobody thought to enumerate.

Inspects both JSON fields and HTTP header values, plus the keyid inside
Signature-Input; a field-only version missed a name planted in the header set.
Fails loudly if no fixtures or no matching fields are found, so it cannot pass
vacuously.
Comment thread scripts/check-fixture-identifiers.mjs Fixed
mikezylos added 2 commits August 4, 2026 19:13
The gitleaks GitHub Action requires a paid licence for organisation repositories
and failed in 4s with 'License key is required', so the job reported failure
without scanning anything. The CLI it wraps has no such requirement.

Scans the working tree and git history separately: 'gitleaks detect' only walks
commit history, so a secret present in the tree but not yet committed passes it
silently -- verified by planting a token that the working-tree scan catches and
the history scan does not.
CodeQL flagged the kid regex as high severity: with '-' present in both the group
body and its separator class, an input like 'agent-' + '--' * n can be partitioned
ambiguously and the match backtracks exponentially. Reproduced locally -- a 50
character input did not finish within 8 seconds.

Rewritten as a single character class, so there is one quantifier and no ambiguity.
A 50,000 character adversarial input now matches in under a millisecond. All real
kid shapes are still accepted, including the dotted/underscored variant that pins
kid quoting, and real identifiers are still rejected.

@boot-coco boot-coco left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Boot (审 sha 24b4263)

Verdict: APPROVE

scripts/check-fixture-identifiers.mjs

Whitelist approach: correct. Blacklist would name the forbidden identifiers in the workflow file (self-defeating). Whitelist catches unexpected identifiers including ones never listed.

Coverage: complete. 5 field rules cover:

  • JSON fields: tenant_id, agent_id, kid
  • HTTP header values: X-Openmax-Tenant, X-Openmax-Agent
  • Signature-Input keyid extracted via /keyid="([^"]+)"/g

Anti-vacuous protection: two layers.

  1. No fixture files in testdata/ → exit 1 ("check would pass vacuously")
  2. Per-field existence check — every FIELD_RULES entry must have at least one value seen across all fixtures, else exit 1 ("not actually inspecting anything")

Seed control verification (3/3 independently replicated):

  • tenant_id: "ajj" → caught ✓
  • X-Openmax-Agent: "finops-core" → caught ✓
  • Signature-Input keyid="finops-core.prod_2026a-v2" → caught ✓
  • Clean tree → passes ✓

ReDoS Fix

KID_OK = /^agent-[a-z0-9._-]+$/ — single character class, one quantifier, no nested groups. Verified: 50,000-char adversarial input (agent- + --×25000) completes in 0.1ms. No backtracking possible.

The original ([._-][a-z0-9-]+)* had - in both the group body and separator class → ambiguous partitioning → exponential backtracking. Fix is correct.

.github/workflows/ci.yml Secret Scan

  • gitleaks dir . (work tree) + gitleaks git . (history) — two separate steps, correct. detect alone only scans history.
  • CLI pinned to 8.28.0 (no paid Action license dependency).
  • --redact flag prevents leaked values from appearing in CI logs.

Overall CI Pipeline

6 jobs: Unit tests / Lint / Golden vector integrity / Fixture identifier guard / SAST (CodeQL) / Secret scan. All appropriate for a public repo handling signing material.

No issues found.

@boot-coco
boot-coco merged commit 911c11d into main Aug 4, 2026
6 checks passed
@boot-coco
boot-coco deleted the fix/identifier-allowlist branch August 4, 2026 11:23
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.

3 participants