Skip to content

ci: lint workflows with actionlint and zizmor, and let Dependabot update npm - #113

Merged
Mearman merged 3 commits into
mainfrom
ci-linters
Oct 3, 2026
Merged

Mearman merged 3 commits into
mainfrom
ci-linters

Conversation

@Mearman

@Mearman Mearman commented Oct 3, 2026

Copy link
Copy Markdown
Member

Adds Actionlint and Zizmor jobs to CI, copied from monorepo-template: actionlint 1.7.12 and shellcheck 0.11.0 downloaded at pinned versions and checked against SHA-256 digests per runner architecture, and zizmor 1.30.1 through uvx, offline. Both run on the runner determine-runner selects and are joined into Required Checks, so the required check name is unchanged. .github/actionlint.yaml lists exadev-runners and the two Blacksmith labels this workflow uses; .github/zizmor.yml requires a commit SHA for every action outside ExaDev (ExaDev/* may use a tag) and disables self-repository, whose $/ syntax actionlint still rejects (rhysd/actionlint#711).

Findings on the existing workflow, before this change:

  • zizmor artipacked on the commitlint, lint, typecheck, mutation and publish-aliases checkouts: fixed with persist-credentials: false. None of them pushes; the release job's checkout already had it and is untouched.
  • zizmor template-injection on echo '${{ toJSON(needs) }}' in Required Checks: the JSON now arrives through env.
  • zizmor adhoc-packages on the release job's npm install -g npm@12.1.0: ignored inline on that line. The version is an exact, deliberately chosen pin, and the release job's behaviour is unchanged.
  • actionlint: nothing.

With the configs from this branch, both commands as CI runs them fail on a deliberately bad workflow in a scratch repository (tag-pinned actions/checkout@v4, unknown runner label, ${{ github.event.pull_request.title }} in run:, an unquoted variable): actionlint exits 1 (runner-label, expression, shellcheck SC2086) and zizmor exits 14 (unpinned-uses, template-injection, artipacked, excessive-permissions).

Dependabot also gets an npm entry with the same weekly schedule, grouped minor and patch updates and the same cooldown: default-days: 7 as the github-actions entry, matching the seven-day minimum release age local installs use. The packages listed in minimumReleaseAgeExclude (eslint-plugin-json-canonical, @exadev/config) are in cooldown.exclude, so both gates treat them alike. The cooldown keys are checked against GitHub's Dependabot options reference (https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference, archived at https://web.archive.org/web/20261001095248/https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference): default-days and exclude are supported for npm, and cooldown never delays security updates.

Jobs that never push no longer leave the job token in .git/config,
where any later step or uploaded artefact could read it.
The release job's checkout already opted out and is unchanged.

The Required Checks job printed toJSON(needs) inside a single-quoted echo,
so a quote in any job output would end the string and run as shell.
It now reaches the script through env.
Nothing stopped a tag-pinned third-party action, an unknown runner label
or a script injection from coming back into the workflows.
Actionlint (with shellcheck) and zizmor now run as their own jobs on the
runner determine-runner selects, and Required Checks waits on both.

Both tools are pinned: actionlint and shellcheck by version and SHA-256
per runner architecture, zizmor through uvx at an exact version, offline.
.github/actionlint.yaml lists the fleet and Blacksmith runner labels.
.github/zizmor.yml requires a commit SHA for every action outside ExaDev
and disables self-repository, whose `$/` syntax actionlint rejects.

The release job's pinned npm upgrade is ignored inline for adhoc-packages.
The npm entry mirrors the github-actions one: weekly, minor and patch
updates grouped, and a seven-day cooldown matching the minimum release age
local installs enforce. Packages listed in minimumReleaseAgeExclude are
exempted from the cooldown too, so the two gates agree.
@Mearman
Mearman marked this pull request as ready for review October 3, 2026 12:59
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-03T13:05:39.885141Z a760bee Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Mearman
Mearman merged commit f495875 into main Oct 3, 2026
10 checks passed
@Mearman
Mearman deleted the ci-linters branch October 3, 2026 13:06
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 2.35.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant