Skip to content

fix(ci): quote GITHUB_OUTPUT/STEP_SUMMARY redirects (SC2086) + add actionlint/shellcheck gate for workflow templates - #1557

Merged
tamirdresher merged 1 commit into
github:devfrom
serbrech:serbrech-shiny-fishstick
Jul 31, 2026
Merged

tamirdresher merged 1 commit into
github:devfrom
serbrech:serbrech-shiny-fishstick

Conversation

@serbrech

@serbrech serbrech commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

What

Downstream repos that run actionlint + shellcheck in CI started failing after squad upgrade, because Squad's bundled workflow templates redirect to unquoted $GITHUB_OUTPUT / $GITHUB_STEP_SUMMARY in run: blocks — shellcheck SC2086 ("double quote to prevent globbing and word splitting").

Since squad upgrade regenerates these files wholesale, any downstream fix gets reverted on the next upgrade. So the fix has to land in the templates, and Squad's own CI has to lint them so it cannot ship again.

Changes

SC2086 fixes (unquoted >> $GITHUB_* redirects)

Templates (the squad upgrade source of truth):

  • .squad-templates/workflows/squad-heartbeat.yml (canonical source)
  • templates/workflows/squad-heartbeat.yml (root mirror)
  • packages/squad-cli/templates/workflows/squad-heartbeat.yml
  • packages/squad-sdk/templates/workflows/squad-heartbeat.yml

Squad's own workflows (same bug class, found by the new gate):

  • .github/workflows/squad-heartbeat.yml — 2 occurrences
  • .github/workflows/squad-repo-health.yml — 10 occurrences across 4 run: blocks
  • .github/workflows/squad-ci.yml — 13 $GITHUB_STEP_SUMMARY occurrences across 5 gate steps

Purely additive quoting — no behaviour change.

New CI gate

.github/workflows/squad-workflow-lint.yml — actionlint 1.7.12 + shellcheck 0.10.0, linting all five workflow/template directories, including the .squad-templates/ canonical source and the templates/ root mirror (not just the packages/* mirrors — a canonical-only edit would otherwise ship unlinted, since this job does not run the template sync).

Notes on hardening:

  • The actionlint installer is fetched from the v1.7.12 tag ref, not main, to avoid a moving-ref RCE surface in CI.
  • ubuntu-latest ships shellcheck 0.9.0; 0.10.0 is installed explicitly to match the version that surfaced the original report.
  • Lints committed state rather than sync-then-lint, so a bug in the canonical source is caught before it propagates. Mirror drift is already covered separately by template-sync.test.ts.
  • Triggered on PR/push with paths: filters so it stays off unrelated changes.

Verification

The proof is this PR's own CI run — actionlint could not be executed locally (no Go/Docker, and npm install failed on SSL in the authoring environment), so the pre-merge check is the real validation rather than a local probe.

What is NOT in this PR

Part 2 of #1556 — squad upgrade clobbering actions/checkout v7 -> v4 — is deliberately deferred to a follow-up PR. It is a more involved change to the upgrade/template-write path (arguably overlapping #1502) and does not belong in a lint fix.

Refs #1556


Working as Booster (CI/CD Engineer)

Copilot AI review requested due to automatic review settings July 29, 2026 07:40
@github-actions

github-actions Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 6d8cab5

PR Scope: 🔧 Infrastructure

⚠️ 2 item(s) to address before review

Status Check Details
✅ Single commit 1 commit — clean history
✅ Not in draft Ready for review
✅ Branch up to date Up to date with dev
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean ⚠️ PR includes 1 .squad/ file(s) — ensure these are intentional
✅ No merge conflicts No merge conflicts
✅ Copilot threads resolved 0 active Copilot thread(s) resolved (3 outdated skipped)
❌ CI passing 10 check(s) still running

Files Changed (12 files, +236 −37)

File +/−
.changeset/fix-workflow-shellcheck-quoting.md +21 −0
.github/actionlint.yaml +18 −0
.github/workflows/size-regression-report.yml +0 −1
.github/workflows/squad-ci.yml +13 −13
.github/workflows/squad-heartbeat.yml +2 −2
.github/workflows/squad-repo-health.yml +13 −13
.github/workflows/squad-workflow-lint.yml +94 −0
.squad-templates/workflows/squad-heartbeat.yml +2 −2
.squad/agents/booster/history.md +67 −0
packages/squad-cli/templates/workflows/squad-heartbeat.yml +2 −2
packages/squad-sdk/templates/workflows/squad-heartbeat.yml +2 −2
templates/workflows/squad-heartbeat.yml +2 −2

Total: +236 −37


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

@github-actions

github-actions Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #1557

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 12
Files added 3
Files modified 9
Files deleted 0
Modules touched 6

🎯 Risk Factors

  • 12 files changed (6-20 → MEDIUM)
  • 6 modules touched (5-8 → HIGH)

📦 Modules Affected

ci-workflows (6 files)
  • .github/actionlint.yaml
  • .github/workflows/size-regression-report.yml
  • .github/workflows/squad-ci.yml
  • .github/workflows/squad-heartbeat.yml
  • .github/workflows/squad-repo-health.yml
  • .github/workflows/squad-workflow-lint.yml
root (2 files)
  • .changeset/fix-workflow-shellcheck-quoting.md
  • templates/workflows/squad-heartbeat.yml
squad-cli (1 file)
  • packages/squad-cli/templates/workflows/squad-heartbeat.yml
squad-sdk (1 file)
  • packages/squad-sdk/templates/workflows/squad-heartbeat.yml
squad-state (1 file)
  • .squad/agents/booster/history.md
templates (1 file)
  • .squad-templates/workflows/squad-heartbeat.yml

This report is generated automatically for every PR. See #733 for details.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Squad File Leakage Detected

The following .squad/ files were modified in this PR:

  • .squad/agents/booster/history.md

These files affect team routing, agent charters, and decisions.
If intentional, ensure approval from the team lead.

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

Fixes shellcheck SC2086 regressions in generated Squad workflow templates (and Squad’s own workflows) by quoting $GITHUB_OUTPUT / $GITHUB_STEP_SUMMARY redirect targets, and adds a dedicated CI gate to prevent these regressions from shipping again (refs #1556).

Changes:

  • Quote >> "$GITHUB_OUTPUT" / >> "$GITHUB_STEP_SUMMARY" across the heartbeat template mirrors and affected in-repo workflows to satisfy shellcheck SC2086.
  • Add .github/workflows/squad-workflow-lint.yml to run actionlint + shellcheck against both live workflows and all template workflow directories.
  • Add a changeset for the CLI/SDK template updates.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.squad-templates/workflows/squad-heartbeat.yml Canonical template: quote $GITHUB_OUTPUT redirects in run: block.
templates/workflows/squad-heartbeat.yml Root mirror: keep heartbeat template in sync with canonical quoting fix.
packages/squad-cli/templates/workflows/squad-heartbeat.yml CLI mirror: propagate quoting fix to shipped template.
packages/squad-sdk/templates/workflows/squad-heartbeat.yml SDK mirror: propagate quoting fix to shipped template.
.github/workflows/squad-heartbeat.yml In-repo workflow: quote $GITHUB_OUTPUT redirects to satisfy shellcheck.
.github/workflows/squad-repo-health.yml In-repo workflow: quote $GITHUB_OUTPUT redirects (multiline output + exit code).
.github/workflows/squad-ci.yml In-repo workflow: quote $GITHUB_STEP_SUMMARY redirects in gate steps.
.github/workflows/squad-workflow-lint.yml New CI workflow: actionlint + shellcheck gate across workflows and all template workflow directories.
.changeset/fix-workflow-shellcheck-quoting.md Changeset documenting the template/workflow quoting fixes and new lint gate.
.squad/agents/booster/history.md Agent history entry documenting the change and follow-up adjustments.

- name: Install actionlint 1.7.12 and shellcheck 0.10.0
run: |
# Installer pinned to v1.7.12 tag — not `main` — to avoid moving-ref RCE surface.
bash <(curl -sL https://raw.githubusercontent.com/rhysd/actionlint/v1.7.12/scripts/download-actionlint.bash) 1.7.12
Comment thread .squad/agents/booster/history.md Resolved
@serbrech
serbrech force-pushed the serbrech-shiny-fishstick branch from ae647cb to c277d37 Compare July 29, 2026 09:22
serbrech added a commit to serbrech/squad that referenced this pull request Jul 29, 2026
…ories

Scribe maintenance pass produced during the issue github#1556 work. Split out of
PR github#1557 so that PR stays scoped to the shellcheck/actionlint gate. No product
code, no workflows, no templates — .squad/ team state only.

Decision inbox merged into decisions.md (6 entries), inbox cleared:
  - booster-ci-deletion-guard
  - retro-copilot-git-safety
  - flight-versioning-policy
  - booster-release-skill-v094
  - procedures-fix-coordinator-inline-dispatch-gate
  - booster-workflow-template-linting (new)
decisions.md 12151 -> 16030 bytes; still under the 20KB archival threshold, so
no entries were archived.

Agent histories summarized (all were over the 15KB threshold):
  eecom 33933 -> 5770, pao 30999 -> 5556, _alumni/kobayashi 26305 -> 3489,
  flight 23236 -> 5661, fido 22844 -> 6007, procedures 18945 -> 4082
This accounts for the ~1700 deleted lines — compaction of team memory, not lost
work; prior content remains in git history.

Cross-agent updates appended to fido (new CI quality gate) and surgeon
(changeset landed; new lint job affects release gating), plus a RETRO history
entry covering the security-scanner scoping fix in PR github#1559.

Blocked on github#1559: the unsafe-git scanner flags decisions.md prose that
documents the `git add .` prohibition. That fix cannot ship here because
squad-repo-health.yml uses pull_request_target and checks out the base branch
for trusted scripts, so CI always runs the dev copy of security-review.mjs.

Refs github#1556

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

`squad upgrade` regenerates the squad-* workflows in downstream repos from
Squad's bundled templates. Those templates redirect to unquoted $GITHUB_OUTPUT
in run: blocks, so any downstream repo running actionlint + shellcheck in CI
fails with SC2086 ("double quote to prevent globbing and word splitting").
Because the files are regenerated wholesale, downstream fixes are reverted on
every upgrade — so the fix has to live in the templates, and Squad's own CI has
to lint them.

SC2086 fixes (unquoted >> $GITHUB_* redirects):
  - .squad-templates/workflows/squad-heartbeat.yml (canonical source)
  - templates/workflows/squad-heartbeat.yml (root mirror)
  - packages/squad-cli/templates/workflows/squad-heartbeat.yml
  - packages/squad-sdk/templates/workflows/squad-heartbeat.yml
  - .github/workflows/squad-heartbeat.yml (2 occurrences)
  - .github/workflows/squad-repo-health.yml (10 across 4 run: blocks)
  - .github/workflows/squad-ci.yml (13 $GITHUB_STEP_SUMMARY across 5 gates)
Purely additive quoting; no behaviour change.

New CI gate — .github/workflows/squad-workflow-lint.yml:
  actionlint 1.7.12 + shellcheck 0.10.0, linting all five workflow/template
  directories including the .squad-templates/ canonical source and the
  templates/ root mirror. Linting only the packages/* mirrors would let a
  canonical-only edit ship unlinted, since this job does not run the template
  sync. The actionlint installer is fetched from the v1.7.12 tag rather than
  main to avoid a moving-ref RCE surface, and shellcheck 0.10.0 is installed
  explicitly because ubuntu-latest ships 0.9.0.

Installer hardening (PR review follow-up):
  - curl -sL -> curl -fsSL: hard-fail on non-200 so a 404 does not feed error
    HTML into bash. Applies to both actionlint and shellcheck downloads.
  - bash <(curl ...) -> download-then-run: write installer to a named file
    before executing so the script is inspectable on failure.
  - set -euo pipefail added to install step (shell: bash): ensures curl
    failure in the curl | tar pipeline is not masked by tar's exit status.
  - Convention matches squad-agents-ai-release.yml (shell: bash +
    set -euo pipefail at top of run block).

Also:
  - .github/actionlint.yaml suppresses SC2129 (style-only "group your
    redirects" suggestion) with documented rationale. This is a rule-scoped
    ignore, not the file-scoped exclusion the issue complains about.
  - size-regression-report.yml: removed dead `status=$?` (SC2034) — the value
    was never read and the step exits 0 unconditionally.

Verified by live regression probe on CI: reintroducing the unquoted redirect
reproduced the exact finding from the issue —
  packages/squad-cli/templates/workflows/squad-heartbeat.yml:32:9:
  SC2086:info:2:29: Double quote to prevent globbing and word splitting
— confirming the gate fires and that the SC2129 ignore does not over-suppress.
All 44 template files across the four directories lint clean.

Part 1 of 2. The actions/checkout v7 -> v4 clobbering on upgrade is deferred to
a follow-up PR.

Refs github#1556

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@serbrech
serbrech force-pushed the serbrech-shiny-fishstick branch from c277d37 to 6d8cab5 Compare July 29, 2026 09:30
serbrech added a commit to serbrech/squad that referenced this pull request Jul 29, 2026
…ories

Scribe maintenance pass produced during the issue github#1556 work. Split out of
PR github#1557 so that PR stays scoped to the shellcheck/actionlint gate. No product
code, no workflows, no templates — .squad/ team state only.

Decision inbox merged into decisions.md (6 entries), inbox cleared:
  - booster-ci-deletion-guard
  - retro-copilot-git-safety
  - flight-versioning-policy
  - booster-release-skill-v094
  - procedures-fix-coordinator-inline-dispatch-gate
  - booster-workflow-template-linting (new)
decisions.md 12151 -> 16030 bytes; still under the 20KB archival threshold, so
no entries were archived.

Agent histories summarized (all were over the 15KB threshold):
  eecom 33933 -> 5770, pao 30999 -> 5556, _alumni/kobayashi 26305 -> 3489,
  flight 23236 -> 5661, fido 22844 -> 6007, procedures 18945 -> 4082
This accounts for the ~1700 deleted lines — compaction of team memory, not lost
work; prior content remains in git history.

Cross-agent updates appended to fido (new CI quality gate) and surgeon
(changeset landed; new lint job affects release gating), plus a RETRO history
entry covering the security-scanner scoping fix in PR github#1559.

Blocked on github#1559: the unsafe-git scanner flags decisions.md prose that
documents the `git add .` prohibition. That fix cannot ship here because
squad-repo-health.yml uses pull_request_target and checks out the base branch
for trusted scripts, so CI always runs the dev copy of security-review.mjs.

Refs github#1556

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
serbrech added a commit to serbrech/squad that referenced this pull request Jul 29, 2026
…ories

Scribe maintenance pass produced during the issue github#1556 work. Split out of
PR github#1557 so that PR stays scoped to the shellcheck/actionlint gate. No product
code, no workflows, no templates — .squad/ team state only.

Decision inbox merged into decisions.md (6 entries), inbox cleared:
  - booster-ci-deletion-guard
  - retro-copilot-git-safety
  - flight-versioning-policy
  - booster-release-skill-v094
  - procedures-fix-coordinator-inline-dispatch-gate
  - booster-workflow-template-linting (new)
decisions.md 12151 -> 16030 bytes; still under the 20KB archival threshold, so
no entries were archived.

Agent histories summarized (all were over the 15KB threshold):
  eecom 33933 -> 5770, pao 30999 -> 5556, _alumni/kobayashi 26305 -> 3489,
  flight 23236 -> 5661, fido 22844 -> 6007, procedures 18945 -> 4082
This accounts for the ~1700 deleted lines — compaction of team memory, not lost
work; prior content remains in git history.

Cross-agent updates appended to fido (new CI quality gate) and surgeon
(changeset landed; new lint job affects release gating), plus a RETRO history
entry covering the security-scanner scoping fix in PR github#1559.

Blocked on github#1559: the unsafe-git scanner flags decisions.md prose that
documents the `git add .` prohibition. That fix cannot ship here because
squad-repo-health.yml uses pull_request_target and checks out the base branch
for trusted scripts, so CI always runs the dev copy of security-review.mjs.

Refs github#1556

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

@tamirdresher tamirdresher left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified the diff: all quoting fixes are correct and consistent across all 5 locations (canonical + 4 template mirrors), no missed unquoted GITHUB_OUTPUT/STEP_SUMMARY patterns repo-wide. New squad-workflow-lint.yml gate uses least-privilege permissions, properly pinned action versions (verified SHA matches v7 tag), and hardened installer scripts. All CI checks green including the new lint job. Minor non-blocking notes: one stale Copilot review thread can be marked resolved, and a small unrelated dead-variable cleanup in size-regression-report.yml is harmless scope creep. Approving.

@tamirdresher
tamirdresher merged commit bc8c75f into github:dev Jul 31, 2026
17 checks passed
tamirdresher pushed a commit that referenced this pull request Jul 31, 2026
…ories (#1558)

* chore(squad): merge decision inbox and summarize oversized agent histories

Scribe maintenance pass produced during the issue #1556 work. Split out of
PR #1557 so that PR stays scoped to the shellcheck/actionlint gate. No product
code, no workflows, no templates — .squad/ team state only.

Decision inbox merged into decisions.md (6 entries), inbox cleared:
  - booster-ci-deletion-guard
  - retro-copilot-git-safety
  - flight-versioning-policy
  - booster-release-skill-v094
  - procedures-fix-coordinator-inline-dispatch-gate
  - booster-workflow-template-linting (new)
decisions.md 12151 -> 16030 bytes; still under the 20KB archival threshold, so
no entries were archived.

Agent histories summarized (all were over the 15KB threshold):
  eecom 33933 -> 5770, pao 30999 -> 5556, _alumni/kobayashi 26305 -> 3489,
  flight 23236 -> 5661, fido 22844 -> 6007, procedures 18945 -> 4082
This accounts for the ~1700 deleted lines — compaction of team memory, not lost
work; prior content remains in git history.

Cross-agent updates appended to fido (new CI quality gate) and surgeon
(changeset landed; new lint job affects release gating), plus a RETRO history
entry covering the security-scanner scoping fix in PR #1559.

Blocked on #1559: the unsafe-git scanner flags decisions.md prose that
documents the `git add .` prohibition. That fix cannot ship here because
squad-repo-health.yml uses pull_request_target and checks out the base branch
for trusted scripts, so CI always runs the dev copy of security-review.mjs.

Refs #1556

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

* fix: resolve security review permissions check failure

Sanitize new decision/history prose so the unsafe-git scanner no longer matches literal forbidden command strings in PR #1558.

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
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