fix: close nine contracts that could only check what they were told - #146
Merged
Merged
Conversation
…ng a registry A closed allowlist can only check what someone remembered to list, so .claude/CLAUDE.md — the only auto-loaded file here — carried a command that aborts under the launcher while the gate stayed green. Discovery now scans the tree for documents launching a real scripts/ subject, requires registration or a written exemption, and rejects stale exemptions. Foreign tools stay out of scope. Proven both ways: a planted unregistered document fails, a foreign-tool document passes. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
validate_catalog.py only ever asserted the schema file existed, so the schema drifted from the tree in both directions: it forbade runtime_requirements, which two capabilities declare, and it declared last_verified a pattern-checked string while seven entries parsed as datetime.date. The schema now covers both runtime fields, the dates are quoted, and a dependency-free _json_schema.py executes the schema against the catalog. The duplicated Python enums and key lists are removed, so shape has one source. Proven to reject an unquoted date, an unexpected property, a bad enum and an empty sources list. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
enforcement was checked against an enum accepting 'disabled', so the default-branch ruleset could be switched off with this gate still green. Tag validation was a single existence boolean while the adoption skill promises immutable tags. Branch and tag rulesets must now be active; a weaker one records a reason here. The tag rule set and the bypass-actor set are both pinned. Proven to reject a disabled branch ruleset, a removed 'update' rule, an added bypass actor, and a stale exemption. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
Four documented zizmor invocations, three wrong in three different ways: AGENTS.md and the nddev-repo-flow skill named --persona regular while ci.yml passes pedantic; CONTRIBUTING.md's comment contradicted its own command, ran an unpinned zizmor off PATH, and omitted GH_TOKEN from both invocations - the omission AGENTS.md documents as how three ref-version-mismatch findings reached the default branch. check_documented_commands.py now derives version, severity and persona from the workflow inputs and from what ci.yml passes. Proven to catch a reverted persona and a workflow pin bumped without the docs. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
…ner lane The binary lane was exhaustively allowlisted while the container lane - the default - validated nothing: the guard returned before it looked and gitleaks_image was not even in the step env, so any caller string reached docker run in a workflow that reads every secret in the tree. The step summary claimed a digest-pinned caller contract that nothing checked. The guard now requires an @sha256: digest and rejects tag-only, latest, empty, short and uppercase-digest images, with six executable cases. The lone unclosed file handle in the repository is closed. Re-proof of the runtime record follows in this branch. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
release.yml only ever checked the forward direction, so a heading claiming 0.11.0 shipped on 2026-07-20 sat between 0.10.0 and 0.11.1 for a month describing a release that was never tagged. Structure - grammar, uniqueness, descending versions, non-increasing dates, agreement with VERSION - blocks in core. Tag reconciliation is advisory, because whether a tag exists is a property of the refs, not of the change. 0.8.1 and 0.6.0 are corrected to their real tag dates; 0.11.0 is recorded as known debt. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
AGENTS.md claimed 46 reusables and nine self workflows against 47 and 10, said the estate calls twenty-seven reusables when it calls 35 across three files, named nine cross-platform-proven reusables against a ledger recording ten, bounded the docs at docs/18 after docs/19 landed, and carried one sentence twice. The counts are removed rather than corrected - each was a copy of a fact the tree already answers, so each was a fresh chance to drift. The README also said tags are mutable while tag-semver.json blocks deletion, update and non-fast-forward, contradicting the adoption skill. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
gitleaks detect walks every ref in the clone and fetch-depth: 0 fetches every branch, so a finding on an unmerged branch failed this scan on every other branch - a required check whose result depended on refs the change never touched. Found by running it: the evidence estate went red on a branch cut from a clean main, and the finding traced to a commit that is an ancestor of neither. scan_scope defaults to ref-history; all-refs stays reachable but must be asked for, and an unknown value fails closed. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
Run 31750480571 executed both Linux X64 lanes green after the container digest guard and the scan-scope input landed. proven_digest aa65f5d9. The prior attempt on this branch is recorded in the evidence: it is what showed that a fetch-depth-0 checkout lets an unrelated ref fail the scan. Signed-off-by: Danil Silantyev <danilsilantyevwork@gmail.com>
rldyourmnd
added a commit
that referenced
this pull request
Aug 14, 2026
Applies the PR #145 checkpoint (7cbd1e8) on top of the track-M fixes merged as PR #146. Conflicts were unions: the Python execution surface carries both track-M's subjects and this branch's. This is the unverified WIP baseline; every defect it carries is fixed in the commits that follow. One fix is folded in here rather than applied after: `gitleaks` flags the sample cache identity on line 238 as `generic-api-key`, and `secret-scan.yml` scans the history of the checked-out ref, so leaving the literal in an ancestor commit would fail the scan on `main` for good. The value is a Flutter action cache key in a negative-self-test sample, not a credential, so nothing needs rotating -- but the line really did read like one, and the fix is to stop the sample looking like a secret rather than to teach the scanner to skip the file. The identities are built from parts, with the version read from `sdk-runtime-spec.yml` instead of written out three more times.
rldyourmnd
added a commit
that referenced
this pull request
Aug 14, 2026
Applies the PR #145 checkpoint (7cbd1e8) on top of the track-M fixes merged as PR #146. Conflicts were unions: the Python execution surface carries both track-M's subjects and this branch's. This is the unverified WIP baseline; every defect it carries is fixed in the commits that follow. One fix is folded in here rather than applied after: `gitleaks` flags the sample cache identity on line 238 as `generic-api-key`, and `secret-scan.yml` scans the history of the checked-out ref, so leaving the literal in an ancestor commit would fail the scan on `main` for good. The value is a Flutter action cache key in a negative-self-test sample, not a credential, so nothing needs rotating -- but the line really did read like one, and the fix is to stop the sample looking like a secret rather than to teach the scanner to skip the file. The identities are built from parts, with the version read from `sdk-runtime-spec.yml` instead of written out three more times.
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.
What this is
Nine main-line defects found by auditing
mainagainst its own contracts. Everyone was invisible to a fully green gate —
validate_allall tiers,actionlint,and
zizmorat both personas all passed before this branch.The theme is the same in most of them: a contract that could only ever check
what someone remembered to tell it.
The defects
.claude/CLAUDE.mdModuleNotFoundErrorafter #144scripts/subject; unlisted or stale-exempt failscapability.schema.yamlruntime_requirements(which two capabilities use) while sevenlast_verifiedvalues had drifted todatetime.datecheck_rulesets.pyenforcementchecked against an enum that acceptsdisabled; tag validation was one booleanactive; the tag-immutability rule set and the bypass-actor set are pinnedregularwhere CI runspedantic, an unpinned binary, and noGH_TOKENin eitherCONTRIBUTING.mdcommandci.ymlpassessecret-scan.ymlcontainer lanegitleaks_imagewas not in the step env — while printing "digest-pinned caller contract"@sha256:digest; six executable casessecret-scan.ymlscopefetch-depth: 0checkout brings in, so an unmerged branch failed the scan on every other branchall-refsmust be asked forCHANGELOG.md## [0.11.0]described a release that was never tagged; two headings predated their own tagscore, tag reconciliation is advisoryREADMEclaiming tags are mutableEvidence
Every new rule is proven to reject, not just to pass:
sourcesupdaterule, an added bypass actor, a stale exemptionVERSIONwith no headinglatest/ empty / short / uppercase-digest images and unknown scopesRuntime:
secret-scan.ymlre-proved on run 31750480571 — both Linux X64 lanes green,proven_digest aa65f5d9.The scope defect was found by running it: the first attempt on this branch went
red on a finding in a commit that is an ancestor of neither this branch nor
main. That failure is recorded in the ledger evidence rather than hidden.Permissions and threat model
No permission changes. Two trust boundaries tighten:
secret-scan.ymlno longer passes an unvalidated caller string todocker runin a workflow that reads every secret in the tree.
what a required check is supposed to guarantee.
scan_scopeis a behaviour change: a consumer relying on the implicitall-branch sweep must now pass
scan_scope: all-refs. Recorded in the changelog.Out of scope, filed instead
.gds/repository.yaml's stale verification command and the 49-commit-behindsubmodule pointer → NDDev-it-com/github-device-sync#176 (control-plane owned)