Skip to content

feat: lint workflows during compilation by default - #71349

Merged
pelikhan merged 7 commits into
mainfrom
pelikhan-expert-disco
Oct 23, 2026
Merged

pelikhan merged 7 commits into
mainfrom
pelikhan-expert-disco

Conversation

@pelikhan

@pelikhan pelikhan commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Run built-in Actions/AW AST linting by default during CLI compilation, before emitting lock files. This closes a validation gap exposed by shell injection in the downstream haiku-printer workflow, which is also fixed here.

  • Check generated Actions graphs and authored AW source, including --no-emit and recompilation through add, update, and validate. Lint errors fail compilation; ordinary warnings remain advisory.
  • Add gh aw compile --skip-lint and MCP skip_lint. These disable only this lint pass, retain existing compiler validation, and are rejected with --dry-run.
  • Honor effective CLI/repository strictness, active threat-rule suppressions, and --allow-action-refs without accepting malformed references or mutating retained source.
  • Support sandbox shorthands, object-form imports.aw, and generated cache-mode, with regressions for normal, no-emit, and dry-run compilation.
  • Preserve the low-level Go API's opt-in behavior through workflow.WithLint(true).
  • Print dispatched haiku messages through an environment variable and a fixed printf format rather than interpolating them into Bash.

Compatibility and coverage

Breaking default: Workflows with lint errors can no longer compile by default. Run gh aw compile --no-emit, fix findings in the authored source, then rerun the original command. --skip-lint is a per-compilation escape hatch available only through compile, not a persistent bypass for other recompiling commands.

Compile-time linting does not require a native JavaScript parser. Deeper authored JavaScript driver and custom-grader analysis requires standalone gh aw lint --javascript-module <module-path>. Secret-leak coverage warnings and unavailable-parser grader-file-io warnings are excluded from compiler warning totals; analysis errors and actual findings remain blocking according to severity. Native Actions YAML and downstream dispatch targets still require standalone linting.

ADR: ADR-71349: Run Built-in Actions/AW AST Lint During Compilation by Default

Validation

  • Merged main at 9084a8c765 using make merge-main. Build, regeneration, and formatting passed; all 348 workflows compiled without generated lock-file changes.
  • Focused compiler, CLI, MCP, action-reference, strictness, sandbox, import, and taint regressions passed, along with all five haiku tests.
  • Native/WASM builds, standard Go lint, JavaScript lint, schema checks, and impacted Go tests passed.
  • Remaining gate failure: make agent-report-progress reports pre-existing custom Go-linter findings in unchanged code in cmd/gh-aw/main.go, pkg/cli/compile_compiler_setup.go, and pkg/cli/compile_development.go.
  • Optional native JavaScript integration tests were skipped because their parser module is not installed.
  • Official macOS ARM64 Copilot CLI 1.0.101 was independently verified against the pinned checksum manifest and its version output confirmed. Hosted Linux installation remains unverified.

All eight requested inline review threads have been answered and resolved. Latest published commit: 46a2d63098.

The full hosted smoke-copilot run remains unperformed: its downstream dispatch targets the default branch, so the receiver fix must land there first. No workflow was manually dispatched or CI manually triggered.

Pass the message through the step environment and preserve literal input in logs and summaries. Add regression coverage for shell syntax, multiline messages, and printf metacharacters.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Run the built-in Actions/AW AST rules before CLI compilation emits a lock file, with --skip-lint and the corresponding MCP option. Preserve compiler validation and reject the opt-out for dry-run compilation. Keep low-level compiler callers opt-in to preserve their existing API contract.

Support generated cache-mode in the Actions AST and valid sandbox shorthand forms in authored secret analysis. Add regression coverage, CLI documentation, and a breaking-change migration note.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan pelikhan changed the title fix: prevent shell injection in haiku dispatch messages feat: lint workflows during compilation by default Oct 23, 2026
@pelikhan
pelikhan marked this pull request as ready for review October 23, 2026 06:08
Copilot AI max review requested due to automatic review settings October 23, 2026 06:08
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Test Quality Sentinel · sonnet50 · ~15 AIC · ⌖ ~16 AIC · ◇ ~7 AIC · ⊞ 12.6K · ◷

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Ponytail Reviewer

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Ponytail Reviewer · gpt56 · ~9 AIC · ⌖ ~7 AIC · ⊞ 14.8K · ◷

Generated by Ponytail Reviewer for #71349

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

Commit pushed: b55dccd

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@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.

Review summary

No actionable blocking issues found in the changed lines. The changes consistently wire default AST linting, the explicit opt-out, and the shell-injection regression coverage. This was a static review; tests were not executed. The specialist pass was unavailable because its file-read invocation was rejected, so this verdict is based on the independent review only.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · ~2 AIC · ⌖ ~1 AIC · ⊞ 1.6K
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR adds 340 new lines in business logic directories (pkg/, threshold 100) but has no linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/71349-run-built-in-ast-lint-during-compilation-by-default.md. Please review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

Decision recorded in the draft: CLI and MCP compilation now run the built-in Actions/AW AST lint by default, before lock-file emission and also with --no-emit. Lint errors fail the build. --skip-lint / skip_lint is the narrow opt-out and is rejected under dry-run. workflow.WithLint stays opt-in for Go API callers.

📋 What to do next
  1. Review the draft ADR committed to your branch. It was generated from the PR diff.
  2. Complete the missing sections. Add context that could not be inferred from the diff, refine the rationale, and check the alternatives. One alternative's rationale is marked [TODO: verify].
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-71349: Run Built-in Actions/AW AST Lint During Compilation by Default

Once an ADR is linked in the PR body, this gate will re-run and check that the implementation matches the decision.

❓ Why ADRs Matter

ADRs keep a searchable, permanent record of why the codebase looks the way it does. This PR makes a breaking change to a default (major changeset), so recording the trade-offs matters.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context: What is the problem? What forces are at play?
  • Decision: What did you decide? Why?
  • Alternatives Considered: What else could have been done?
  • Consequences: What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · opus55 · ~30 AIC · ⌖ ~41 AIC · ⊞ 1.9K · ◷
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.

Skills-Based Review 🧠

Applied /codebase-design and /tdd to the two most behavior-sensitive hunks: the new default compile-time lint pass and the sandbox-shorthand handling in authored taint analysis. Triage via pr-triage was not invoked (small, well-scoped diff fit a direct read); classification follows the fallback heuristic against pr-meta.json/pr-diff.patch, prioritizing pkg/workflow/compiler_lint.go, pkg/cli/mcp_tools_readonly.go, and pkg/workflow/taint/authored_scripts.go by change size and risk.

📋 Key Themes & Highlights

Key Themes

  • Lint coverage parity gap: lintCompiledWorkflow never passes JavaScript options into workflowlint.Input, so JS-driver-aware rules (secret-leak, grader-file-io) run with reduced fidelity at compile time vs. standalone gh aw lint. Not necessarily wrong, but undocumented and worth an explicit decision.
  • Sandbox shorthand short-circuit: the new early returns in authoredScriptEnvironment silently skip the sandbox.agent.env overlay for bool-typed agent fields that previously triggered a type error — a quiet behavior widening that should get an explicit regression test.

Positive Highlights

  • ✅ --skip-lint is well-guarded: blocked under --dry-run at both the CLI (validateDevelopmentCompileMode) and MCP (registerCompileTool) layers, with matching tests in both places.
  • ✅ Strong regression coverage for the haiku-printer fix: parameterized tests exercise shell metacharacters, quotes, and empty-string edge cases against the actual generated run: script.
  • ✅ compiler_lint_test.go covers both the vulnerable and fixed workflow shapes, threat-suppression honoring, warning-vs-error severity split, and emission ordering (TestCompilerLintRunsBeforeEmission) — solid TDD-style coverage for the new pass.
  • ✅ Clear .changeset and docs updates matching the new default behavior and opt-out flag.

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · ~60 AIC · ⌖ ~16 AIC · ⊞ 10.2K
Comment /matt to run again

Comment thread pkg/workflow/compiler_lint.go
Comment thread pkg/workflow/taint/authored_scripts.go

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.

🟡 Changes recommended

Default linting rejects supported workflow configurations and does not consistently honor existing compiler policy and CLI options.

6 open issues
What changed in this PR

This PR moves existing Actions/AW lint checks into gh-aw’s compilation pipeline and fixes shell injection in the haiku dispatch receiver.

Changes:

  • Enables built-in linting before lock-file emission, with CLI/MCP opt-outs and a low-level Go opt-in.
  • Passes dispatched messages through an environment variable and adds literal-output regressions.
  • Extends AST compatibility and documents the breaking default and migration options.
File Description
pkg/​workflow/​taint/​authored_scripts.go Handles sandbox shorthands during environment analysis.
pkg/​workflow/​taint/​authored_scripts_test.go Tests shorthand environment handling.
pkg/​workflow/​compiler.go Runs lint before returning generated YAML.
pkg/​workflow/​compiler_types.go Stores the compiler lint setting.
pkg/​workflow/​compiler_options.go Adds WithLint.
pkg/​workflow/​compiler_lint.go Integrates lint diagnostics and suppressions.
pkg/​workflow/​compiler_lint_test.go Covers lint failures, warnings, and emission behavior.
pkg/​workflow/​actions/​workflow.go Adds AST storage for cache mode.
pkg/​workflow/​actions/​parse.go Parses cache mode into the AST.
pkg/​workflow/​actions/​parse_test.go Tests cache-mode parsing.
pkg/​workflow/​actions/​lower.go Preserves cache mode during emission.
pkg/​cli/​mcp_tools_readonly.go Exposes and forwards skip_lint.
pkg/​cli/​mcp_tools_output_streams_test.go Tests MCP opt-out forwarding and dry-run rejection.
pkg/​cli/​compile_development.go Rejects skipping lint during dry-run compilation.
pkg/​cli/​compile_config.go Adds the CLI lint opt-out setting.
pkg/​cli/​compile_compiler_setup.go Enables linting through shared compiler setup.
pkg/​cli/​compile_compiler_setup_test.go Tests defaults, opt-out, and retained validation.
docs/​src/​content/​docs/​setup/​cli.md Documents the new flag and default behavior.
docs/​src/​content/​docs/​reference/​compilation-process.md Explains lint integration and scope.
cmd/​gh-aw/​main.go Registers and propagates --skip-lint.
cmd/​gh-aw/​compile_flags_test.go Tests flag defaults and configuration mapping.
actions/​setup/​js/​haiku_printer_workflow.test.cjs Verifies literal message output through Bash.
.github/​workflows/​haiku-printer.yml Removes direct message interpolation from shell source.
.changeset/​compile-default-ast-lint.md Announces the breaking default and migration guidance.

Review effort: Max

Comment thread pkg/cli/compile_compiler_setup.go
Comment thread pkg/workflow/compiler_lint.go
Comment thread pkg/workflow/compiler_lint.go
Comment thread pkg/workflow/compiler_lint.go Outdated
Comment thread pkg/workflow/compiler_lint.go
Comment thread pkg/workflow/compiler_lint.go
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot address the following outstanding work in one pass:

  1. Update this branch with the latest main using make merge-main, resolving any conflicts and preserving the intended changes.
  2. Review (pkg/workflow/compiler_lint.go:22): [/codebase-design] The compile-time lint pass omits JavaScript from workflowlint.Input, unlike standalone gh aw lint (see pkg/cli/lint_command.go). This silently degrades secret-leak and grader-file-io coverage for authored JS drivers during default compilation — the exact kind of hook this PR is meant to catch by default. - feat: lint workflows during compilation by default #71349 (comment)
  3. Review (pkg/workflow/taint/authored_scripts.go:257): [/tdd] The new sandbox shorthand short-circuit returns the current bindings as soon as sandbox is a bare \"awf\"/\"default\" string or sandbox.agent is nil/a string/bool, silently skipping the sandbox.agent.env overlay. This is a behavior change from erroring on type mismatch to quietly accepting the value — worth a test asserting the previous error-on-bad-type behavior wasn't accidentally widened. - feat: lint workflows during compilation by default #71349 (comment)
  4. Review (pkg/cli/compile_compiler_setup.go:102): Default linting is inconsistent across CLI compilation paths. gh aw add constructs compilers directly in add_workflow_compilation.go:36,101, without WithLint(true), so it can emit a lock that the default compile command rejects. Conversely, commands such as update and validate use this factory with SkipLint left false but expose no opt-out; running compile --skip-lint first does not bypass their recompilation. Define a consistent CLI contract: enable linting in the add paths and either propagate the opt-out to recompiling commands or explicitly document their exceptions and mig... - feat: lint workflows during compilation by default #71349 (comment)
  5. Review (pkg/workflow/compiler_lint.go:24): The default registry rejects the supported sandbox: awf and sandbox: default shorthands. SourceDocument retains these strings, but SandboxConfigRule calls authoredPolicyMapping(..., \"sandbox\"), which returns AST policy lint requires a mapping at sandbox. That analysis error now prevents lock-file emission for otherwise valid workflows, including with --no-emit. The new handling in authoredScriptEnvironment only fixes the taint analyzer. Accept both shorthands in the sandbox policy rule and add lint-enabled compilation regressions, including dry-run mode where --skip-lint is u... - feat: lint workflows during compilation by default #71349 (comment)
  6. Review (pkg/workflow/compiler_lint.go:28): Valid object-form imports now cause a compile failure when the source also contains a tools mapping. The schema and parser accept imports: {aw: [...]}, but tool-scope calls authoredImportsPending, which accepts only lists and returns authored policy requires an imports list for this mapping. This branch turns that rule failure into a hard compilation error. Teach the shared helper to inspect imports.aw, including an empty or absent list, and add a lint-enabled compilation regression. Do not downgrade all analysis failures to hide this unsupported input shape. - feat: lint workflows during compilation by default #71349 (comment)
  7. Review (pkg/workflow/compiler_lint.go:32): A valid custom grader such as graders.quality.script: 'return 1;' now blocks dry-run compilation. This pass never supplies Input.JavaScript, so grader-file-io emits an unavailable-parser warning for every custom JavaScript grader. Counting that warning makes appendDevelopmentCompilerDiagnostics fail the dry-run gate. The suggested --javascript-module option exists only on lint, while dry-run rejects --skip-lint, so users cannot satisfy the check through compile options. Exclude these unavailable-analysis warnings from the compiler warning count, as for secret-leak, or provide a... - feat: lint workflows during compilation by default #71349 (comment)
  8. Review (pkg/workflow/compiler_lint.go:46): Default linting defeats --allow-action-refs under the default strict policy. When resolution fails, that flag lets the pinning code warn and retain a mutable reference such as owner/actionv1. The new action-pin check then derives error severity from the authored document and this branch fails compilation anyway. This contradicts the flag's promise to allow unresolved refs with warnings; validate --allow-action-refs also has no --skip-lint workaround. Pass the allowance into the lint policy so permitted unresolved mutable refs remain warnings, without downgrading malformed references,... - feat: lint workflows during compilation by default #71349 (comment)
  9. Review (pkg/workflow/compiler_lint.go:24): The lint input uses authored strictness rather than the compiler's effective policy. With strict: false in the source and strict mode enforced by --strict or repository configuration, workflow-run-scope still reports wildcard-only branches as a warning. For example, workflow_run with workflows: [Build] and branches: ['*'] passes ordinary compilation: the existing compiler validator checks only that branches exists. Apply effective strictness to an independent lint document, preserving the retained source, and cover both override paths. - feat: lint workflows during compilation by default #71349 (comment)

Push the necessary fixes, reply to each listed review thread and resolve it when addressed. Ignore feedback already answered or resolved. Use the pr-finisher skill and stop when only human review or CI remains; do not trigger CI.

Sous-chef head: b55dccd
Sous-chef work: 0322d33b3e88e00db544e494a4cf971fbe683cb3e1d3866a3bd7df04cfbf88ae 4a9b25dd9526b00afbbdbca444fc387ac38af34539beac0a7523ed1a79e4bb51 64811c1a0604598d32c7f300f3c7016715bd72cee66f2e1d442a725c3e3a69f4 7c42c8c5da27a82b7929edff5097730c02e30d8653ffef1bee472d5fe924fa96 853336bbbb6637f103edc5720528bea4f4401976904cfbd6723cdfe8010d58c9 8611aaf58b120479cd4e4cb1b4c72d2d53375199edad526325be59b34e408f69 e4da6744b0061fd4426c578690f6a72e715f1a1ac85579a778429cbdd5556a55 f6b1104c6c72342427a28c4d7fcfe300a7b610c59797ef46778fe002b9cb9592
Sous-chef state: 78ece1f0b3f252798fa0df7d0de8f265025833c9f3868c171a30219f0874cb54

Generated by 👨‍🍳 PR Sous Chef · pi · haiku45 · ~6 AIC · ⌖ ~7 AIC · ⊞ 1.1K · ◷
Comment /souschef to run again

Copilot AI and others added 2 commits October 23, 2026 07:35
…lt lint

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

Copilot AI commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@copilot address the following outstanding work in one pass:

  1. Update this branch with the latest main using make merge-main, resolving any conflicts and preserving the intended changes....

Pushed 93a1770 and bfd4670 and replied once to each of the eight listed review threads. make merge-main confirmed the latest main is already included and completed its build/recompile/format steps. The fixes cover CLI consistency, supported sandbox/import shapes, JavaScript coverage documentation and nonblocking parser warnings, action-reference allowances, and effective strictness.

Focused regressions, impacted Go tests, the five haiku tests, standard Go lint, and schema checks passed. The required gate still fails on the previously reported custom-linter findings in unchanged code; the newly introduced function-length finding was fixed. Supplemental code review found no high-confidence issues. Automated review was unavailable, and CodeQL skipped the oversized database.

No CI was triggered. Thread resolution needs a maintainer: this environment can post replies but exposes no resolve-thread operation, and shell GitHub access is unauthenticated. Final HEAD is bfd4670; CI on that revision remains unverified and needs a maintainer re-trigger.

pelikhan and others added 2 commits October 23, 2026 07:18
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise supported workflow shapes under normal, no-emit, and dry-run compilation and preserve malformed-input failures. Finalize ADR-71349 and document the per-compilation migration escape hatch.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): acknowledged as an informational review completion, not a separate code-change request. The two actionable inline findings from this review were evaluated and addressed individually.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): no code change is warranted by this informational reported_no_action result. Validation for this batch is based on executed focused regressions, not the sentinel's completion status.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): no code change is warranted by this informational reported_no_action result. It is not being treated as evidence that validation or publication succeeded.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): acknowledged as an informational review completion with no additional actionable finding. The separate correctness findings were handled through their individual inline threads.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): accepted the generated ADR as a starting point and reviewed it against the implementation. The revised ADR records the compilation contract and its coverage and migration trade-offs, and is linked from the PR description.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): accepted and completed the ADR's rationale, alternatives, consequences, and status metadata, and linked ADR-71349 from the PR body. It explicitly records limited JavaScript coverage and the compile-only opt-out.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): accepted the aggregate request and integrated latest main with make merge-main, checked the eight inline findings, and pushed the combined batch in 46a2d63. Each inline thread has an individual disposition; no workflow dispatch or manual CI trigger was performed.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71349 (comment): the earlier fixes and validation report were independently checked rather than treated as proof of completion. This batch supplements the remaining regression and ADR gaps and verifies publication; the required repository gate still reports pre-existing custom-linter findings in unchanged code.

@pelikhan
pelikhan merged commit 88cc982 into main Oct 23, 2026
123 checks passed
@pelikhan
pelikhan deleted the pelikhan-expert-disco branch October 23, 2026 14:40
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.93.3

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.

4 participants