Skip to content

feat: shellcheck linting phase for run steps in compile pipeline - #49762

Merged
pelikhan merged 16 commits into
mainfrom
copilot/extend-compile-with-linting
Aug 2, 2026
Merged

feat: shellcheck linting phase for run steps in compile pipeline#49762
pelikhan merged 16 commits into
mainfrom
copilot/extend-compile-with-linting

Conversation

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Adds --shellcheck to gh aw compile to run shellcheck on run: step scripts extracted from compiled lock files.

What changes

  • pkg/cli/shellcheck.go — new file with core integration: extracts bash/sh run: steps from lock file YAML, writes each script to a temp file, invokes shellcheck --format=gcc, and suppresses known GitHub Actions false positives by default
  • pkg/cli/compile_config.go — adds Shellcheck bool field
  • pkg/cli/compile_external_tools.go — adds RunShellcheckOnLockFiles public wrapper
  • pkg/cli/compile_pipeline.go — wires shellcheck into both compileSpecificFiles and compileAllFilesInDirectory after compilation
  • pkg/cli/compile_orchestrator.go — warns when --shellcheck --validate is set but the shellcheck binary is not in PATH
  • cmd/gh-aw/main.go — registers --shellcheck CLI flag
  • pkg/cli/mcp_tools_readonly.go — exposes shellcheck in MCP compile tool schema
  • pkg/cli/shellcheck_test.go — unit tests for shell filter, YAML extraction, step label, ignore codes, and binary-unavailable skip

Key behaviours

  • Targets only bash/sh steps; skips pwsh, python, cmd, etc.
  • Uses the system shellcheck binary (no Docker); silently skips when unavailable
  • In --validate mode, emits a warning if shellcheck is not in PATH
  • Default suppressed codes (GitHub Actions false positives):
    • SC2016${{ }} expressions in single-quoted strings
    • SC1090/SC1091 — dynamically sourced scripts not resolvable at lint time
gh aw compile --shellcheck             # lint run steps; skip if shellcheck not installed
gh aw compile --shellcheck --validate  # warn if shellcheck not installed
gh aw compile --shellcheck --strict    # fail compilation on shellcheck findings

Run: https://github.com/github/gh-aw/actions/runs/30750494960

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12 AIC · ⌖ 7.39 AIC · ⊞ 8.3K ·
Comment /souschef to run again


run: https://github.com/github/gh-aw/actions/runs/30751969165

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 11.5 AIC · ⌖ 9.33 AIC · ⊞ 8.3K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 10.7 AIC · ⌖ 5.12 AIC · ⊞ 8.3K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.8 AIC · ⌖ 7.54 AIC · ⊞ 8.3K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title feat: add shellcheck linting phase for run steps in compile pipeline feat: shellcheck linting phase for run steps in compile pipeline Aug 2, 2026
Copilot AI requested a review from pelikhan August 2, 2026 11:04
@pelikhan

pelikhan commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

@copilot --shellcheck should always be enabled by default if available. Add --no-shellcheck flag and flag it as error in strict mode.

…t mode when unavailable

- Rename `Shellcheck bool` to `NoShellcheck bool` in CompileConfig;
  shellcheck now runs by default when available
- Replace `--shellcheck` CLI flag with `--no-shellcheck` to explicitly
  opt out
- In strict mode, return an error if shellcheck is not installed;
  in validate-only mode, emit a warning as before
- Update MCP compile tool schema: `shellcheck` → `no-shellcheck` field
- Fix yamllint test helper to set NoShellcheck=true so it stays
  independent of shellcheck behavior

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot --shellcheck should always be enabled by default if available. Add --no-shellcheck flag and flag it as error in strict mode.

Done. Changes in commit feat: make shellcheck default-on, add --no-shellcheck, error in strict mode when unavailable:

  • Shellcheck now runs by default when the binary is available (removed --shellcheck flag)
  • Added --no-shellcheck flag to opt out
  • In strict mode, absence of the shellcheck binary is now an error (not a warning)
  • In validate-only mode (non-strict), absence of shellcheck still emits a warning
  • Updated the MCP compile tool schema: shellcheckno-shellcheck

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

PR Triage

  • Category:
  • Risk:
  • Priority: (score: 41/100)
    • Impact: 22/50, Urgency: 10/30, Quality: 9/20
  • Recommended action:

Automated triage — see full report issue for details.

Structured data:

{
  "action": "defer",
  "category": "feature",
  "pr_number": 49762,
  "risk": "medium"
}

Generated by 🔧 PR Triage Agent · auto · 73.4 AIC · ⌖ 3.47 AIC · ⊞ 8K ·

@pelikhan
pelikhan marked this pull request as ready for review August 2, 2026 12:56
Copilot AI review requested due to automatic review settings August 2, 2026 12:56
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

Copilot AI left a comment

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.

Pull request overview

Adds shellcheck linting for compiled workflow run: steps, including CLI/MCP wiring and tests.

Changes:

  • Extracts shell scripts from lock files and invokes system shellcheck.
  • Integrates linting into both compilation paths.
  • Adds configuration, CLI/MCP options, and unit tests.
Show a summary per file
File Description
pkg/cli/shellcheck.go Implements extraction and shellcheck execution.
pkg/cli/shellcheck_test.go Tests extraction and shell handling.
pkg/cli/mcp_tools_readonly.go Adds MCP opt-out parameter.
pkg/cli/compile_pipeline.go Runs shellcheck after compilation.
pkg/cli/compile_pipeline_yamllint_test.go Isolates yamllint tests.
pkg/cli/compile_orchestrator.go Checks shellcheck availability.
pkg/cli/compile_external_tools.go Exposes the shellcheck wrapper.
pkg/cli/compile_config.go Adds shellcheck configuration.
pkg/cli/compile_command_test.go Tests configuration defaults.
cmd/gh-aw/main.go Registers the CLI opt-out flag.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 5
  • Review effort level: Balanced

Comment thread cmd/gh-aw/main.go
compileCmd.Flags().Bool("grype", false, "Run grype vulnerability scanner on container images referenced in compiled .lock.yml files (uses Docker image "+cli.GrypeImage+")")
compileCmd.Flags().Bool("grant", false, "Run grant license scanner on container images referenced in compiled .lock.yml files (uses Docker image "+cli.GrantImage+")")
compileCmd.Flags().Bool("yamllint", false, "Run yamllint YAML linter on generated .lock.yml files (uses Docker image "+cli.YamllintImage+")")
compileCmd.Flags().Bool("no-shellcheck", false, "Disable shellcheck linting of run step scripts (shellcheck runs by default when available)")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The maintainer explicitly requested shellcheck to be default-on with --no-shellcheck as the opt-out (see @pelikhan's comment: "shellcheck should always be enabled by default if available. Add --no-shellcheck flag"). The --no-shellcheck flag at cmd/gh-aw/main.go:778 and the NoShellcheck bool field in CompileConfig implement exactly that: shellcheck runs automatically when available, with --no-shellcheck to disable it. This is an intentional design change from the original opt-in proposal.

Comment thread pkg/cli/compile_orchestrator.go Outdated
}

// Warn or error when shellcheck is enabled (the default) but not installed.
if !config.NoShellcheck && !isShellcheckAvailable() {
Comment thread pkg/cli/shellcheck.go Outdated
Comment on lines +129 to +130
shell, _ := step["shell"].(string)
if !isShellcheckableShell(shell) {
Comment thread pkg/cli/shellcheck.go
Comment on lines +170 to +173
for _, code := range ignoreCodes {
args = append(args, "--exclude="+code)
}
args = append(args, tmpFile.Name())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in a previous commit by adding sanitizeGHAExpressions() which replaces every ${{ ... }} expression with the identifier __GHA_EXPR__ before passing the script to shellcheck. This prevents SC1073/SC1083 parse errors while keeping the script structurally valid shell. SC2016 is retained as a safety net for any edge cases the regex might miss.

Comment thread pkg/cli/shellcheck.go Outdated
Comment on lines +185 to +188
// Display findings – replace the temp file path with the lock file for clarity.
output := strings.ReplaceAll(stdout.String(), tmpFile.Name(), filepath.Base(info.LockFile))
if stderr.Len() > 0 {
output += strings.ReplaceAll(stderr.String(), tmpFile.Name(), filepath.Base(info.LockFile))
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 85/100 — Excellent

Analyzed 7 test(s): 6 design, 1 implementation, 0 violation(s).

📊 Metrics (7 tests)
Metric Value
Analyzed 7 (Go: 7, JS: 0)
✅ Design 6 (85.7%)
⚠️ Implementation 1 (14.3%)
Edge/error coverage 6 (85.7%)
Duplicate clusters 0
Inflation No (178 test / 277 prod = 0.64)
🚨 Violations 0
Test File Classification Coverage
TestIsShellcheckableShell shellcheck_test.go:15 design_test, high_value 8 subtests covering bash, sh, pwsh, powershell, python, cmd, case-insensitivity
TestShellcheckShell shellcheck_test.go:43 design_test, high_value 4 assertions verifying shell flag argument mapping
TestExtractRunStepsFromLockFile shellcheck_test.go:52 design_test, high_value 6 subtests: positive extraction, empty runs, missing jobs, multi-job, file errors, YAML parse errors
TestStepLabel shellcheck_test.go:132 implementation_test, medium_value 2 subtests on diagnostic label formatting
TestDefaultIgnoreCodes shellcheck_test.go:147 design_test, high_value 3 assertions verifying shellcheck false-positive codes are defined
TestRunShellcheckOnLockFilesSkipsWhenUnavailable shellcheck_test.go:156 design_test, high_value Tests graceful degradation when shellcheck binary is missing
TestRunShellcheckOnLockFilesEmpty shellcheck_test.go:166 design_test, high_value Tests handling of empty file list

Verdict

passed. 14.3% implementation tests (threshold: 30%). Test suite covers core design invariants: shell detection rules, YAML parsing, error conditions, and graceful degradation when tools are unavailable. Edge cases well-represented via table-driven subtests and explicit error assertions. No violations detected.

🧪 Test quality analysis by Test Quality Sentinel · haiku45 · 19 AIC · ⌖ 5.4 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

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.

✅ Test Quality Sentinel: 85/100. 14.3% implementation tests (threshold: 30%). All tests verify design invariants with good edge-case coverage and no violations.

…ipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pelikhan

pelikhan commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

@copilot resolve the merge conflicts on this branch.

Copilot AI and others added 2 commits August 2, 2026 15:54
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…d playwright-cli line)

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Resolved. Merged origin/main into the branch (commit 79f1058) — the only conflicts were in two generated .lock.yml files (daily-multi-device-docs-tester and unbloat-docs). Accepted main's versions and recompiled all 268 workflows. Also fixed a garbled playwright-cli line in daily-multi-device-docs-tester.md that was causing a SC2241 shellcheck error (commit 1ef3d53). All 268 workflows now compile cleanly with no shellcheck findings.

…e-with-linting

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts on this branch.

The branch is up to date with origin/main. Merged the latest commit (9eb50e1 — typeutil lookup.go refactor) with no conflicts. All 268 workflows still compile cleanly.

@pelikhan

pelikhan commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix https://github.com/github/gh-aw/actions/runs/30756567646/job/91520102453#step:9:1

Fixed in commit 4ef0d9f. The root cause: the MCP compile handler was spawning compile --validate --json without --no-shellcheck. On Windows CI where shellcheck is not installed, this triggered the "shellcheck not found" warning path in the orchestrator. While the warning only writes to stderr (which should be benign), the subprocess was exiting with no JSON output.

The fix: always pass --no-shellcheck in the MCP compile handler's base cmdArgs. This is architecturally correct regardless of the root cause — shellcheck output goes to stderr (captured in the subprocess error buffer), so shellcheck findings never surface in the JSON response visible to the LLM. Shellcheck is a local CLI linting tool and has no useful role in MCP mode.

Changes in pkg/cli/mcp_tools_readonly.go:

  • Base cmdArgs changed from ["compile", "--validate", "--json"] to ["compile", "--validate", "--json", "--no-shellcheck"]
  • Removed NoShellcheck field from compileArgs schema (no longer needed)
  • Removed the if args.NoShellcheck { ... } conditional block
  • Updated log message to remove the no-shellcheck field

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please continue triage on this PR.

Remaining reviewer-visible blockers:

  • requested-changes reviews remain on shellcheck behavior and UX concerns (strict mode behavior, noisy output, opt-in vs opt-out consistency, shared helper extraction, and missing strict-mode coverage)
  • latest maintainer comment asks you to fix the failing Actions job: https://github.com/github/gh-aw/actions/runs/30756567646/job/91520102453#step:9:1
  • after addressing the failing job and reviewer feedback, run the pr-finisher skill and leave a concise maintainer handoff

Run details: https://github.com/github/gh-aw/actions/runs/30758413653

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 10.7 AIC · ⌖ 5.12 AIC · ⊞ 8.3K ·
Comment /souschef to run again

@pelikhan

pelikhan commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Copilot AI and others added 2 commits August 2, 2026 17:32
…r-code-quality-reviewer

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
…reviewer

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please continue triage on this PR.

Remaining reviewer-visible blockers:

  • recent maintainer request asks you to fix the failing Actions job: https://github.com/github/gh-aw/actions/runs/30758672352/job/91525636859
  • requested-changes review feedback still remains visible around shellcheck behavior and UX; close out any still-open thread follow-up on the current head
  • after the failing job and review follow-up are addressed, run the pr-finisher skill and leave a concise maintainer handoff

Branch refresh was requested for this PR.

Run details: https://github.com/github/gh-aw/actions/runs/30759528407

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.8 AIC · ⌖ 7.54 AIC · ⊞ 8.3K ·
Comment /souschef to run again

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix https://github.com/github/gh-aw/actions/runs/30758672352/job/91525636859

Both failures in that run are fixed in commits b0fa7ba and a263a42:

  1. lint-go / tolowerequalfold — replaced strings.ToLower(shell) == with strings.EqualFold in pkg/cli/shellcheck.go
  2. Unit tests (M-R) / TestPRCodeQualityReviewerWorkflowSubAgentModelContract — updated model: claude-haiku-4.5model: small in pr-code-quality-reviewer.md to match the contract test

Both pass locally. CI needs a re-trigger to confirm on the new HEAD.

@pelikhan
pelikhan merged commit c2d74ef into main Aug 2, 2026
30 of 31 checks passed
@pelikhan
pelikhan deleted the copilot/extend-compile-with-linting branch August 2, 2026 18:00
Copilot stopped work on behalf of gh-aw-bot due to an error August 2, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants