Skip to content

ci: add actionlint, zizmor, and oxfmt checks - #15

Open
sou1118 wants to merge 1 commit into
mainfrom
ci/workflow-linters
Open

ci: add actionlint, zizmor, and oxfmt checks#15
sou1118 wants to merge 1 commit into
mainfrom
ci/workflow-linters

Conversation

@sou1118

@sou1118 sou1118 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

Add a Workflow Lint job to CI that runs three checks, all version-pinned in mise.toml:

  • actionlint 1.7.12 — workflow syntax/semantics linting
  • zizmor 1.28.0 — GitHub Actions security audit (runs with GH_TOKEN for online audits)
  • oxfmt 0.62.0 — format check for YAML/Markdown/JSON/TOML across the repo (installed as a native binary via the aqua backend, pinned to the oxc monorepo apps_v1.77.0 release tag)

Security fixes (zizmor findings)

Running zizmor surfaced real issues, fixed here so the new check starts green:

  • artipacked (4×): actions/checkout persists git credentials in the workspace by default — added persist-credentials: false everywhere; nothing in these workflows pushes back.
  • excessive-permissions (high): release.yml granted contents: write workflow-wide — now read at the top level, with write scoped to the release job only.
  • cache-poisoning (high, 2×): mise-action's cache in an artifact-publishing workflow is a cache-poisoning vector — disabled caching in release.yml (small speed cost, only on releases).
  • superfluous-actions (info): kept action-gh-release for generate_release_notes/asset handling; ignored via .github/zizmor.yml.

Also reformatted renovate.json per oxfmt.

Notes

  • oxlint was considered but it is a JS/TS linter and does not apply to this repo; oxfmt covers the YAML/Markdown formatting.
  • All three checks pass locally against this branch.
  • Touches release.yml in different hunks than ci: add windows arm64 and linux riscv64 release targets #14, so merge order should not matter.

Summary by CodeRabbit

  • Chores

    • Improved release workflow security by limiting permissions and disabling persisted credentials and caching where appropriate.
    • Added automated validation for workflow files.
    • Added tooling for workflow linting, security checks, and formatting.
  • Documentation

    • Added configuration for workflow security checks.
    • Reformatted dependency update configuration without changing its settings.

Add a workflow-lint CI job running actionlint, zizmor, and oxfmt
(YAML/Markdown/JSON format check), all managed via mise.

Fix the issues zizmor found:
- Disable credential persistence on all checkout steps (artipacked)
- Scope contents:write to the release job only (excessive-permissions)
- Disable mise-action caching in release.yml (cache-poisoning)
- Ignore superfluous-actions for action-gh-release via .github/zizmor.yml

Also reformat renovate.json with oxfmt.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds workflow linting with actionlint, zizmor, and oxfmt. It disables persisted checkout credentials, narrows release permissions, disables mise caching, and adds related tool configuration.

Changes

Workflow hardening and validation

Layer / File(s) Summary
Workflow lint toolchain
.github/workflows/ci.yml, .github/zizmor.yml, mise.toml, renovate.json
The CI workflow runs actionlint, zizmor, and oxfmt. Tool versions and zizmor rules are configured. Renovate presets use a single-line array format.
CI checkout credential handling
.github/workflows/ci.yml
The main CI and compile-test checkout steps disable persisted credentials.
Release permissions and setup
.github/workflows/release.yml
The workflow uses read-only global contents access. The release job grants contents: write. Build and publish checkout steps disable persisted credentials, and mise caching is disabled.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI as workflow-lint job
  participant Actionlint
  participant Zizmor
  participant Oxfmt
  CI->>Actionlint: validate workflow files
  CI->>Zizmor: scan workflow files with GITHUB_TOKEN
  CI->>Oxfmt: format-check workflow files
Loading

Possibly related PRs

  • sou1118/typdiff#13: Both pull requests modify the CI and release workflow checkout steps, but this pull request focuses on hardening and linting.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding actionlint, zizmor, and oxfmt CI checks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/workflow-linters

Comment @coderabbitai help to get the list of available commands.

@sou1118

sou1118 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 62: Update the zizmor workflow step to enable strict collection by adding
the --strict-collection option while preserving the existing .github/workflows/
target.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b1e26549-8af9-4f2f-9293-3077325589e6

📥 Commits

Reviewing files that changed from the base of the PR and between 20a752f and baea1d2.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .github/zizmor.yml
  • mise.toml
  • renovate.json

Comment thread .github/workflows/ci.yml
- name: actionlint
run: actionlint
- name: zizmor
run: zizmor .github/workflows/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- workflow context ---'
sed -n '45,75p' .github/workflows/ci.yml
printf '%s\n' '--- zizmor references ---'
rg -n -i 'zizmor|strict-collection' .github README.md 2>/dev/null || true
printf '%s\n' '--- pinned documentation option ---'
curl -fsSL --max-time 20 https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/docs/usage.md \
  | rg -n -C 4 -- '--strict-collection|strict.collection|collection'

Repository: sou1118/typdiff

Length of output: 3257


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- all tracked version/config references ---'
rg -n -i 'zizmor|mise|aqua' --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' . || true

printf '%s\n' '--- v1.28.0 source tree candidates ---'
curl -fsSL --max-time 20 \
  'https://api.github.com/repos/zizmorcore/zizmor/git/trees/v1.28.0?recursive=1' \
  | jq -r '.tree[] | select(.path | test("src/|Cargo.toml|CHANGELOG|release"; "i")) | .path' \
  | head -200

printf '%s\n' '--- tagged source references ---'
for path in \
  src/cli.rs \
  src/main.rs \
  src/args.rs \
  src/collection.rs \
  src/inputs.rs
do
  url="https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/$path"
  body="$(curl -fsSL --max-time 20 "$url" 2>/dev/null || true)"
  if [ -n "$body" ]; then
    printf '%s\n' "--- $path ---"
    printf '%s\n' "$body" | rg -n -C 5 'strict.collection|strict-collection|parse.*fail|collection' || true
  fi
done

Repository: sou1118/typdiff

Length of output: 5468


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- version configuration ---'
cat -n mise.toml

for path in crates/zizmor/src/cli.rs crates/zizmor/src/main.rs crates/zizmor/src/models/inputs.rs; do
  printf '%s\n' "--- $path ---"
  curl -fsSL --max-time 20 \
    "https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/$path" \
    | rg -n -C 8 'strict.collection|strict-collection|collection|parse' || true
done

printf '%s\n' '--- relevant tagged source declarations ---'
for path in crates/zizmor/src/cli.rs crates/zizmor/src/main.rs; do
  curl -fsSL --max-time 20 \
    "https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/$path" \
    | rg -n 'struct|enum|strict|collect|parse|exit|Error' || true
done

Repository: sou1118/typdiff

Length of output: 14596


🏁 Script executed:

#!/bin/bash
set -eu
path=crates/zizmor/src/registry/input.rs
curl -fsSL --max-time 20 \
  "https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/$path" \
  > /tmp/zizmor-input-v1.28.0.rs
printf '%s\n' '--- collector structure ---'
rg -n -C 12 'strict|parse|warn|Syntax|Schema|CollectionError|collect' /tmp/zizmor-input-v1.28.0.rs

printf '%s\n' '--- standalone semantic check ---'
python3 - <<'PY'
from pathlib import Path
s = Path('/tmp/zizmor-input-v1.28.0.rs').read_text()
needles = [
    'if options.strict',
    'tracing::warn!',
    'CollectionError',
]
for needle in needles:
    print(f'{needle}: {s.count(needle)} occurrence(s)')
assert 'if options.strict' in s
assert 'tracing::warn!' in s
print('The collector has separate strict and warning branches.')
PY

Repository: sou1118/typdiff

Length of output: 23875


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
s = Path('/tmp/zizmor-input-v1.28.0.rs').read_text()

syntax = re.search(
    r'Err\(CollectionError::Syntax\(e\)\) if !strict:\s*\{(?P<body>.*?)\n\s*\}\n'
    r'\s*Err\(e @ CollectionError::Schema',
    s, re.S,
)
schema = re.search(
    r'Err\(e @ CollectionError::Schema \{ \.\. \}\) if !strict:\s*\{(?P<body>.*?)\n\s*\}\n'
    r'\s*Err\(e\) => Err\(CollectionError::Inner',
    s, re.S,
)
assert syntax and 'tracing::warn!' in syntax.group('body') and 'Ok(())' in syntax.group('body')
assert schema and 'tracing::warn!' in schema.group('body') and 'Ok(())' in schema.group('body')
assert 'Err(e) => Err(CollectionError::Inner' in s
print('v1.28.0 collector behavior: non-strict syntax/schema errors warn and return Ok(()); strict errors return Err.')

main = Path('/tmp/zizmor-main-v1.28.0.rs')
if not main.exists():
    import urllib.request
    main.write_bytes(urllib.request.urlopen(
        'https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/crates/zizmor/src/main.rs',
        timeout=20,
    ).read())
m = main.read_text()
exit_block = re.search(r'Error::Collection\(err\).*?let exit = if .*?;\s*exit', m, re.S)
assert exit_block
assert 'ExitCode::FAILURE' in exit_block.group()
print('v1.28.0 CLI maps collection errors to a failing process exit.')
PY

Repository: sou1118/typdiff

Length of output: 242


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re, urllib.request

src = Path('/tmp/zizmor-input-v1.28.0.rs').read_text()
for variant in ('Syntax', 'Schema'):
    pattern = rf'Err\(.*CollectionError::{variant}.*\) if !strict\s*=>\s*\{{(?P<body>.*?)\n\s*\}}\n'
    match = re.search(pattern, src, re.S)
    assert match, variant
    body = match.group('body')
    assert 'tracing::warn!' in body and 'Ok(())' in body, variant
assert re.search(r'Err\(e\) => Err\(CollectionError::Inner', src)
print('v1.28.0: non-strict syntax/schema collection errors warn and return Ok(()); strict errors return Err.')

main = Path('/tmp/zizmor-main-v1.28.0.rs')
main.write_bytes(urllib.request.urlopen(
    'https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/crates/zizmor/src/main.rs',
    timeout=20,
).read())
m = main.read_text()
assert 'Error::Collection(err)' in m
assert re.search(r'let exit = if .*?ExitCode::FAILURE', m, re.S)
print('v1.28.0: collection errors map to a failing process exit.')
PY

Repository: sou1118/typdiff

Length of output: 2542


🏁 Script executed:

#!/bin/bash
set -eu
curl -fsSL --max-time 20 \
  https://raw.githubusercontent.com/zizmorcore/zizmor/v1.28.0/crates/zizmor/src/main.rs \
  | sed -n '585,615p'

Repository: sou1118/typdiff

Length of output: 866


Add --strict-collection to the zizmor step.

When a collected input has syntax or schema errors, zizmor 1.28.0 warns and skips it unless strict collection is enabled. Run zizmor --strict-collection .github/workflows/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml at line 62, Update the zizmor workflow step to
enable strict collection by adding the --strict-collection option while
preserving the existing .github/workflows/ target.

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