From ce695c9c97be65feb0a1e95a6f42aa949261aefa Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 6 Oct 2026 01:35:43 +0000 Subject: [PATCH] Cancel replaced CI runs and drop the checkout token (closes #107) The canonical `.gitea/workflows/check.yml` gains a `concurrency` block grouped by workflow and branch with `cancel-in-progress: true`, so a new push cancels the older run on the same branch and no other, and its checkout step sets `persist-credentials: false`, so the job's token is not left in `.git/config`; `script/cibuild` needs none. Both come from `dnswatcher`, where a byte-identical re-vendor would have removed them. The workflow bullet of `prompts/REPO_POLICIES.md` and both checklists now describe the file as it is. Model: opus-5-5 --- .gitea/workflows/check.yml | 7 +++++++ TODO.md | 6 ++++++ prompts/EXISTING_REPO_CHECKLIST.md | 4 +++- prompts/NEW_REPO_CHECKLIST.md | 4 +++- prompts/REPO_POLICIES.md | 12 +++++++++--- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/check.yml b/.gitea/workflows/check.yml index ee73864..6246a7e 100644 --- a/.gitea/workflows/check.yml +++ b/.gitea/workflows/check.yml @@ -1,9 +1,16 @@ name: check on: [push] +# Free the shared runner: a new push cancels only the same branch's older run. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: check: runs-on: ubuntu-latest steps: # actions/checkout v4.2.2, 2026-02-22 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + # script/cibuild needs no token, so none is left in .git/config. + with: + persist-credentials: false - run: script/cibuild diff --git a/TODO.md b/TODO.md index 80d8ca8..0057a3b 100644 --- a/TODO.md +++ b/TODO.md @@ -21,6 +21,12 @@ fmt-check, and commit. # Completed Steps +- 2026-10-06: The canonical `.gitea/workflows/check.yml` now has a `concurrency` + block, so a new push cancels the older run on the same branch and no other, + and its checkout step sets `persist-credentials: false`, so the job's token is + not left in `.git/config` (issue 107). `REPO_POLICIES.md` and both checklists + describe the workflow as it now is. Not yet tried on the shared runner, which + is out of disk space. Repositories pick this up on their next re-vendor. - 2026-10-06: The canonical `.golangci.yml` now disables `canonicalheader` (issue 105). In golangci-lint v2.14.0 it misses findings at random in a package that also calls `ResponseWriter.Header()`, so the same tree can fail diff --git a/prompts/EXISTING_REPO_CHECKLIST.md b/prompts/EXISTING_REPO_CHECKLIST.md index 28bb055..b12ee3b 100644 --- a/prompts/EXISTING_REPO_CHECKLIST.md +++ b/prompts/EXISTING_REPO_CHECKLIST.md @@ -96,7 +96,9 @@ with your task. `fetch-depth: 0` on the CI checkout step, which clones shallow and fetches no tags by default. - [ ] Gitea Actions workflow in `.gitea/workflows/` runs `script/cibuild` on - push — reference + push, checks out with `persist-credentials: false`, and carries the + `concurrency` block that lets a new push cancel only the same branch's + older run — reference `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml` - [ ] Language-specific config: - [ ] Go: `go.mod`, `go.sum`, `.golangci.yml` (fetch from diff --git a/prompts/NEW_REPO_CHECKLIST.md b/prompts/NEW_REPO_CHECKLIST.md index 56619a3..ab43568 100644 --- a/prompts/NEW_REPO_CHECKLIST.md +++ b/prompts/NEW_REPO_CHECKLIST.md @@ -106,7 +106,9 @@ Template files can be fetched from: - Non-server: the final stage brings up the dev environment - Image pinned by sha256 hash with version/date comment - [ ] Gitea Actions workflow at `.gitea/workflows/check.yml` that runs - `script/cibuild` on push — reference + `script/cibuild` on push, checks out with `persist-credentials: false`, + and carries the `concurrency` block that lets a new push cancel only the + same branch's older run — reference `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml` - [ ] Language-specific: - [ ] Go: `go mod init sneak.berlin/go/`, `.golangci.yml` (fetch from diff --git a/prompts/REPO_POLICIES.md b/prompts/REPO_POLICIES.md index c72195c..73a0b8c 100644 --- a/prompts/REPO_POLICIES.md +++ b/prompts/REPO_POLICIES.md @@ -283,9 +283,15 @@ style conventions are in separate documents: refuses an empty build argument drops that refusal and keeps the argument. - Every repo should have a Gitea Actions workflow (`.gitea/workflows/`) that - runs `script/cibuild` on push, and checks out the repo as its only other step. - That script bootstraps, runs the gate phases, and then builds the image, so a - successful run means every check passed; a bare `docker build .` does not + runs `script/cibuild` on push, and checks out the repo as its only other step, + with `persist-credentials: false`: `script/cibuild` needs no token, and + without it the checkout leaves the job's token in `.git/config` for every + later step. Its `concurrency` block groups runs by workflow and branch + (`${{ github.workflow }}-${{ github.ref }}`) with `cancel-in-progress: true`, + so a new push cancels the older run on the same branch, queued or running, and + no other: runs for replaced commits do not hold up the shared runner. + `script/cibuild` bootstraps, runs the gate phases, and then builds the image, + so a successful run means every check passed; a bare `docker build .` does not carry the same guarantee, because its gate phases may come from the cache. The image build is uncached and so runs the gate phases a second time. That is the price of the rule above, and it is worth paying: the image that ships is built