Skip to content

ci: fix the three MegaLinter failures on main - #20

Merged
gwarf merged 2 commits into
mainfrom
ci/fix-megalinter-failures
Aug 12, 2026
Merged

ci: fix the three MegaLinter failures on main#20
gwarf merged 2 commits into
mainfrom
ci/fix-megalinter-failures

Conversation

@gwarf

@gwarf gwarf commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Fixes the MegaLinter failure on main (run 31520588750, commit 519b549). Three linters were red; each had a distinct cause. Fixing the first one unmasked a fourth batch of findings, handled in the second commit.

1. ACTION_ZIZMOR — 1 error

zizmor's ref-confusion audit calls the GitHub API and got 401 Unauthorized, so it aborted with fatal: no audit was performed. GITHUB_TOKEN is already in the job env, but MegaLinter sanitises secret-shaped variables out of linter subprocesses unless explicitly whitelisted.

Fix: ACTION_ZIZMOR_UNSECURED_ENV_VARIABLES: GITHUB_TOKEN, which is what MegaLinter's own error message recommends.

Trade-off worth stating: this hands the job token to a third-party linter binary inside the container. The alternative, ACTION_ZIZMOR_ARGUMENTS: --no-online-audits, would keep every offline audit and give up only ref-confusion and known-vulnerable-actions. I went with the token because the job token here is contents: read on a public repo and known-vulnerable-actions is worth keeping. Note that the alternative would not have made the job green on its own, since the findings in section 4 below are all offline audits.

2. BASH_SHELLCHECK — 12 errors

Nine of the twelve are in home/private_dot_local/bin/executable_msmtpq, which is vendored upstream (msmtpq suite, Chris Gianniotis, GPLv3) — SC2218, SC2046, SC2064, SC2320, SC2174, SC2329. Not ours to patch, and patching it would conflict on every upstream sync. Excluded, along with its sibling executable_msmtp-queue, via BASH_SHELLCHECK_FILTER_REGEX_EXCLUDE.

The other three are SC1091 in daryl-gemini, daryl-goose and daryl-gpt: they source ~/.config/daryl/mail-env.sh, which only exists at runtime on a provisioned host. Fixed properly with a # shellcheck source=/dev/null directive rather than an exclusion.

Left alone deliberately: shfmt also runs over the two vendored scripts and rewrites them. It is green today, so it is out of scope here, but it will produce upstream-sync churn — worth excluding separately if that ever bites.

3. REPOSITORY_BETTERLEAKS — 1 error

generic-api-key matched signingkey in home/dot_gitconfig.user.tmpl:8. The value is a public GPG key fingerprint, which is exactly the sort of thing you publish. Marked with an inline betterleaks:allow plus a comment saying why.

gitleaks passes on the same file; betterleaks is the newer sibling linter with a wider generic rule.

4. ACTION_ZIZMOR again — 8 pre-existing findings, previously masked

Once zizmor could authenticate it ran to completion for the first time and reported 8 real findings in this workflow. They were always there; the abort in section 1 hid them. Second commit fixes all of them.

  • unpinned-uses, 5x, high. Every uses: was on a floating major tag. Pinned to a commit SHA with the major kept as a trailing comment. .github/dependabot.yml already tracks github-actions daily, so it will keep the pins current — no manual upkeep. Note these pin the currently referenced majors (checkout@v6, megalinter@v9); no version bumps are smuggled in here, dependabot can propose those separately.
  • artipacked, 1x. actions/checkout left the token in .git/config for every later step. Set persist-credentials: false. Both fix-applying steps authenticate on their own (create-pull-request via its token: input, and APPLY_FIXES_MODE is pull_request so the git-auto-commit-action path is inert), so nothing downstream needs it. There is a comment in the workflow flagging that flipping APPLY_FIXES_MODE to commit would need this revisited — that is the one coupling to keep in mind.
  • template-injection, 2x. ${{ steps.cpr.outputs.* }} expanded straight into a run: block. Moved to env: so the values reach the shell as data, not source.

Verification

  • shellcheck --external-sources on the three daryl-* scripts: clean, exit 0. Same run against executable_msmtpq: still exit 1 with 49 lines of findings, confirming the exclusion is what clears it and not something else.
  • git config --get user.signingkey against the edited stanza returns 46BDC6B3... with the trailing # betterleaks:allow stripped, so the comment does not corrupt the value.
  • zizmor --no-online-audits on the edited workflow: No findings to report, exit 0.
  • actionlint: clean, exit 0.
  • CI on this PR: both MegaLinter runs green.

One gap worth naming: this PR runs with VALIDATE_ALL_CODEBASE: false, so shellcheck only lints changed files and the msmtpq exclusion is not exercised by the PR run — hence the local check above. Full-codebase validation happens on the push to main after merge.

Run 31520588750 failed on zizmor, shellcheck and betterleaks.

- zizmor: online audits need a GitHub token, and MegaLinter strips
  GITHUB_TOKEN from linter subprocesses unless whitelisted. Whitelist it
  so ref-confusion and known-vulnerable-actions keep running.
- shellcheck: msmtpq and msmtp-queue are vendored upstream and account
  for 9 of the 12 findings; exclude them. Silence SC1091 in the three
  daryl-* wrappers, whose sourced file only exists at runtime.
- betterleaks: user.signingkey is a public GPG key fingerprint, not a
  secret; mark it allowed.
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ ACTION actionlint 1 0 0 0.3s
✅ ACTION zizmor 1 0 0 0 1.22s
✅ BASH shellcheck 3 0 0 0.26s
✅ BASH shfmt 3 0 0 0 0.08s
✅ REPOSITORY betterleaks yes no no 1.03s
✅ REPOSITORY checkov yes no no 12.28s
✅ REPOSITORY gitleaks yes no no 0.06s
✅ REPOSITORY git_diff yes no no 0.05s
✅ REPOSITORY osv-scanner yes no no 0.16s
✅ REPOSITORY secretlint yes no no 2.32s
✅ REPOSITORY syft yes no no 1.95s
✅ REPOSITORY trivy-sbom yes no no 0.25s
✅ SPELL lychee 1 0 0 0.06s
✅ YAML prettier 1 0 0 0 0.42s
✅ YAML v8r 1 0 0 1.75s
✅ YAML yamllint 1 0 0 0.45s

Notices

📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining SECURITY_SUGGESTIONS: false)

See detailed reports in MegaLinter artifacts
Set VALIDATE_ALL_CODEBASE: true in mega-linter.yml to validate all sources, not only the diff

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

With the token in place zizmor completes its audits for the first time
and reports 8 pre-existing findings that the earlier abort had masked.

- unpinned-uses (5x, high): pin every action to a commit SHA with the
  major tag kept as a trailing comment. dependabot is already configured
  for github-actions, so it will keep the pins current.
- artipacked (1x): set persist-credentials: false on checkout. Both
  fix-applying steps authenticate on their own, so nothing downstream
  needs the token left in .git/config.
- template-injection (2x): pass the create-pull-request step outputs
  through env vars instead of expanding them into the shell source.

@gwarf gwarf left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

LGTM

@gwarf
gwarf merged commit d47749d into main Aug 12, 2026
2 checks passed
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.

1 participant