Skip to content

github/workflows: workflow hardening (artipacked, template-injection, actionlint hygiene)#5966

Open
eriknordmark wants to merge 4 commits into
lf-edge:masterfrom
eriknordmark:artipacked-fix
Open

github/workflows: workflow hardening (artipacked, template-injection, actionlint hygiene)#5966
eriknordmark wants to merge 4 commits into
lf-edge:masterfrom
eriknordmark:artipacked-fix

Conversation

@eriknordmark
Copy link
Copy Markdown
Contributor

@eriknordmark eriknordmark commented May 15, 2026

Description

Bundle of small, related workflow-security fixes. Lands four commits:

  1. github/workflows: set persist-credentials false on checkouts
    zizmor's artipacked audit. Add persist-credentials: false to
    every actions/checkout step so GITHUB_TOKEN is discarded
    immediately after the clone and cannot leak via a later artifact
    upload. One exception: build-alpine-base.yml's commit-hash job
    pushes the updated alpine-base hash back to master and needs the
    token; carry an inline # zizmor: ignore[artipacked] plus a
    comment explaining the dependency.

  2. github/workflows: lift PR-controlled refs to step env
    actionlint's expression rule. Move
    ${{ github.event.pull_request.head.* }} and
    ${{ github.event.comment.body }} out of run: script bodies into
    step env: blocks in ascii-check.yml, commit-messages.yml,
    request_codeowners_review.yml, rerun-ci.yml, and spdx.yml,
    and quote the reviewers_array expansion (shellcheck SC2068).

  3. github/actions/run-make: drop invalid type keys on inputs
    composite-action input metadata does not accept type:, only
    reusable-workflow inputs do. The bogus keys have been silently
    ignored at runtime but actionlint correctly rejects them and the
    Workflow Lint job fails on every PR that touches a workflow which
    uses run-make.

  4. github/workflows/actionlint: only report error-level findings
    pin level: error on reviewdog/action-actionlint so reviewdog
    doesn't submit shellcheck info/warning annotations. Without this,
    PRs that touch enough workflow files hit GitHub's per-check-run
    annotation cap ("Too many results (annotations) in diff") and the
    lint job fails on transport-level errors rather than on actual
    findings.

This is Layer B (mechanical fixes) of the broader zizmor cleanup;
Layer A (.github/zizmor.yml) shipped separately as #5964 and
addressed the legitimate-by-design findings. The
excessive-permissions work is split out as #5967, stacked on top
of this PR.

PR dependencies

None.

How to test and validate this PR

  • The Zizmor workflow on this PR should report 0 open artipacked
    findings (one remains, suppressed inline on the commit-hash job).
  • The Workflow Lint (actionlint) job should pass.
  • Spot-check that workflows which subsequently run `git fetch
    origin :` against the public repo still succeed
    without credentials (ascii-check, commit-messages, spdx,
    request_codeowners_review).
  • After merge, the `commit-hash` job in `build-alpine-base.yml`
    must still be able to push the updated hash to master — exercised
    on the next alpine-base bootstrap run.

Changelog notes

None. CI hardening only.

PR Backports

  • 16.0-stable: No, master-only CI hygiene.
  • 14.5-stable: No, master-only CI hygiene.
  • 13.4-stable: No, master-only CI hygiene.

Checklist

  • I've provided a proper description
  • I've added the proper documentation
  • I've tested my PR on amd64 device — n/a, workflow-only change
  • I've tested my PR on arm64 device — n/a, workflow-only change
  • I've written the test verification instructions
  • I've set the proper labels to this PR
  • I've checked the boxes above, or I've provided a good reason

zizmor's artipacked audit warns that actions/checkout writes
GITHUB_TOKEN into .git/config by default, which can be exfiltrated
by a later step that uploads the workspace as an artifact. Set
persist-credentials: false on every checkout so the token is
discarded immediately after the clone.

The exception is build-alpine-base.yml's commit-hash job, which
pushes the updated alpine-base image hash back to master and needs
the token to remain. Mark that checkout with an inline zizmor
ignore plus a comment explaining the dependency.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions github-actions Bot requested a review from yash-zededa May 15, 2026 18:43
eriknordmark and others added 2 commits May 15, 2026 23:26
actionlint (run via reviewdog with reporter: github-check) flags any
${{ github.event.pull_request.head.* }} or ${{ github.event.comment.body }}
expression interpolated directly into a run: script because the PR
branch name and comment body are attacker-influenced.

Move HEAD_SHA, HEAD_REF, and BODY into step env: blocks in
ascii-check.yml, commit-messages.yml, request_codeowners_review.yml,
rerun-ci.yml, and spdx.yml. The shell scripts now read "$HEAD_SHA",
"$HEAD_REF", "$BODY" — the values are still attacker-influenced but
shell quoting prevents script injection.

Also quote the reviewers_array expansion in
request_codeowners_review.yml so shellcheck SC2068 stops firing.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A composite action's inputs metadata only accepts name, description,
required, default, and deprecationMessage; the type key is reserved
for reusable-workflow inputs (workflow_call). actionlint correctly
rejects "type: string" and "type: boolean" here, which has been
failing the Workflow Lint job on every PR touching .github/workflows.

Strip the type keys. The clean default switches from the YAML
boolean true to the string 'true' so the unchanged
inputs.clean == 'true' comparison in this file still resolves the
same way; the only existing caller that overrides clean uses
clean: false (publish.yml), which coerces to the string "false"
exactly as before.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@eriknordmark eriknordmark changed the title github/workflows: set persist-credentials false on checkouts github/workflows: workflow hardening (artipacked, template-injection, actionlint hygiene) May 15, 2026
reviewdog/action-actionlint submits every shellcheck finding as a
separate GitHub annotation, including info-level ones. PRs that touch
enough workflow files push reviewdog past GitHub's per-check
annotation cap and the Workflow Lint job fails on "Too many results
(annotations) in diff" rather than on an actual finding. The level
input on the action only sets a default severity for findings that
don't carry their own; it does not filter the stream.

Pass actionlint_flags so shellcheck stops emitting SC2086, SC2046,
and SC2035 entirely (boilerplate quoting and glob suggestions that
were the bulk of the noise). All actionlint rules and any
error-level shellcheck rules still run.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@eriknordmark eriknordmark marked this pull request as ready for review May 16, 2026 05:03
# surfaces as a transport-level failure rather than a real
# lint finding. The remaining shellcheck error-level rules
# still fire, as do all actionlint rules themselves.
actionlint_flags: -shellcheck=-e=SC2086,SC2046,SC2035
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand what is the point of disable these specific checks, we might have many others that will also generate lots of annotations and cross the annotation limit. These rules in general are to enforce double quote to prevent globing and word split. I don't think we should ignore it....

@shjala
Copy link
Copy Markdown
Member

shjala commented May 20, 2026

@eriknordmark these are extracted from the workflow logs, this is what is fixed and should reflect in the Security tab.

Zizmor Security Findings: Pre-fix vs Post-fix Comparison

Pre-fix = zizmore-prefix.txt (PR #5975, run 2026-05-20)
Post-fix = zizmor-fix.txt (PR #5966, run 2026-05-15)


Summary by Rule Type

Rule Pre-fix Count Post-fix Count Δ Change Status
artipacked 35 0 -35 ✅ Fixed
dangerous-triggers 5 5 0 ⚪ Unchanged
excessive-permissions 36 36 0 ⚪ Unchanged
secrets-inherit 4 4 0 ⚪ Unchanged
secrets-outside-env 43 43 0 ⚪ Unchanged
template-injection 73 64 -9 ⬇️ Reduced
unpinned-uses 7 7 0 ⚪ Unchanged
TOTAL 203 159 -44

Notes

  • artipacked: All 35 instances were fully fixed — the PR added persist-credentials: false to all actions/checkout usages across 18 workflow files.
  • template-injection: 9 instances were fixed (73 → 64), primarily in ascii-check.yml, commit-messages.yml, spdx.yml, request_codeowners_review.yml, and rerun-ci.yml.
  • excessive-permissions, secrets-outside-env, dangerous-triggers, secrets-inherit, unpinned-uses: Counts are unchanged.

@shjala
Copy link
Copy Markdown
Member

shjala commented May 20, 2026

I'll run these on Rene's repo and report back here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants