fix: make two green gates actually check something, and close the security-gate gaps - #56
Merged
Merged
Conversation
…urity-gate gaps
**The result-artifact gate validated nothing.** The step named "Validate
bundled result artifacts against schemas/result-v1" loaded the schema and
called `Draft202012Validator.check_schema(schema)`. That checks the schema
*document* is well-formed JSON Schema; it never loaded an artifact. Required,
branch-protected, green, and proving nothing about its own name.
Running it for real (scripts/validate_result_artifacts.py, six commands
against the bundled fixtures) immediately found five disagreements between the
schema and the emitters. Two are genuine code defects, not schema pedantry:
- `changes` was the array of changes in `diff` and an integer count in
`breaking`. Same key, two types, from one tool.
- `operations` was an integer count in `validate` and `self-test`, but the
array of per-operation stats everywhere else -- and performance/engine.py
reads it back as that array (`{o["operation_key"]: o for o in
baseline["operations"]}`). Handing it a `validate` artifact would raise.
Both counts are renamed to `change_count` / `operation_count`. Nothing
consumed the integer forms; every consumer in apiverity, tests and web/ reads
the array forms, which are untouched.
The other three were the schema being wrong: `seed`, `target` and
`operation_key` are legitimately null when they do not apply -- that is the
provenance honesty this project fixed earlier -- and `rules`, `plugins`,
`changelog` and `self-test` emit artifacts but were missing from the command
enum.
**Pinned actions lied about their versions.** Five `uses:` lines pinned
actions/setup-python@5fda3b95a4ea and annotated it `# v5.6.0`. That SHA is
v7.0.0 -- two majors newer -- and devrepro-doctor and local-ai-hardware-bench
pin the identical SHA while correctly calling it v7.0.0.
scripts/check_action_pins.py resolves every pinned SHA against the GitHub API
and fails on a comment that disagrees, or on any action not pinned at all.
**Security gates.** This repository ran pip-audit and nothing on the npm side,
so half its dependency surface went unexamined under a green "Dependency scan".
Its only secret check was a local pre-commit hook that `--no-verify` skips and
CI never ran. CodeQL now uses `security-extended`, matching
local-ai-hardware-bench.
**The secret scanner needed its own test more than anything else here.**
Planting a real-shaped secret of every class it claims to detect found that it
had no Slack, Google, Stripe or npm rule at all -- four classes silently
unchecked -- and that my first placeholder heuristic hid a real-shaped npm
token because it ended in `0123456789`.
I reached for Shannon entropy first. Measuring it showed the fixture
`sk-abcdefghijklmnop1234` scores 4.44, *higher* than a real GitHub PAT at
4.14, because a sequential alphabet maximises character diversity. Entropy was
the wrong instrument and the measurement is what said so; the replacement
requires an ascending run to dominate the value rather than merely appear in
it.
GitHub's push protection then rejected the first version of the test file,
reading the Slack fixture as a live token. That is correct on its side and
useful evidence on ours -- the fixtures are realistic enough for a real
scanner to bite. It offered an "allow this secret" URL; taking it would teach
this repository to wave detections away. The fixtures are assembled from
fragments at runtime instead, so the test still exercises fully-formed values
while no complete credential-shaped literal exists in the tree for anyone's
scanner to trip over. That also shrank the explicit-exemption count from
twelve lines to one.
Verified: ruff, ruff format, mypy (90 files), 428 tests pass, coverage 81.12%
against the 72% floor, and all six repeatable gates clean (e2e, rule catalog,
README capture, result artifacts, secret scan, action pins).
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
API Verity — contract reviewOne comment per PR — updated on each push. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The result-artifact gate validated nothing
The step named "Validate bundled result artifacts against schemas/result-v1" loaded the schema and called
Draft202012Validator.check_schema(schema). That checks the schema document is well-formed JSON Schema — it never loaded an artifact. Required, branch-protected, green, and proving nothing about its own name.Running it for real found five disagreements between the schema and the emitters. Two are genuine code defects:
diff/ baselinebreaking/validatechangesoperationsperformance/engine.pyreads it back as that array — avalidateartifact would raiseBoth counts are renamed to
change_count/operation_count. Nothing consumed the integer forms; every consumer inapiverity,testsandweb/reads the array forms, untouched.The other three were the schema being wrong:
seed,targetandoperation_keyare legitimately null when they don't apply — that's the provenance honesty this project fixed earlier — andrules,plugins,changelogandself-testemit artifacts but were absent from the command enum.Pinned actions lied about their versions
Five
uses:lines pinnedactions/setup-python@5fda3b95a4eaand annotated it# v5.6.0. That SHA is v7.0.0 — two majors newer — anddevrepro-doctorandlocal-ai-hardware-benchpin the identical SHA while correctly calling it v7.0.0. The pin is the control; the comment is what a reviewer reads.scripts/check_action_pins.pyresolves every pinned SHA against the GitHub API and fails on a comment that disagrees, or on any action not pinned at all. It verifies 30 pins here.Security gates
pip-auditran and nothing on the npm side, so half the dependency surface went unexamined under a green "Dependency scan". The only secret check was a local pre-commit hook that--no-verifyskips and CI never ran.npm audit --audit-level=high— hard gatescripts/secret_scan.pyin CIsecurity-extended, matchinglocal-ai-hardware-benchThe secret scanner needed a test more than anything else here
Planting a real-shaped secret of every class it claims to detect found it had no Slack, Google, Stripe or npm rule at all — four classes silently unchecked.
Two things worth recording:
sk-abcdefghijklmnop1234scores 4.44 — higher than a real GitHub PAT at 4.14, because a sequential alphabet maximises character diversity. Entropy was the wrong instrument and the measurement said so. The replacement requires an ascending run to dominate the value, not merely appear in it (the first version hid a real-shaped npm token ending in0123456789).Verification
ruff check/ruff format --checkmypypyteste2e·rule catalog --check·README capture --checkvalidate_result_artifacts.pysecret_scan.pycheck_action_pins.py