-
[OPIK-3662] [INFRA] feat: add actionlint workflow validation (#6600)
发布于
2026-05-18 11:11:59 +00:00 - [OPIK-3662] [INFRA] feat: add actionlint workflow validation
Adds actionlint as a CI gate for changed GitHub Actions workflow files,
plus a matching pre-commit hook with graceful degradation when the
binary is not installed locally. Both run withSHELLCHECK_OPTS=--severity=warning
so the pre-existing SC2086 backlog (tracked in OPIK-6323) does not gate
PRs while real warning+ findings still do.Real defects fixed alongside the enabling change:
- 9 outdated action versions (publish_cursor_extension.yml@v2,
setup-python@v3/v4 in 4 files, setup-node@v3 in 3 files, cache@v3,
release-drafter@v5) - Script-injection risk in trigger_test_env_on_label.yaml: pull_request.head.ref
is now passed via env: instead of interpolated into actions/github-script
body - Deprecated set-output -> $GITHUB_OUTPUT (documentation_cookbook_tests.yml)
- SC2046 unquoted command substitution in same file
- workflow_call default value on a required input (build_and_publish_sdk.yaml)
- Undeclared workflow_dispatch input ALLURE_JOB_RUN_ID (test_docs_links.yml)
Deferred to OPIK-6323: 168 SC2086 quoting cleanup, 9 remaining cosmetic
events default removals, 2 remaining expression issues, and tightening
the gate to scan all files at default shellcheck severity.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(ci): use unicode octopus in workflow name
:octocat:is a GitHub markdown shortcode and only renders in places
that go through GFM (PR descriptions, comments). It does not render in
the Actions UI workflow name, where the raw string:octocat: Lint Workflowswas showing instead. Switching to the unicode octopus 🐙
which the Actions UI renders correctly.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(ci): pin actionlint install via gh release + attestation verify
Addresses Baz comment on PR #6600: the previous
bash <(curl ...)install
pulled the download script from a mutable URL with no integrity check.Replaces it with the upstream-recommended secure install path from
https://github.com/rhysd/actionlint/blob/main/docs/install.md:- Resolve the latest release tag via
gh release view - Download the linux_amd64 tarball as an immutable release asset
- Verify its GitHub artifact attestation (Sigstore-signed by rhysd's
release CI) before executing — verifies provenance, not just bytes - Echo the version in the workflow log for traceability
This is strictly stronger than the SHA256-pinning Baz suggested:
attestation verification confirms the artifact was built by the
official rhysd/actionlint release workflow, not just that the bytes
match a hardcoded hash.ghis preinstalled on GitHub-hosted runners,
so no extra setup needed.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat(ci): also lint workflows that use changed composite actions
Composite actions in .github/actions/*/action.yml can't be linted by
actionlint directly (it treats them as workflows and complains about
missing on:/jobs:). They're validated transitively when a workflow
that references them is linted.Extends the gate (CI + pre-commit) to detect when a composite action
is changed without a workflow edit, find the workflows that reference
it viauses: ./.github/actions/<name>, and add those to the lint
set. Avoids the full-tree fallback that would have tripped on the
pre-existing baseline findings deferred to OPIK-6323.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- refactor(ci): drop unnecessary const layer in trigger_test_env_on_label
Addresses liyaka's review comment on PR #6600: the intermediate
const headRef = process.env.HEAD_REFandconst baseVersion = ...lines
added ceremony for values used once. Inlines${process.env.HEAD_REF}
and${process.env.BASE_VERSION}directly in the template literal.The
env:block is preserved — that's the actual security primitive.
Passing${{ github.event.pull_request.head.ref }}via env: (rather
than inlining it into the script body) prevents script injection,
because env: values are read at runtime via process.env rather than
substituted into the script source by${{ }}expansion. Added a
comment block above the env: keys explaining this so the indirection
is no longer mysterious.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com
下载附件