ci: single gate, merged image job, shared composite actions, docs workflow merge - #4221
Conversation
|
Allowlist update needed for Please wait for the allowlist PR to merge before merging this PR, otherwise CI will fail because the new SHA isn't allowlisted yet. |
|
Allowlist update needed for Please wait for the allowlist PR to merge before merging this PR, otherwise CI will fail because the new SHA isn't allowlisted yet. |
|
Allowlist update needed for Please wait for the allowlist PR to merge before merging this PR, otherwise CI will fail because the new SHA isn't allowlisted yet. |
ae2d7a3 to
a9cd2cd
Compare
7601fe2 to
dc803ea
Compare
|
Allowlist update for A maintainer declined to allowlist this action, so CI will keep failing while it is used. Remove the action or switch to an allowed alternative, and contact the security team if you believe this rejection is a mistake. |
|
Allowlist update for A maintainer declined to allowlist this action, so CI will keep failing while it is used. Remove the action or switch to an allowed alternative, and contact the security team if you believe this rejection is a mistake. |
|
Allowlist update for A maintainer declined to allowlist this action, so CI will keep failing while it is used. Remove the action or switch to an allowed alternative, and contact the security team if you believe this rejection is a mistake. |
|
👋 This PR has merge conflicts with the base branch. Please rebase or merge the latest base branch and resolve them. I've moved it to draft and added |
1 similar comment
|
👋 This PR has merge conflicts with the base branch. Please rebase or merge the latest base branch and resolve them. I've moved it to draft and added |
- `gate` is the single job the main ruleset needs to require: it needs every blocking job (now also test-windows, cross-compile and image) and passes on success or skip, so adding a check no longer touches the ruleset; `publish` needs `gate` instead of listing every job. - `build-image` and `build-and-push-image` duplicated ~120 lines and differed only by exporter/attestations/build args; one `image` job now decides publish vs cache-only in a step and feeds both build-push steps. - OIDC validation, Hub login and builder setup move to `setup-buildx`; Task install moves into `setup-go`, which also saves the cache itself on main (actions/cache post step) so jobs lose their Save Go caches step. - `lint` gains the parts of `task lint` CI never ran (project cops, go mod tidy) plus shellcheck on every script and the models-delta golden test, replacing the models-delta-lint workflow. - Jobs renamed to short nouns: test, test-windows, cross-compile, licenses, image, publish. Actions bumped to the latest allow-listed versions (checkout v7.0.1, setup-go v7.0.0, setup-task v2.2.0, docker/* majors on Node 24, golangci-lint v2.13.2, Task 3.53.1). - The run-commit sanity checks that only re-verified actions/checkout are dropped; the expected_sha input and OIDC config checks remain.
docs-lint, docs-a11y and docs-upstream shared the same triggers and path filters; they become parallel jobs of docs.yml (markdownlint, canonical, links, llms-txt, a11y, upstream). Hugo is installed by a setup-hugo composite action so the version is pinned once for docs and docs-deploy. Path filters also cover the composite action and every scripts/docs-*.sh. deploy-pages bumped to v5.0.1.
Workflow names are lowercase kebab-case (codeql, pr-review, pr-review-trigger, models-update); the workflow_run reference in pr-review follows the rename. models-update and models-live-check use the setup-go composite action restoring the test job's cache instead of their own Go/Task pins. codeql-action pinned to v4.38.0, create-pull-request to v8.1.1.
The repo sits at the 10 GB cache cap: each main push saved ~1 GB per Go job because every entry bundled the module cache. setup-go now keeps two caches: GOMODCACHE keyed on go.sum alone (saved once per dependency change, shared by every job and OS) and GOCACHE per job with the SHA suffix as before. A `save` input lets lint, licenses and CodeQL restore the test-linux build cache without saving a copy of their own. setup-task verifies the Task archive against the release checksums (per OS) and setup-hugo does the same for the Hugo tarball. setup-buildx gains a `builder` input so registry-only jobs skip creating a builder.
…n, zizmor - `changes` (dorny/paths-filter) marks a PR docs-only when every changed file is under docs/; Markdown elsewhere is test data so it still counts as code. Go jobs and image need it; lint always runs; gate treats skipped as passed. Pushes and merge-queue runs always run everything. - `merge_group` trigger, with its own concurrency group like main and tags. - `timeout-minutes` on every job (default was 6 h). - `test-race` runs `task test-race` (-race -shuffle=on) on main pushes only; not part of gate so it never sits on the PR critical path. - test-windows excludes the workspace, Go caches and TEMP from Defender real-time scanning; best effort (continue-on-error). - zizmor audits workflows and composite actions in lint (min severity low); .github/zizmor.yml keeps the deliberate workflow_run trigger of pr-review. Its findings fixed here: persist-credentials: false on every checkout. - Local actions referenced as `$/.github/actions/...` (resolved from the running commit, no checkout needed) — also fixes publish, which called a ./ action without checking out. actionlint 1.7.12 does not know the syntax yet, so that one message is ignored; workflow-lint skips `$/` refs. - go-licenses pinned to v2.0.1; gate writes a job/result table to the step summary; publish no longer creates an unused builder.
…flows Every job gets timeout-minutes, every checkout persist-credentials: false, and local actions use the $/ syntax. docs-deploy scopes pages/id-token permissions to the deploy job. CodeQL's Go analysis restores the test-linux build cache through setup-go instead of setup-go's shared snapshot.
Weekly grouped updates for workflows and the composite actions under .github/actions (SHA pins and version comments), with a 7-day cooldown so releases settle first. Go modules stay with the bump-go-dependencies skill.
dc803ea to
ecb6ee1
Compare
…ally Fork PRs, PRs opened by Dependabot and other bots running with a read-only token, and CI in forks of this repo receive neither repository variables nor an OIDC token, so the image job failed on `DOCKERHUB_OIDC_CONNECTION_ID must be configured` (why #4220 was reverted in #4223). The old condition compared the PR's *base* repository to this one, which is always true. The job now decides at runtime: Build Cloud (both platforms, one runner) whenever the Hub OIDC connection id and the OIDC token endpoint are present, otherwise a plain docker-container builder on the runner, linux/amd64 only, nothing pushed, no build-record upload. Publishing runs still fail loudly when Build Cloud is unavailable rather than downgrading. The Dockerfile is exercised on every PR instead of being skipped or failing.
ecb6ee1 to
f0e23b9
Compare
Why
Follow-up to #4220, which #4223 reverted because the image job failed on PRs from forks (
DOCKERHUB_OIDC_CONNECTION_ID must be configured). This PR is rebased on the revertedmain, so it re-lands everything #4220 did (parallel jobs, warm Go cache, Build Cloud) and fixes the fork case properly, see "Fork PRs" below. The workflows still duplicated setup boilerplate (Go, Task, Hugo, Hub login) across jobs and workflows, the two image jobs were ~120 near-identical lines, three docs workflows shared identical triggers, every new blocking check required editing themainruleset, runs onmaincould be evicted from the concurrency queue (run 34469610126), and the repo sat at the 10 GB cache cap.Changes
Structure
gateneeds every blocking job and passes on success or skip. Adding a blocking job means adding it togate.needs; the ruleset never changes again.test-windows,cross-compileandimagebecome blocking.build-image+build-and-push-image→image; a step decides publish vs cache-only and feeds both build-push steps.publishneedsgate+image..github/actions/, referenced as$/.github/actions/<name>(GitHub's same-repository syntax, resolved from the running commit, no checkout needed):setup-go(Go, Task, caches),setup-hugo,setup-buildx(OIDC login, optional Build Cloud builder). Tool versions are pinned there once.docs-lint,docs-a11y,docs-upstream→docs.yml, six parallel jobs.models-delta-lintfolded intolint.changes,lint,test-linux,test-windows,cross-compile,licenses,image,test-race,gate,publish. Workflows:ci,codeql,docs,docs-deploy,models-update,models-live-check,pr-review,pr-review-trigger,winget.Build Cloud first, local build as fallback
60% of this repo's PRs come from forks, and bots (Dependabot, the models-update workflow, the PR reviewer) open PRs too. Fork PRs and PRs run with a read-only token receive neither repository variables nor an OIDC token, and the old
imagecondition compared the PR's base repository to this one (always true), so the job ran and failed.imagenow decides at runtime: ifDOCKERHUB_OIDC_CONNECTION_IDand the OIDC token endpoint are present it uses Build Cloud (both platforms, one runner); otherwise it falls back to a plain builder on the runner,linux/amd64only, nothing pushed, no build-record upload, with a notice in the run. Publishing runs (main, tags) never downgrade: they fail loudly if Build Cloud is unavailable. Same-repo bot PRs (e.g. models-update) keep Build Cloud since they run with the repo's variables and OIDC. CI in a fork of this repo also works, via the local path.Feedback loop
changes(dorny/paths-filter) marks a PR docs-only when every changed file is underdocs/; Markdown elsewhere is test data and counts as code. Pushes and merge-queue runs always run everything.go.sumchange; build cache per job (SHA-suffixed) as before;lint,licensesand CodeQL restoretest-linux's build cache without saving their own. Saves happen onmainonly, viaactions/cache's post step, so the per-job save steps are gone. Stalesetup-*,buildx-*,buildkit-*,index-*entries purged (150 entries, ~4.3 GB).main, tags or merge-queue runs. Their concurrency group includesgithub.run_id; PR runs still supersede each other.continue-on-error). To be measured oncemainseeds the new cache keys.timeout-minuteson every job (default was 6 h).test-race(task test-race:-race -shuffle=on) onmainpushes only, outsidegate.Quality gates and supply chain
lintnow also runs the parts oftask lintCI never ran (project cops,go mod tidy --diff), shellcheck on every script, the models-delta golden test, and zizmor (.github/zizmor.ymlkeeps the deliberateworkflow_runtrigger ofpr-review). Its findings fixed here:persist-credentials: falseon every checkout, Pages permissions scoped to the deploy job.go-licensespinned to v1.6.0 (what@latestresolved to).bump-go-dependenciesskill.scripts/workflow-lint.shalso checks SHA pins in.github/actions/*and knows the$/syntax. AGENTS.md gained a GitHub Actions section.$/yet; that single message is ignored via-ignore.Action versions
All references are authorized by
docker/infra-github-allow-list(actions/*,github/*,docker/*wildcarded; third-party actions match exact entries). Bumped to the newest allowed:Held back:
browser-actions/setup-chromev2.1.2 (v2.2.0 not allow-listed yet), Hugo 0.163.0 (docker/docs still pins it).Node 20 deprecation: with these bumps every action and every action nested in the composite actions we use declares
node24. The onlynode20left isactions/download-artifactinside docker/docs'svalidate-upstream.ymlreusable workflow, which is theirs to update.Repo settings to update, and their impact
1. Before merging: require
gateinstead of the three old contextsThe "Main rules" ruleset requires
build-and-test,license-check,lint, which no longer exist here, so this PR cannot merge until it changes:Impact: from that moment every other open PR shows
gateas "Expected — waiting for status" because theirci.ymldoes not produce it. Existing PRs must rebase on (or merge)mainafter this PR lands to become mergeable again. Do it right before merging this PR to keep the window short.2. After merging: enable the merge queue
Only possible after this lands, because the queue needs the
merge_grouptrigger, which only exists in this PR'sci.yml:Impact: merging becomes "Merge when ready"; the queue tests each PR against the real tip of
mainbefore merging, somainis never broken by two green PRs that conflict semantically. PRs that have not rebased since this landed will fail in the queue (theirci.ymlhas nomerge_grouptrigger,gatenever reports, the entry times out after 60 min). Same remedy: rebase. Auto-merge already enabled on the repo keeps working through the queue.3. Nothing else
Dependabot starts on its own (first run next Monday). The cache purge is already done. The Enterprise ruleset is untouched.
Verified
actionlint (with the
$/ignore),scripts/workflow-lint.sh, shellcheck on every script, zizmor (no findings),go run ./lint .,go mod tidy --diff— all green locally, and the PR run is green on every job includinggate(run 34476151145); the ruleset just does not require it yet.test-windowstook 15 min on that run: the new cache key prefix means it compiled cold, so the Defender exclusion cannot be judged beforemainseeds the cache. First-run findings already fixed:go-licensesv2 lives under a/v2module path; the actionlint action splitsflagson whitespace.The local fallback cannot be exercised from this same-repo PR; the first fork or Dependabot PR after merge is its real test. Not in this PR: making
docsa required check (needs the same change-detection pattern), the Windows timing comparison, and thedbc-remediationbranch, which rewrites the image jobs too and will conflict.