Bring the seed's workflow templates up to the seeded repos' zizmor hygiene

Merged
JE
2mo ago
+208-82

seed/.github/workflows/*.yml.tmpl, rendered with placeholder values and audited by zizmor 1.30.0 (--persona regular), produce 93 findings on main today (97 before #14 removed the five self-repository ones). A freshly seeded SDK therefore fails its own actions audit on its first CI run, and then someone re-does by hand what hey-sdk, basecamp-sdk and fizzy-sdk each already did in their own workflows. This PR brings the templates up to what those repos run, so the seed stops drifting from them.

Originally stacked on #11 and #14; both have merged, so this is now two commits against main. #17 was closed as a duplicate of #11 and is folded away: the only edit to #11's smithy-verify.yml.tmpl is a trailing # zizmor: ignore[unpinned-uses] on its basecamp/sdk/actions/smithy-verify@main line, and test.yml.tmpl keeps #11's inline smithy-verify job (the composite action run directly, as #11's header comment says) with the hygiene applied to it.

Before / after

Rendered templates (.tmpl stripped, placeholders filled), zizmor --no-progress --persona regular, default policy:

rulemain (0a453bc)this PR
unpinned-uses (high)460 (5 ignored inline)
artipacked220 (1 ignored inline)
excessive-permissions90
cache-poisoning (high)70 (7 ignored inline)
template-injection70
adhoc-packages20 (1 ignored inline)
total930

actionlint (1.7.12) on the same rendered tree: clean, with the added seed/.github/actionlint.yaml (hey-sdk's file) naming the exact $/ reusable-workflow call actionlint predates. The repo's own gate from #11 — hack/render-seed.sh, then actionlint and zizmor --config hack/zizmor-seed.yml --min-severity high over the render — is green, and the render is also clean under the default policy, so every exception hack/zizmor-seed.yml records "until the template it names is re-extracted" is now unnecessary; that file can shrink to the four basecamp/sdk/actions/* entries or go entirely, since the inline ignores cover those. Left for a follow-up rather than folded in here.

What changed, per finding class

Each change is the seeded repos' version of the same line; hey-sdk is the reference, basecamp-sdk where hey-sdk has no Kotlin, Ruby, Swift or TypeScript.

  • unpinned-uses — every uses: pinned to a full commit SHA with its # vX.Y.Z comment, copied from the Dependabot-maintained pins in hey-sdk and basecamp-sdk and each verified against the upstream tag: actions/checkout v7.0.1, actions/setup-go v7.0.0, actions/setup-java v6.0.0, actions/setup-node v7.0.0, gradle/actions/setup-gradle v6.3.0, ruby/setup-ruby v1.321.0, aquasecurity/trivy-action v0.36.0, github/codeql-action/upload-sarif v4.37.9, rubygems/configure-rubygems-credentials v2.1.0. The seed's own composite actions (basecamp/sdk/actions/*@main) stay on main by design and carry the ignore hey-sdk wrote for it.
  • excessive-permissions — permissions: {} at the top of every workflow; contents: read per job, including the jobs that call the reusable workflow; id-token: write, packages: write and security-events: write only on the job that publishes or uploads.
  • artipacked — persist-credentials: false on every checkout except the Go tag job, which pushes and carries hey-sdk's ignore.
  • cache-poisoning — caches kept, with the seeded repos' two reasons: cache is branch-isolated; fork PRs cannot write to this cache on release-job setups, cached deps are for testing, not release artifact generation on test-job setups.
  • template-injection — ${{ steps.*.outputs.* }} and ${{ github.event_name }} hoisted into env:.
  • adhoc-packages — npm install -g npm@latest at release time is gone: the npm publish job runs on Node 24, whose bundled npm already supports OIDC trusted publishing (basecamp-sdk's move, with its comment). gem install bundler-audit stays, with basecamp-sdk's reason inline. govulncheck@latest is pinned to v1.1.4, the newest release that builds on the seed's Go floor: go.mod.tmpl says go 1.23, the templates select the toolchain with go-version-file: go/go.mod (as the seeded repos do), setup-go v7 exports GOTOOLCHAIN=local, and every govulncheck release from v1.2.0 requires Go 1.25 (v1.8.0: 1.26). hey-sdk and fizzy-sdk pin v1.1.4; basecamp-sdk's v1.8.0 works there only because its go.mod is 1.26. The pin moves with go.mod.tmpl.

Two consequences of the pin bumps, both following basecamp-sdk: gradle/actions/setup-gradle v6 defaults to its commercial enhanced cache provider, so the templates set cache-provider: basic (what v5 did); rubygems/configure-rubygems-credentials moves v1.0.0 → v2.1.0, the only SHA the seeded repos pin (the step takes no inputs).

Left in place, with reasons inline

All 14 ignored findings carry a # zizmor: ignore[rule] -- reason copied from the seeded repos: 5 unpinned-uses (the seed's own actions on @main), 7 cache-poisoning, 1 artipacked (Go tag push), 1 adhoc-packages (bundler-audit). Under --persona pedantic the rendered tree still reports concurrency-limits, undocumented-permissions and anonymous-definition, none of which the seeded repos' default-persona CI enforces either.

Merges

Two commits on main, no merge conflicts. Against #15 (rustS2/seed-rust), git merge-tree reports two add/add conflicts: .github/workflows/ci.yml, which #15 already has against main (it is based on #11's pre-merge branch), and seed/.github/workflows/smithy-verify.yml.tmpl, which this PR causes — #15 re-adds #11's file verbatim and this PR's copy differs by the one trailing ignore comment. Whichever lands second takes #11's file plus that comment.

Not done here

  • No lint-actions job (actionlint + zizmor) in test.yml.tmpl. Every seeded repo has one; it is what would keep a seeded SDK honest after day one, but it is a new job rather than a fix to an existing finding. Worth its own PR.
  • persist-credentials: false followed by git fetch origin main works because the seeded repos are public (hey-sdk's release-go ran green with this pattern today). A private SDK would need that one step's credentials back.
  • Raising the seed's Go floor from 1.23 to 1.26 (what all three seeded repos run today) would allow govulncheck v1.8.0; that is a seed-wide change for a separate decision.