Repository navigation
feat: check-tool-versions reads adopter-owned pins from an optional scripts/tool-pins.extra - #112
Conversation
…cripts/tool-pins.extra Adopters that pin tools the template does not ship (syft, uv, pnpm, ...) had to edit install-ci-tools.sh and check-tool-versions.sh — local changes every upstream sync must preserve — or leave the pin unwatched. The drift check now also reads an optional, adopter-owned plain-data file, one row per tool: `<tool> <version> <source>`, with github:<owner>/<repo>, npm:<pkg> or pypi:<pkg> as the source. The template ships no such file. Malformed rows and unknown sources are errors, never skips; holds work the same as for kit tools. The JSON fetch timeout goes from 30 s to 90 s: PyPI's JSON for a large project is ~5 MB and a cold fetch took 45-63 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 65529ad723
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…in the script's report, not a cancel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35bd951237
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…icated, instead of gh api `gh api` has no request timeout, so a stalled call could outlast the job before the script reported its lookup error. Every GitHub lookup now uses the same bounded curl path as the registries, with GH_TOKEN, GITHUB_TOKEN or a logged-in gh's token as a bearer header (passed on a file descriptor, not in argv), keeping the authenticated rate limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Markdown (#113) <!-- markdownlint-disable-next-line MD041 --> ## Summary `scripts/pr-lint.js` decided which issues a PR closes by re-implementing CommonMark block parsing. Nine review rounds on #96 still left it disagreeing with GitHub whenever containers nest, and three more simple cases turned up after v0.5.7. GitHub already exposes the ground truth: the pull request's `closingIssuesReferences` field, read with `excludeUserLinked: true` so it lists exactly the issues the body closes, with keywords in prose as GitHub renders them. - `run()` reads that field over GraphQL. `lint()` checks the result: exactly one issue, in this repository, the branch's, and still open. Branch grammar and the bot exemptions are unchanged. - The Markdown scanner and its tests are gone (−260 lines net). - **The field lags a body edit.** I measured this by editing a PR body and polling: 1–9 s. The lint therefore reads until two reads 5 s apart agree, at most five times. Typical cost is one extra read and a 5 s wait. - Because the lint reads live state, "Re-run jobs" now re-checks the current body. The `ci.yml` comment that said it replays the old payload is corrected. - Messages follow GitHub's semantics. A number that is a pull request, or a deleted issue, now shows up as "closes no issue", because GitHub closes nothing for it. **Checking GitHub against CommonMark.** I put the three cases deferred to this issue into an open PR's body and read the field: | Body | GitHub | CommonMark | v0.5.7 scanner | | --- | --- | --- | --- | | `Heading\n=======\n Closes #104` | not closed | not closed | closed | | `- ```\n Closes #104\n ```` | not closed | not closed | closed | | `- item\n > quote\n # heading\n\n Closes #107` | closed | closed | not closed | **Sidebar links do not count.** Adding or removing an issue link in the PR's sidebar fires no `pull_request` event, so accepting it would let a green check go stale; the lint reads only what the body closes, and AGENTS.md step 4, `skills/pr-authoring` rule 5 and the architecture ledger say so. Before the first read, the lint also waits until the triggering edit is 15 s old, so two agreeing reads cannot both be stale. **Downstream:** the kit's `pr-lint.js` and `pr-lint.test.js` change shape completely; adopters replace both files whole. The workflow step is unchanged, and so are the job permissions: `issues: read` and `pull-requests: read` were already there. ## Related issue Closes #104 ## Validation Pick validation depth by blast radius. A level that applies but could not run becomes a `RISK:` line below. See AGENTS.md for the validation ladder. - [x] L0 static — `make lint` - [x] L1 unit — `make check` (`scripts/pr-lint.test.js`, 14 pass: lint rules, settle logic with a lagging and a flapping field, `run()` with a GraphQL stub, 403 and other failures) - [x] L2 integration — the real query through `closingRefs()` against live PRs here: #111 → [105], #112 → [107], #91 → [88, CLOSED], release PR #94 → [] - [x] L3 e2e / preview — this PR's own `ci` run executes the new lint against this PR ## Risk / rollback ```text RISK: L2 not run on a private repository — GraphQL under the ci job's issues/pull-requests read scopes is expected to work as the REST read did, but is untested; the first private adopter run will show it, and a refusal fails the check with the scopes named Rollback: revert this PR; the Markdown scanner returns ``` ## Checklist Before merging: - [x] Conventional Commit PR title (`<type>: <description>`) - [x] Linked issue using "Closes #N" - [x] No secrets, no `*.local.md` files committed - [x] Documentation updated where affected --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.6.0](v0.5.8...v0.6.0) (2026-09-29) ### Features * check-tool-versions reads adopter-owned pins from an optional scripts/tool-pins.extra ([#112](#112)) ([5e37f0b](5e37f0b)) * pr-lint asks GitHub which issues a PR closes instead of parsing Markdown ([#113](#113)) ([02b4138](02b4138)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
scripts/check-tool-versions.shwatched only the five pins inscripts/install-ci-tools.sh. An adopter that pins another tool (two downstream repositories pin syft, one also uv and pnpm) had two options: edit both kit files, which creates local changes every upstream sync must preserve, or leave the pin unwatched.The check now also reads an optional, adopter-owned plain-data file,
scripts/tool-pins.extra:github:<owner>/<repo>(any non-numeric tag prefix is stripped),npm:<package>andpypi:<package>.hold_reasonapplies to these rows as it does to kit tools.awk '$1 == "syft" { print $2 }').Docs:
skills/github-actions-hygienerule 10 and thedocs/template/architecture.mdledger row mention the file.Related issue
Closes #107
Validation
Pick validation depth by blast radius. A level that applies but could not run becomes a
RISK:line below. See AGENTS.md for the validation ladder.make lint;bash -nandshellcheckon the scriptmake checkok, exit 0;DRIFT; a two-field row →ERROR (… expected '<tool> <version> <source>');gitlab:x/y→ERROR (lookup failed), exit 1;Risk / rollback
Checklist
Before merging:
<type>: <description>)*.local.mdfiles committed