Skip to content

fix(gh-aw): prevent edited command replay - #2149

Merged
bradygaster merged 6 commits into
devfrom
bradygaster-prevent-command-replay
Oct 2, 2026
Merged

bradygaster merged 6 commits into
devfrom
bradygaster-prevent-command-replay

Conversation

@bradygaster

@bradygaster bradygaster commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

What

Prevent edited issue and comment events from replaying unchanged embedded /squad invocations, require dual-principal authorization for /squad revoke-improvement, and ensure live improvement revalidation honors only authorized, unedited human revocations.

Why

The clean consumer review at octodemo/zava-social-queue-worker-20261002132914#1 showed that unrelated body edits could redispatch an unchanged accepted or rejected embedded command. It also showed that revoke-improvement mutated durable approval state while remaining publicly open, and an unauthorized revocation comment could still be honored later even after the router refused it.

How

The shared command contract now canonicalizes the prior and current invocation on edited events using changes.body.from; missing/malformed prior evidence and equivalent commands noop, while newly introduced or materially changed accepted/rejected commands retain existing behavior. revoke-improvement was removed from the open-mode set without changing the command allowlist, roles: all, or intentionally public status, review, research, and plan. Issue-body and edited-comment revocations are rejected because they cannot become durable records. Improvement revalidation now live-checks revocation-author permission, rejects edited/app/bot revocations, ignores weak permissions, and fails closed on unresolved evidence or malformed revocation timestamps with bounded lookups. Canonical package sources and integrity manifests were regenerated with npm run gh-aw:integrity:write.

Security review: no new secrets, actions, redirects, PATs, GitHub Apps, private keys, repository secrets, or environment secrets were added. The first consumer compile approved only the repository's existing documented safe-update baseline (SQUAD_GITHUB_APP_PRIVATE_KEY, SQUAD_GITHUB_TOKEN, and bradygaster/squad/.github/actions/squad-init); the final strict compile required no approval and produced exactly the two documented warnings. An independent security review found the revocation revalidation bypass, a different revision author closed it, and the independent security re-review found no vulnerabilities.


⚠️ Quick Check

  • If SDK/CLI source files changed: completed the applicable Changeset step below (npx changeset add / .changeset/*.md, direct CHANGELOG.md entry for maintainers, or skip-changelog label for no user-facing changes)

PR Readiness Checklist

The PR readiness bot will validate these automatically after push.
Check each item before requesting review. See CONTRIBUTING.md for full details.

Branch & Commit

  • Branch created from dev (not main)
  • Branch is up to date with dev (git fetch upstream && git rebase upstream/dev)
  • Verified diff contains only intended changes (git diff --cached --stat)
  • PR is not in draft mode (mark ready when checks pass)
  • Commit history is clean (squash fixups before review)

Build & Test

  • npm run build passes
  • npm test passes (all tests green) — waived below because six unrelated linked-worktree-sensitive tests fail locally; the GitHub full-test job passed on the prior head and is rerunning on the final head.
  • npm run lint passes (type check clean)
  • npm run lint:eslint passes
  • For migration PRs (>20 files): include test output summary in PR description — N/A; this is not a migration PR and changes fewer than 20 files.

Validation evidence:

  • npm exec vitest run test/gh-aw-*.test.ts — passed: 29 files, 2,048 tests.
  • Focused router/improvement mutation and authorization suites — passed: 3 files, 350 tests.
  • npm run gh-aw:integrity:check — passed.
  • Consumer gh aw compile --strict --no-check-update — Compiled 8 workflows: 8 succeeded, 2 warnings; only the documented pull_request_target and slash-command/bot warnings.
  • Compiled squad-command-router.lock.yml contains the edited-event replay gate.
  • SKIP_BUILD_BUMP=1 npm run build — passed.
  • npm run lint — passed.
  • npm run lint:eslint — passed with existing warnings only.
  • Full npm test was attempted but this linked-worktree environment has 6 unrelated failures in externalized-state/init/consult tests that intentionally resolve the repository's main-checkout .squad state; all 2,048 gh-aw tests are green.

Changeset

  • Changeset added via npx changeset add (if packages/squad-sdk/src/ or packages/squad-cli/src/ changed)
  • Or direct CHANGELOG.md entry (maintainers only — write-protected for external contributors) — N/A; the changeset path above was used.
  • Or skip-changelog label applied (if no user-facing changes) — N/A; the changeset path above was used.

Docs

  • README section updated (if new feature/module) — N/A; no README feature section applies.
  • Docs feature page (if new user-facing capability) — authorization behavior updated in the gh-aw guide.

Exports

  • package.json subpath exports updated (if new module) — N/A; no SDK modules or exports changed.

Breaking Changes

None.

Waivers

Waived: full npm test green status in this linked-worktree environment. Six unrelated externalized-state/init/consult tests intentionally detect and use/refuse the main checkout rather than their temporary fixture; all 2,048 gh-aw tests, focused mutation tests, build, type-check, ESLint, integrity verification, install-contract tests, and strict compilation pass. Requires repository reviewer approval before merge.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 14:48
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🟡 Impact Analysis — PR #2149

Risk tier: 🟡 MEDIUM

📊 Summary

Metric Count
Files changed 18
Files added 1
Files modified 17
Files deleted 0
Modules touched 3

🎯 Risk Factors

  • 18 files changed (6-20 → MEDIUM)
  • 3 modules touched (2-4 → MEDIUM)

📦 Modules Affected

docs (1 file)
  • docs/src/content/docs/guide/gh-aw.md
root (12 files)
  • .changeset/prevent-command-replay.md
  • workflows/package/squad-command-router.md
  • workflows/package/squad-improvement-worker.md
  • workflows/package/squad-retro.md
  • workflows/package/squad.md
  • workflows/shared/squad-command-contract.mjs
  • workflows/shared/squad-improvement-gate.mjs
  • workflows/squad-command-router.md
  • workflows/squad-improvement-worker.md
  • workflows/squad-retro.md
  • workflows/squad-workflows.manifest.json
  • workflows/squad.md
tests (5 files)
  • test/gh-aw-command-parse.test.ts
  • test/gh-aw-command-router-relay.test.ts
  • test/gh-aw-improvement-worker.test.ts
  • test/gh-aw-quality.test.ts
  • test/gh-aw-retro-workflow.test.ts

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

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 0552ffc

PR Scope: 🔧 Infrastructure

⚠️ 4 item(s) to address before review

Status Check Details
❌ Single commit 6 commits — consider squashing before review
✅ Not in draft Ready for review
❌ Branch up to date dev is 1 commit(s) ahead — rebase recommended
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean No .squad/ or docs/proposals/ files
✅ No merge conflicts Merge status unknown — GitHub is still computing
✅ Copilot threads resolved 5 active Copilot thread(s) resolved (5 outdated skipped)
❌ CI passing 1 check(s) still running

Files Changed (18 files, +765 −77)

File +/−
.changeset/prevent-command-replay.md +6 −0
docs/src/content/docs/guide/gh-aw.md +7 −5
test/gh-aw-command-parse.test.ts +157 −2
test/gh-aw-command-router-relay.test.ts +299 −0
test/gh-aw-improvement-worker.test.ts +103 −6
test/gh-aw-quality.test.ts +3 −3
test/gh-aw-retro-workflow.test.ts +4 −0
workflows/package/squad-command-router.md +9 −1
workflows/package/squad-improvement-worker.md +7 −4
workflows/package/squad-retro.md +5 −2
workflows/package/squad.md +8 −13
workflows/shared/squad-command-contract.mjs +54 −1
workflows/shared/squad-improvement-gate.mjs +60 −6
workflows/squad-command-router.md +9 −1
workflows/squad-improvement-worker.md +7 −4
workflows/squad-retro.md +5 −2
workflows/squad-workflows.manifest.json +14 −14
workflows/squad.md +8 −13

Total: +765 −77


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

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

Case-only edits can still replay commands, same-second comment ordering is incorrect, and authorization guidance remains inconsistent.

3 open findings
What changed in this PR

Hardens /squad routing and improvement revocation authorization.

Changes:

  • Suppresses replay of canonically unchanged edited commands.
  • Requires authorization for revocations and revalidates revocation authors.
  • Updates tests, documentation, generated workflows, and integrity hashes.
File Description
workflows/​squad.md Updates revocation authorization guidance.
workflows/​squad-workflows.manifest.json Refreshes integrity digests.
workflows/​squad-command-router.md Adds the edited-command replay gate.
workflows/​shared/​squad-improvement-gate.mjs Revalidates live revocations.
workflows/​shared/​squad-command-contract.mjs Adds invocation comparison and authorization changes.
workflows/​package/​squad.md Regenerates the packaged Squad workflow.
workflows/​package/​squad-command-router.md Regenerates the packaged router.
test/​gh-aw-quality.test.ts Updates compiled-workflow hashes.
test/​gh-aw-improvement-worker.test.ts Tests revocation revalidation.
test/​gh-aw-command-router-relay.test.ts Tests replay prevention and dual authorization.
test/​gh-aw-command-parse.test.ts Tests edited-event canonicalization.
docs/​src/​content/​docs/​guide/​gh-aw.md Documents revocation authorization.
.changeset/​prevent-command-replay.md Records package-facing fixes.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread workflows/squad.md Resolved
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

Rejected-command recasing still replays, issue-body revocations have no durable effect, and worker guidance remains inconsistent.

3 open findings
3 resolved since last review

🧠 Review effort: Balanced

Comment thread test/gh-aw-command-router-relay.test.ts Resolved
Comment thread docs/src/content/docs/guide/gh-aw.md Resolved
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

Edited revocations can silently remain ineffective, and malformed revocation timestamps currently fail open.

2 open findings
3 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Low severity Update documented improvement authorization request limit

workflows/​shared/​squad-improvement-gate.mjs:29

This raises the declared worst-case authorization ceiling to 36 requests, but the guide still states that improvement authorization is bounded to fourteen reads per check (docs/src/content/docs/guide/gh-aw.md:892). Update that operational limit so users can size API-rate usage accurately.

This issue also appears on line 353 of the same file.

🧠 Review effort: Balanced

Comment thread docs/src/content/docs/guide/gh-aw.md Resolved
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

Revocation syntax and malformed timestamp handling can still cause accepted or unresolved revocations to be silently ignored.

1 open finding
2 resolved since last review

🧠 Review effort: Balanced

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

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

Editing an existing revocation silently invalidates it without routing the promised rejection.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

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

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.

🔵 Needs a closer look

Security-sensitive authorization and durable revocation changes warrant final human review despite strong focused coverage.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@bradygaster
bradygaster merged commit 5455312 into dev Oct 2, 2026
19 checks passed
@bradygaster
bradygaster deleted the bradygaster-prevent-command-replay branch October 3, 2026 00:11
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.

2 participants