diff --git a/.changeset/gh-aw-upstream-one.md b/.changeset/gh-aw-upstream-one.md new file mode 100644 index 000000000..75af043a4 --- /dev/null +++ b/.changeset/gh-aw-upstream-one.md @@ -0,0 +1,6 @@ +--- +"@bradygaster/squad-sdk": patch +"@bradygaster/squad-cli": patch +--- + +Update the Squad agentic-workflow enlistment skill to install the canonical github/squad package with stable gh-aw 1.x, without pinning the CLI installation to an exact patch release. Preserve immutable compiler-action pins and full installation/staging verification; the package currently validates gh-aw v1.0.1 output. diff --git a/.github/agents.md b/.github/agents.md index cc0f14c41..a8fb45e72 100644 --- a/.github/agents.md +++ b/.github/agents.md @@ -49,11 +49,11 @@ The quick start installs this workflow set: ```bash SQUAD_SHA="<40-character-commit-sha>" # explicit, maintainer-approved; never `commits/dev` -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` -The removal is intentional: gh-aw v0.91.5 generates that generic tool-owned +The removal is intentional: gh-aw v1.0.1 generates that generic tool-owned router, which loads mutable prompts from the current `github/gh-aw` repository. It is not Squad-owned or bound to `SQUAD_SHA`. Keep the exact `.github/skills/gh-aw-enlistment/SKILL.md` installed by Squad. diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 968ec1911..e1a46be44 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -176,7 +176,7 @@ jobs: # than skipping — a skipped gate is indistinguishable from no gate. This # includes the shell input security contract gate (#1834) and the compile # contract (#1732). - run: gh extension install --pin v0.91.5 github/gh-aw + run: gh extension install --pin v1.0.1 github/gh-aw env: GH_TOKEN: ${{ github.token }} - name: Build @@ -658,10 +658,10 @@ jobs: - name: Install verifier dependencies run: npm ci --ignore-scripts --registry=https://registry.npmjs.org/ - - name: Install gh-aw v0.91.5 (pinned) + - name: Install gh-aw v1.0.1 (pinned) run: | - gh extension install --force --pin v0.91.5 github/gh-aw - test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.91.5 + gh extension install --force --pin v1.0.1 github/gh-aw + test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v1.0.1 env: GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/squad-gh-aw-hosted-e2e.yml b/.github/workflows/squad-gh-aw-hosted-e2e.yml index 53b773d59..dcf5ba517 100644 --- a/.github/workflows/squad-gh-aw-hosted-e2e.yml +++ b/.github/workflows/squad-gh-aw-hosted-e2e.yml @@ -24,7 +24,7 @@ jobs: hosted-e2e: name: Install, merge, bootstrap, and probe if: >- - github.repository == 'bradygaster/squad' + github.repository == 'github/squad' && github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest timeout-minutes: 45 @@ -50,8 +50,8 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - gh extension install --force --pin v0.91.5 github/gh-aw - test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.91.5 + gh extension install --force --pin v1.0.1 github/gh-aw + test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v1.0.1 - name: Verify trusted default-branch controller env: diff --git a/.github/workflows/squad-release-verify.yml b/.github/workflows/squad-release-verify.yml index d76b1fb3d..25045b0ba 100644 --- a/.github/workflows/squad-release-verify.yml +++ b/.github/workflows/squad-release-verify.yml @@ -203,8 +203,8 @@ jobs: - name: Check extracted release scripts and workflow policy run: node scripts/release/check-release-scripts.mjs - - name: Install gh-aw v0.91.5 (pinned; required by fail-closed test gates) - run: gh extension install --force --pin v0.91.5 github/gh-aw + - name: Install gh-aw v1.0.1 (pinned; required by fail-closed test gates) + run: gh extension install --force --pin v1.0.1 github/gh-aw env: GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/squad-standalone-release.yml b/.github/workflows/squad-standalone-release.yml index da4e75983..1d7bff2ed 100644 --- a/.github/workflows/squad-standalone-release.yml +++ b/.github/workflows/squad-standalone-release.yml @@ -1082,7 +1082,7 @@ jobs: --base master \ --head "tamirdresher:${BRANCH}" \ --title "New version: ${PACKAGE_IDENTIFIER} version ${VERSION}" \ - --body "Automated manifest update for [Squad ${TAG}](https://github.com/bradygaster/squad/releases/tag/${TAG}), using the release run's packaging-manifests artifact.")" + --body "Automated manifest update for [Squad ${TAG}](https://github.com/github/squad/releases/tag/${TAG}), using the release run's packaging-manifests artifact.")" pr_status="Opened" else pr_status="Reused" diff --git a/.squad-templates/skills/gh-aw-enlistment/SKILL.md b/.squad-templates/skills/gh-aw-enlistment/SKILL.md index 0a02b6d01..9c150881f 100644 --- a/.squad-templates/skills/gh-aw-enlistment/SKILL.md +++ b/.squad-templates/skills/gh-aw-enlistment/SKILL.md @@ -25,7 +25,7 @@ bootstrap pull request** — never an auto-merge. This skill **operationalizes** the supported bootstrap path. It does not summarize it: each step below is a gate with explicit success evidence and **STOP conditions**. The authoritative source is `docs/src/content/docs/guide/gh-aw.md` (mirrored at -`https://bradygaster.github.io/squad/docs/guide/gh-aw/`). If that guide and this +`https://github.github.com/squad/guide/gh-aw/`). If that guide and this skill ever disagree, the guide wins — re-read it before proceeding. GitHub Issues are a hard prerequisite: `/squad` commands arrive as issue @@ -54,16 +54,15 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status -# Prove the exact package-capable compiler version before creating artifacts +# Require stable gh-aw 1.x without pinning the CLI installation to a patch # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -71,8 +70,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -87,21 +86,27 @@ git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> capture both output streams from `gh aw --version`. On any mismatch, remove -> `github/gh-aw`, cleanly install the exact `v0.91.5` pin, and verify both -> streams again. Stop before branch creation or file generation unless that -> second check proves exactly `v0.91.5`; never select a newer release. +> capture both output streams from `gh aw --version`. If absent or 0.x, cleanly +> install the current stable `github/gh-aw` release without `--pin` and verify +> both streams again. Stop unless the result is a stable 1.x release; never +> downgrade a newer major version automatically. The current package validates +> v1.0.1 compiler bytes and immutable action pins. Other 1.x releases require +> a maintainer-reviewed package update, not a consumer-side digest refresh. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. -- **STOP** if exact gh-aw `v0.91.5` cannot be proven after the clean pinned - reinstall. Do not create a branch or generate repository files. +- **STOP** if stable gh-aw 1.x cannot be proven after installation, or the + package's published compiler contract does not cover the installed release. + Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation run and the requested `@copilot` review both depend on it. +- Before installation, record whether `.vscode/settings.json` and + `.github/workflows/agentics-maintenance.yml` already exist. Preserve pre-existing + files; stop and report their diff if gh-aw changes them. ### 1. Require GitHub Issues, then allow Actions-created PRs with a read-only token @@ -193,13 +198,13 @@ published release guidance, then set it once: echo "STOP: SQUAD_SHA must be the exact 40-character commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` The nested `workflows/aw.yml` is the only supported distribution registration. It isolates package auto-discovery from unrelated repository skills and agents, -and installs exactly eight workflows, seventeen runtime resources, and one +and installs exactly eight workflows, twenty-one runtime resources, and one `gh-aw-enlistment` skill at the same resolved revision: - `squad.md` + `squad.lock.yml` @@ -217,7 +222,7 @@ governance-scoped retrospective proposal (see the gh-aw guide's retrospective auto-implementation section); installing it alongside the other seven keeps the full stack consistent and avoids a second bootstrap pass later. -gh-aw v0.91.5 also materializes +gh-aw v1.0.1 also materializes `.github/skills/agentic-workflows/SKILL.md`. That generic tool-owned router is not part of the Squad package and directs agents to mutable prompts from the current `github/gh-aw` repository rather than the pinned Squad revision. Remove @@ -247,7 +252,7 @@ On a clean repo, `gh aw add` reports these expected safe updates and **nothing e - Restricted secrets: **`SQUAD_GITHUB_APP_PRIVATE_KEY`** and **`SQUAD_GITHUB_TOKEN`** -- Action: **`bradygaster/squad/.github/actions/squad-init`** +- Action: **`github/squad/.github/actions/squad-init`** > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets @@ -285,7 +290,7 @@ This must run after any first-install approval and before committing. Success criteria: - All eight workflows compile successfully. -- With gh-aw v0.91.5, require exactly two warnings, one occurrence of each +- With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -335,15 +340,22 @@ If `.github/aw/logs/` lacks a `.gitignore`, add one there: !.gitignore ``` -`gh aw add` may also create `.vscode/settings.json` (enables Copilot for Markdown -workflow files). This is an **optional editor setting** — the stage command below -intentionally leaves it untracked. Delete it if unwanted, or stage it explicitly -if your team wants to share it. Decide deliberately; do not stage it by accident. +gh-aw v1.0.1 may generate two auxiliary outputs: `.vscode/settings.json` +(optional Markdown editor settings) and `.github/workflows/agentics-maintenance.yml` +(the compiler's maintenance workflow). Neither is authenticated by Squad's +package manifest. Leave both outside the bootstrap PR by default; the staging +commands below exclude them. Review and stage an auxiliary file by its exact +path only after explicit approval. + +Only remove an unwanted auxiliary file if it was absent before installation +and was created by this invocation. Never delete or overwrite pre-existing +editor settings or maintenance workflows. Known, newly generated auxiliary +files left untracked are expected output, not an unrelated-change failure. Stage **only** the documented generated surfaces, then verify the staged set: ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -498,7 +510,7 @@ git switch -c chore/squad-gh-aw-bootstrap echo "STOP: SQUAD_SHA must be an explicit, maintainer-approved 40-character lowercase hex commit SHA." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # Safe-update report shows ONLY the two documented secrets + squad-init → approve once @@ -508,7 +520,7 @@ gh aw compile --strict # final, no --approve; exactly the two document node .github/workflows/shared/squad-install-verifier.mjs \ --verify-install --source-revision "${SQUAD_SHA}" --strict-compile -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git commit -m "ci: add Squad agentic workflow" @@ -566,7 +578,7 @@ gh pr merge --squash # auto-merge before human review. NEVER. `.github/skills/agentic-workflows/SKILL.md`; keep the exact Squad-owned `.github/skills/gh-aw-enlistment/SKILL.md`. - ❌ **Approving unknown safe updates.** Approve ONLY `SQUAD_GITHUB_APP_PRIVATE_KEY`, - `SQUAD_GITHUB_TOKEN`, and `bradygaster/squad/.github/actions/squad-init`. Anything + `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Anything else is a STOP. - ❌ **Treating `--approve` as the final compile.** Always finish with a plain `gh aw compile --strict` (no `--approve`). diff --git a/README.md b/README.md index de91c387b..4912eb565 100644 --- a/README.md +++ b/README.md @@ -600,7 +600,7 @@ test "$(gh api "repos/${owner_repo}" --jq '.has_issues')" = "true" || { } SQUAD_SHA="<40-character-commit-sha>" # explicit, maintainer-approved; never `commits/dev` -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md git add -- \ .github/aw/ \ diff --git a/agents-agentic-workflows.md b/agents-agentic-workflows.md new file mode 100644 index 000000000..63534f9f6 --- /dev/null +++ b/agents-agentic-workflows.md @@ -0,0 +1,31 @@ +# Squad agentic workflows bootstrap prompt + +**Compiler contract:** Install stable gh-aw 1.x without an exact CLI patch-version installation lock. The package currently validates v1.0.1 output with immutable compiler-action pins and complete-lock digests; newer compiler releases require a reviewed package update. Use a published immutable Squad revision carrying this contract, not an older upstream revision. See [compiler compatibility](https://github.com/github/squad/blob/dev/docs/src/content/docs/guide/gh-aw.md#gh-aw-1x-compatibility). + +```text +Bootstrap this repository with GitHub's Squad agentic workflows from `github/squad`. Inspect the repo first, make only the necessary changes, validate them, and open a PR for human review if your tools permit it. Do not merge. + +Before editing: +- Check the default branch, working tree, authentication, and existing `.github/aw/`, `.github/workflows/`, and `.github/skills/` files. +- Record whether `.vscode/settings.json` and `.github/workflows/agentics-maintenance.yml` already exist. Never delete or overwrite pre-existing settings or maintenance workflows; stop and report their diff if gh-aw changes them. +- If an installation is already present, or files conflict and you can't verify their ownership, stop and report the paths; don't overwrite them. +- Check `gh aw --version` against current official stable 1.x releases. Do not install an exact patch version or downgrade to 0.x to bypass a failed prerequisite. +- Obtain an approved, immutable 40-character lowercase `SQUAD_SHA` from published guidance or a maintainer. Never guess or use a moving branch. +- Require published compatibility evidence for that revision, `github/squad/workflows` ownership, and the installed 1.x compiler. This package validates v1.0.1 compilation with immutable action pins and complete compiled-lock digests. Stop if the selected revision's contract does not cover the installed compiler. Do not rewrite ownership, regenerate trusted digests in the consumer repo, or weaken the verifier. +- Check that Issues are enabled and Actions permissions match the documented Profile A (`default_workflow_permissions=read`, `can_approve_pull_request_reviews=false`). Don't change settings without explicit authorization. + +Only after every prerequisite passes, install on `chore/squad-gh-aw-bootstrap`, without overwriting existing work: +`gh aw add "github/squad/workflows@${SQUAD_SHA}"` + +Do not run generic `gh aw init` or create Squad files by hand. If the install generates `.github/skills/agentic-workflows/SKILL.md`, remove only that tool-generated file as the guide directs. Don't create the optional secrets. If a first-install safe-update approval is required, compare its exact secret/action list with the approved revision's published guidance: `SQUAD_GITHUB_APP_PRIVATE_KEY`, `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Stop on any mismatch; do not approve or substitute an action. + +Run and require success: +1. `node .github/workflows/shared/squad-install-verifier.mjs --materialize-runtime` +2. `gh aw compile --strict --no-check-update` +3. `node .github/workflows/shared/squad-install-verifier.mjs --verify-install --source-revision "${SQUAD_SHA}" --strict-compile` +4. Stage only newly installed/materialized changed/owned paths within `.gitattributes`, `.github/aw/`, `.github/workflows/`, and `.github/skills/`; never stage whole directories containing unrelated files. Leave `.vscode/settings.json` and `.github/workflows/agentics-maintenance.yml` outside the PR unless explicitly approved: they are tool-generated auxiliary outputs, not Squad-manifest-authenticated files. Only remove either file if it was absent beforehand and this invocation created it. Review the staged diff, then run `node .github/workflows/shared/squad-install-verifier.mjs --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}"`. + +Confirm eight workflows and their generated lockfiles are present and review the compiled artifacts. Require the approved revision's documented warning policy: one `pull_request_target` warning for `squad-review.md` and one combined `slash_command`/`bots` warning for `squad.md` under the current v1.0.1 contract. Known, newly generated auxiliary files left untracked are expected output, not an unrelated-change failure. Stop on any undocumented warning, error, unexpected deletion, or other unrelated change. Review the staged diff before committing. + +Open a PR against the default branch captured during inspection only after all checks pass. If you can't verify a prerequisite, validate the install, push, or create the PR, report the exact blocker instead of claiming success. Report the PR URL and validation results if created; leave merge and post-merge activation to a human. +``` diff --git a/cspell.json b/cspell.json index c1835b6b4..46273d783 100644 --- a/cspell.json +++ b/cspell.json @@ -18,6 +18,7 @@ "ADO", "AKIA", "affordances", + "agentics", "kiro", "resumability", "amolchanov", diff --git a/docs/src/content/docs/guide/gh-aw.md b/docs/src/content/docs/guide/gh-aw.md index b7b2443ae..cdc039961 100644 --- a/docs/src/content/docs/guide/gh-aw.md +++ b/docs/src/content/docs/guide/gh-aw.md @@ -11,20 +11,26 @@ request you can review before merging. This guide covers setup, every slash command, and daily usage patterns. -> **v0.91.5 permission migration.** Review the permission change before installing +> **Compiler permission migration.** Review compiled permissions before installing > this compiler upgrade in a consumer repository. Compared with v0.89.22, -> v0.91.5 adds `actions: read` and `pull-requests: read` to the Bootstrap +> the compiler adds `actions: read` and `pull-requests: read` to the Bootstrap > `conclusion` job, which previously requested only `issues: write`. The compiler > requires these reads for existing automatic failure-issue reporting; disabling > that reporting would change standalone behavior. No additional write scope is > introduced. Local installation and strict verification do not approve hosted > permissions, and the dispatcher SDK adapter's hosted runtime parity still -> requires runtime evidence. +> requires runtime evidence. gh-aw v1.0.1 also adds `checks: read` to the +> compiler-owned conclusion diagnostics. --- ## Quick start +> **Compatibility prerequisite:** Read [gh-aw 1.x compatibility](#gh-aw-1x-compatibility). +> Install the current stable 1.x CLI without an exact patch installation pin. +> This package currently validates v1.0.1 compilation and immutable action pins; +> newer compiler output requires a reviewed package update, not weaker checks. + Seven steps from zero to a validated, reviewable Squad bootstrap: > **Agent action required:** When a user asks an AI coding agent to install Squad @@ -37,18 +43,17 @@ Seven steps from zero to a validated, reviewable Squad bootstrap: ```bash set -euo pipefail -# 1. Verify GitHub access and prove the exact supported gh-aw version +# 1. Verify GitHub access and require the stable gh-aw 1.x compiler family gh auth status # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -56,8 +61,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -111,13 +116,13 @@ SQUAD_SHA="<40-character-commit-sha>" exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # 5. On first install, review the safe-update report. Approve ONLY if it # contains exactly the two documented secrets (SQUAD_GITHUB_APP_PRIVATE_KEY, # SQUAD_GITHUB_TOKEN) and the one documented action -# (bradygaster/squad/.github/actions/squad-init) and nothing else. STOP and +# (github/squad/.github/actions/squad-init) and nothing else. STOP and # report any other entry instead of approving. gh aw compile --strict --approve # first install only, when the safe-update warning appears @@ -133,7 +138,7 @@ node .github/workflows/shared/squad-install-verifier.mjs \ --strict-compile # 7. Commit the generated files and open the bootstrap PR -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -550,7 +555,7 @@ SQUAD_SHA="<40-character-commit-sha>" echo "STOP: SQUAD_SHA must be an explicit 40-character Squad commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` @@ -613,7 +618,7 @@ retrospective proposal (see [Retrospective auto-implementation](#retrospective-auto-implementation-opt-in) below). `gh aw add` also installs the Squad skill under `.github/skills/`, which is why -the bootstrap commit stages that path alongside the workflows. gh-aw v0.91.5 +the bootstrap commit stages that path alongside the workflows. gh-aw v1.0.1 additionally generates `.github/skills/agentic-workflows/SKILL.md`. That tool-owned router loads mutable prompt files from the current `github/gh-aw` repository and is not bound to the pinned Squad revision or compiler version. @@ -641,7 +646,7 @@ source/lock pairs, and one coherent 40-character revision. On a clean repository, `gh aw add` reports these expected safe-update changes: - Restricted secrets: `SQUAD_GITHUB_APP_PRIVATE_KEY` and `SQUAD_GITHUB_TOKEN` -- Action: `bradygaster/squad/.github/actions/squad-init` +- Action: `github/squad/.github/actions/squad-init` > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets > the workflows *reference* so you can approve that surface — it is not asking you @@ -671,7 +676,7 @@ gh aw compile --strict ``` Run this exact command after any required first-install approval and before -committing. With gh-aw v0.91.5, require exactly two warnings, one occurrence +committing. With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -715,7 +720,7 @@ node .github/workflows/shared/squad-install-verifier.mjs \ ### Open the bootstrap pull request ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -759,10 +764,19 @@ omitted required files or staged digest mismatches stop the install before commit/push. Never force-add a directory or glob; rerun the gate after edits or restaging, including package upgrades. -`gh aw add` may also create `.vscode/settings.json` to enable Copilot for -Markdown workflow files. The command above intentionally leaves that optional -editor setting untracked. Delete it if you do not want the local setting, or -stage it explicitly if your team wants to share it. +gh-aw v1.0.1 may also generate `.vscode/settings.json` (optional Markdown editor +settings) and `.github/workflows/agentics-maintenance.yml` (the compiler's +maintenance workflow). Neither auxiliary file is authenticated by Squad's +package manifest. The staging commands intentionally exclude both from the +bootstrap PR; review and stage an exact auxiliary path only after explicit +approval. + +Before installation, record whether these paths already exist. Never delete +or overwrite pre-existing editor settings or maintenance workflows; stop and +report their diff if gh-aw changes them. Remove an unwanted auxiliary file +only when it was absent beforehand and this invocation created it. Known, +newly generated auxiliary files left untracked are expected output, not an +unrelated-change failure. > **Troubleshooting:** If the lock files are missing, rerun `gh aw compile > --strict`. Do not open or merge the bootstrap PR until all eight source/lock @@ -812,7 +826,7 @@ activation with a GitHub App instead, configure: | `SQUAD_GITHUB_APP_OWNER` | Variable | App installation owner (org or user) | The workflow mints an installation token at activation time, explicitly scoped -to the current repository with `contents: read`, as required by gh-aw v0.91.5 +to the current repository with `contents: read`, as required by gh-aw v1.0.1 strict compilation. Only `squad init` and `squad health` receive this token. The repository is passed as its full `owner/name`; a configured installation owner that does not match the current repository fails explicitly rather than @@ -1010,7 +1024,7 @@ gh-aw preserves HTML comments inside code fences, and lifecycle readers inspect the complete posted text rather than its rendered visibility. This tool-input rule is distinct from serialized output. The pinned gh-aw -v0.91.5 `add_comment` adapter adds a `temporary_id`; its collector appends the +v1.0.1 `add_comment` adapter adds a `temporary_id`; its collector appends the `Structured data:` JSON suffix while retaining `data`. The guard accepts only a string ID in the adapter's bare `aw_` format (3–12 alphanumeric or underscore characters), not other mutation fields. For serialized plan comments, it first @@ -1614,7 +1628,7 @@ comment, ignore a missing proof, or dispatch partial bindings. #### Run the existing executable example The repository's -[activation finalization integration fixture](https://github.com/bradygaster/squad/blob/dev/test/gh-aw-activation-finalization.test.ts) +[activation finalization integration fixture](https://github.com/github/squad/blob/dev/test/gh-aw-activation-finalization.test.ts) is the executable producer/consumer example. In `continues after a later-phase pending-source recovery and validates the complete transitive reader chain`, it obtains proofs through the real workflow `verifyReconciliationRequest`, @@ -1623,13 +1637,13 @@ both the SDK selector and canonical checker. These helpers belong to `workflows/shared/squad-activation.mjs`; they are **not** public `/casting` verifier exports. The `trusted synchronous publication completion (source and strict-compiled jobs)` group also executes emitted job scripts and the pinned issue-creation API adapter. -The companion [selector contract tests](https://github.com/bradygaster/squad/blob/dev/test/agent-provenance.test.ts) +The companion [selector contract tests](https://github.com/github/squad/blob/dev/test/agent-provenance.test.ts) cover selection, no-record results and rejection cases; their hand-built evidence is test data, not production authorization. Run from a Squad repository checkout with Node.js **22.5.0 or newer**, npm, Git, GitHub CLI, and the repository's npm dependencies already installed. Install the -exact compiler once with `gh extension install --pin v0.91.5 github/gh-aw`. +exact compiler once with `gh extension install --pin v1.0.1 github/gh-aw`. If a different gh-aw version is installed, remove that extension with `gh extension remove gh-aw` before the pinned installation; v0.89.22 is unsupported for this fixture. Before **either compiler path below**, build the current @@ -1642,16 +1656,16 @@ npm run build -w packages/squad-sdk With the pinned extension available, run: ```bash -test "$(gh aw --version | awk 'END {print $NF}')" = "v0.91.5" && +test "$(gh aw --version | awk 'END {print $NF}')" = "v1.0.1" && npm test -- test/gh-aw-activation-finalization.test.ts test/agent-provenance.test.ts ``` Alternatively, set `SQUAD_GH_AW_BIN` to an **absolute path** to an already obtained -v0.91.5 executable when running that same `npm test` command. The fixture checks +v1.0.1 executable when running that same `npm test` command. The fixture checks the exact compiler version, strict-compiles an isolated package installation, and validates immutable action pins. Outbound HTTPS access to `raw.githubusercontent.com` is required to fetch the runtime closure at -`github/gh-aw-actions` commit `16b430146d5d5646eccef5a1ceb72152333b18b9`. +`github/gh-aw-actions` commit `221ba4f4319de6b8e809d1a15528b3ae6a818aa5`. GitHub issue APIs are synthetic and writes stay local: this example neither creates live issues nor demonstrates hosted credentials or permissions. A missing compiler, mismatched pin, failed runtime download or failed assertion @@ -2507,7 +2521,7 @@ same native package as one unit: ```bash SQUAD_SHA="<40-character-commit-sha>" -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" --force +gh aw add "github/squad/workflows@${SQUAD_SHA}" --force rm -f .github/skills/agentic-workflows/SKILL.md node .github/workflows/shared/squad-install-verifier.mjs --materialize-runtime gh aw compile --strict @@ -2525,9 +2539,9 @@ prints the exact safe recovery commands. The schema-v2 integrity manifest records two complete compiled lock digests per workflow: `lock_sha256` for a per-workflow source annotation and -`package_lock_sha256` for a package-root annotation. gh-aw v0.91.5 emits -`bradygaster/squad/workflows@SHA` for direct package includes, but can emit -`bradygaster/squad/workflows/package/.md@SHA` when installing dispatched +`package_lock_sha256` for a package-root annotation. gh-aw v1.0.1 emits +`github/squad/workflows@SHA` for direct package includes, but can emit +`github/squad/workflows/package/.md@SHA` when installing dispatched dependencies. Fresh and forced installs can therefore contain different mixtures. The verifier selects one digest from the exact, ownership- and source-validated annotation; it never tries both until one passes. Compiled source comments, @@ -2547,13 +2561,13 @@ all native lock bytes, and staged verification includes the unchanged consumer configuration. Squad never rewrites that file. Manifest generation and installation test fixtures seed isolated compiler action -locks with the immutable `setup` and `setup-cli` pins for gh-aw v0.91.5. Both +locks with the immutable `setup` and `setup-cli` pins for gh-aw v1.0.1. Both source variants use the real strict compiler and validate its version and emitted action pins. This avoids a second network resolution returning a mutable version tag when credentials or the API are unavailable. Missing or altered pins fail generation; mutable-tag compiled locks still fail installation integrity. -The v0.91.5 compiler owns the reserved `aw_context` dispatch input; workflow +The v1.0.1 compiler owns the reserved `aw_context` dispatch input; workflow sources must not declare it. The generated workflows retain that optional string input and Squad's existing provenance checks. The dispatcher alone uses Copilot SDK mode because this compiler disables native CLI web-fetch in offline @@ -2608,9 +2622,69 @@ other refs. --- +## gh-aw 1.x compatibility + +The bootstrap target is `github/squad` with a stable gh-aw 1.x release, +**without an exact patch-version lock on CLI installation**. The +[repository-agent prompt](https://github.com/github/squad/blob/dev/agents-agentic-workflows.md) +preserves the inspection, immutable-revision, installation-verification, +explicit-staging, and human-review gates. Select a published immutable Squad +revision carrying the migrated package contract; older upstream revisions do +not acquire compatibility merely because their repository name is unchanged. + +The current validated compiler is +[gh-aw v1.0.1](https://github.com/github/gh-aw/releases/tag/v1.0.1), with immutable +`setup` and `setup-cli` action SHA +`221ba4f4319de6b8e809d1a15528b3ae6a818aa5`. The tested official `darwin-arm64` +binary matched the published SHA256 checksum +`e159eca9db8d9fed6eee61695c6b9a9235c8fcc83bda3a0915773ca0a50e4288`. + +Compilation is not installation verification. The current verifier additionally +requires exactly v1.0.1 for package installer metadata and canonical compilation, +checks immutable compiler-action pins, and compares complete normalized lock +digests for workflow and package source annotations, including supported +failure-retention variants. Native upstream ownership is +`.github/aw/packages/github-squad-workflows-23a7638f599e.json`. Both the +package-owned runtime resources and their materialized destinations are checked. +Staged verification checks the exact owned files, not whole-directory claims. + +The stable-major preflight deliberately does not reinstall or downgrade an +existing stable 1.x CLI. **This does not promise compatibility with arbitrary +future 1.x releases:** a different installer/compiler version or different +compiled bytes fails the published contract. Stop and request a reviewed package +update instead of changing consumer ownership records or trusted digests. + +The first-install approval list is the two optional secrets +`SQUAD_GITHUB_APP_PRIVATE_KEY`, `SQUAD_GITHUB_TOKEN`, and the immutable +`github/squad/.github/actions/squad-init` action. The workflow explicitly selects +`github/squad` release assets; the older pinned action's fork default is not used. +The 1.0.1 compiler adds `checks: read` to Bootstrap's conclusion job for its +compiler-owned diagnostic reporting. Review that read permission along with the +rest of the emitted artifact. The two documented source warnings remain +`pull_request_target` in `squad-review.md` and combined `slash_command`/`bots` in +`squad.md`. Local compilation and installation checks do not prove hosted +activation, repository Actions policy, or GitHub App permissions. + +For maintainers upgrading the compiler: review the official release and immutable +action SHA, update the verifier and runtime-test pins together, then run +`node workflows/shared/squad-install-verifier.mjs --write-source` followed by +`node workflows/shared/squad-install-verifier.mjs --check-source` with that +compiler (`SQUAD_GH_AW_BIN` can select a standalone official binary). Run the real +compile/install/staging and mutation suites, inspect permissions and warnings, +and publish the coherent source/package/manifest/tests revision. Consumers then +select that approved immutable revision. Never regenerate the trusted contract +inside a consumer repository to make its installation pass. + +The original upstream revision +`7b731ec97f35346bdc4fa87c3edaf16b808fc0ae` demonstrated why the complete migration +was necessary: v1.0.1 installation, materialization, and strict compilation +succeeded, but `--verify-install --source-revision` failed with +`Expected exactly one bradygaster/squad/workflows ownership record; found 0.` +That historical failure is not the contract of a revision carrying this migration. + ## See also -- [Squad README](https://github.com/bradygaster/squad#readme) — project overview and local CLI usage -- [Workflow definition](https://github.com/bradygaster/squad/blob/dev/workflows/squad.md) — full slash command specification -- [Implementation worker](https://github.com/bradygaster/squad/blob/dev/workflows/squad-implement-worker.md) — isolated issue implementation workflow -- [Bootstrap component](https://github.com/bradygaster/squad/blob/dev/workflows/shared/squad.md) — activation and artifact lifecycle +- [Squad README](https://github.com/github/squad#readme) — project overview and local CLI usage +- [Workflow definition](https://github.com/github/squad/blob/dev/workflows/squad.md) — full slash command specification +- [Implementation worker](https://github.com/github/squad/blob/dev/workflows/squad-implement-worker.md) — isolated issue implementation workflow +- [Bootstrap component](https://github.com/github/squad/blob/dev/workflows/shared/squad.md) — activation and artifact lifecycle diff --git a/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md b/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md index 0a02b6d01..9c150881f 100644 --- a/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md +++ b/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md @@ -25,7 +25,7 @@ bootstrap pull request** — never an auto-merge. This skill **operationalizes** the supported bootstrap path. It does not summarize it: each step below is a gate with explicit success evidence and **STOP conditions**. The authoritative source is `docs/src/content/docs/guide/gh-aw.md` (mirrored at -`https://bradygaster.github.io/squad/docs/guide/gh-aw/`). If that guide and this +`https://github.github.com/squad/guide/gh-aw/`). If that guide and this skill ever disagree, the guide wins — re-read it before proceeding. GitHub Issues are a hard prerequisite: `/squad` commands arrive as issue @@ -54,16 +54,15 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status -# Prove the exact package-capable compiler version before creating artifacts +# Require stable gh-aw 1.x without pinning the CLI installation to a patch # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -71,8 +70,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -87,21 +86,27 @@ git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> capture both output streams from `gh aw --version`. On any mismatch, remove -> `github/gh-aw`, cleanly install the exact `v0.91.5` pin, and verify both -> streams again. Stop before branch creation or file generation unless that -> second check proves exactly `v0.91.5`; never select a newer release. +> capture both output streams from `gh aw --version`. If absent or 0.x, cleanly +> install the current stable `github/gh-aw` release without `--pin` and verify +> both streams again. Stop unless the result is a stable 1.x release; never +> downgrade a newer major version automatically. The current package validates +> v1.0.1 compiler bytes and immutable action pins. Other 1.x releases require +> a maintainer-reviewed package update, not a consumer-side digest refresh. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. -- **STOP** if exact gh-aw `v0.91.5` cannot be proven after the clean pinned - reinstall. Do not create a branch or generate repository files. +- **STOP** if stable gh-aw 1.x cannot be proven after installation, or the + package's published compiler contract does not cover the installed release. + Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation run and the requested `@copilot` review both depend on it. +- Before installation, record whether `.vscode/settings.json` and + `.github/workflows/agentics-maintenance.yml` already exist. Preserve pre-existing + files; stop and report their diff if gh-aw changes them. ### 1. Require GitHub Issues, then allow Actions-created PRs with a read-only token @@ -193,13 +198,13 @@ published release guidance, then set it once: echo "STOP: SQUAD_SHA must be the exact 40-character commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` The nested `workflows/aw.yml` is the only supported distribution registration. It isolates package auto-discovery from unrelated repository skills and agents, -and installs exactly eight workflows, seventeen runtime resources, and one +and installs exactly eight workflows, twenty-one runtime resources, and one `gh-aw-enlistment` skill at the same resolved revision: - `squad.md` + `squad.lock.yml` @@ -217,7 +222,7 @@ governance-scoped retrospective proposal (see the gh-aw guide's retrospective auto-implementation section); installing it alongside the other seven keeps the full stack consistent and avoids a second bootstrap pass later. -gh-aw v0.91.5 also materializes +gh-aw v1.0.1 also materializes `.github/skills/agentic-workflows/SKILL.md`. That generic tool-owned router is not part of the Squad package and directs agents to mutable prompts from the current `github/gh-aw` repository rather than the pinned Squad revision. Remove @@ -247,7 +252,7 @@ On a clean repo, `gh aw add` reports these expected safe updates and **nothing e - Restricted secrets: **`SQUAD_GITHUB_APP_PRIVATE_KEY`** and **`SQUAD_GITHUB_TOKEN`** -- Action: **`bradygaster/squad/.github/actions/squad-init`** +- Action: **`github/squad/.github/actions/squad-init`** > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets @@ -285,7 +290,7 @@ This must run after any first-install approval and before committing. Success criteria: - All eight workflows compile successfully. -- With gh-aw v0.91.5, require exactly two warnings, one occurrence of each +- With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -335,15 +340,22 @@ If `.github/aw/logs/` lacks a `.gitignore`, add one there: !.gitignore ``` -`gh aw add` may also create `.vscode/settings.json` (enables Copilot for Markdown -workflow files). This is an **optional editor setting** — the stage command below -intentionally leaves it untracked. Delete it if unwanted, or stage it explicitly -if your team wants to share it. Decide deliberately; do not stage it by accident. +gh-aw v1.0.1 may generate two auxiliary outputs: `.vscode/settings.json` +(optional Markdown editor settings) and `.github/workflows/agentics-maintenance.yml` +(the compiler's maintenance workflow). Neither is authenticated by Squad's +package manifest. Leave both outside the bootstrap PR by default; the staging +commands below exclude them. Review and stage an auxiliary file by its exact +path only after explicit approval. + +Only remove an unwanted auxiliary file if it was absent before installation +and was created by this invocation. Never delete or overwrite pre-existing +editor settings or maintenance workflows. Known, newly generated auxiliary +files left untracked are expected output, not an unrelated-change failure. Stage **only** the documented generated surfaces, then verify the staged set: ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -498,7 +510,7 @@ git switch -c chore/squad-gh-aw-bootstrap echo "STOP: SQUAD_SHA must be an explicit, maintainer-approved 40-character lowercase hex commit SHA." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # Safe-update report shows ONLY the two documented secrets + squad-init → approve once @@ -508,7 +520,7 @@ gh aw compile --strict # final, no --approve; exactly the two document node .github/workflows/shared/squad-install-verifier.mjs \ --verify-install --source-revision "${SQUAD_SHA}" --strict-compile -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git commit -m "ci: add Squad agentic workflow" @@ -566,7 +578,7 @@ gh pr merge --squash # auto-merge before human review. NEVER. `.github/skills/agentic-workflows/SKILL.md`; keep the exact Squad-owned `.github/skills/gh-aw-enlistment/SKILL.md`. - ❌ **Approving unknown safe updates.** Approve ONLY `SQUAD_GITHUB_APP_PRIVATE_KEY`, - `SQUAD_GITHUB_TOKEN`, and `bradygaster/squad/.github/actions/squad-init`. Anything + `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Anything else is a STOP. - ❌ **Treating `--approve` as the final compile.** Always finish with a plain `gh aw compile --strict` (no `--approve`). diff --git a/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md b/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md index 0a02b6d01..9c150881f 100644 --- a/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md +++ b/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md @@ -25,7 +25,7 @@ bootstrap pull request** — never an auto-merge. This skill **operationalizes** the supported bootstrap path. It does not summarize it: each step below is a gate with explicit success evidence and **STOP conditions**. The authoritative source is `docs/src/content/docs/guide/gh-aw.md` (mirrored at -`https://bradygaster.github.io/squad/docs/guide/gh-aw/`). If that guide and this +`https://github.github.com/squad/guide/gh-aw/`). If that guide and this skill ever disagree, the guide wins — re-read it before proceeding. GitHub Issues are a hard prerequisite: `/squad` commands arrive as issue @@ -54,16 +54,15 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status -# Prove the exact package-capable compiler version before creating artifacts +# Require stable gh-aw 1.x without pinning the CLI installation to a patch # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -71,8 +70,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -87,21 +86,27 @@ git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> capture both output streams from `gh aw --version`. On any mismatch, remove -> `github/gh-aw`, cleanly install the exact `v0.91.5` pin, and verify both -> streams again. Stop before branch creation or file generation unless that -> second check proves exactly `v0.91.5`; never select a newer release. +> capture both output streams from `gh aw --version`. If absent or 0.x, cleanly +> install the current stable `github/gh-aw` release without `--pin` and verify +> both streams again. Stop unless the result is a stable 1.x release; never +> downgrade a newer major version automatically. The current package validates +> v1.0.1 compiler bytes and immutable action pins. Other 1.x releases require +> a maintainer-reviewed package update, not a consumer-side digest refresh. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. -- **STOP** if exact gh-aw `v0.91.5` cannot be proven after the clean pinned - reinstall. Do not create a branch or generate repository files. +- **STOP** if stable gh-aw 1.x cannot be proven after installation, or the + package's published compiler contract does not cover the installed release. + Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation run and the requested `@copilot` review both depend on it. +- Before installation, record whether `.vscode/settings.json` and + `.github/workflows/agentics-maintenance.yml` already exist. Preserve pre-existing + files; stop and report their diff if gh-aw changes them. ### 1. Require GitHub Issues, then allow Actions-created PRs with a read-only token @@ -193,13 +198,13 @@ published release guidance, then set it once: echo "STOP: SQUAD_SHA must be the exact 40-character commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` The nested `workflows/aw.yml` is the only supported distribution registration. It isolates package auto-discovery from unrelated repository skills and agents, -and installs exactly eight workflows, seventeen runtime resources, and one +and installs exactly eight workflows, twenty-one runtime resources, and one `gh-aw-enlistment` skill at the same resolved revision: - `squad.md` + `squad.lock.yml` @@ -217,7 +222,7 @@ governance-scoped retrospective proposal (see the gh-aw guide's retrospective auto-implementation section); installing it alongside the other seven keeps the full stack consistent and avoids a second bootstrap pass later. -gh-aw v0.91.5 also materializes +gh-aw v1.0.1 also materializes `.github/skills/agentic-workflows/SKILL.md`. That generic tool-owned router is not part of the Squad package and directs agents to mutable prompts from the current `github/gh-aw` repository rather than the pinned Squad revision. Remove @@ -247,7 +252,7 @@ On a clean repo, `gh aw add` reports these expected safe updates and **nothing e - Restricted secrets: **`SQUAD_GITHUB_APP_PRIVATE_KEY`** and **`SQUAD_GITHUB_TOKEN`** -- Action: **`bradygaster/squad/.github/actions/squad-init`** +- Action: **`github/squad/.github/actions/squad-init`** > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets @@ -285,7 +290,7 @@ This must run after any first-install approval and before committing. Success criteria: - All eight workflows compile successfully. -- With gh-aw v0.91.5, require exactly two warnings, one occurrence of each +- With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -335,15 +340,22 @@ If `.github/aw/logs/` lacks a `.gitignore`, add one there: !.gitignore ``` -`gh aw add` may also create `.vscode/settings.json` (enables Copilot for Markdown -workflow files). This is an **optional editor setting** — the stage command below -intentionally leaves it untracked. Delete it if unwanted, or stage it explicitly -if your team wants to share it. Decide deliberately; do not stage it by accident. +gh-aw v1.0.1 may generate two auxiliary outputs: `.vscode/settings.json` +(optional Markdown editor settings) and `.github/workflows/agentics-maintenance.yml` +(the compiler's maintenance workflow). Neither is authenticated by Squad's +package manifest. Leave both outside the bootstrap PR by default; the staging +commands below exclude them. Review and stage an auxiliary file by its exact +path only after explicit approval. + +Only remove an unwanted auxiliary file if it was absent before installation +and was created by this invocation. Never delete or overwrite pre-existing +editor settings or maintenance workflows. Known, newly generated auxiliary +files left untracked are expected output, not an unrelated-change failure. Stage **only** the documented generated surfaces, then verify the staged set: ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -498,7 +510,7 @@ git switch -c chore/squad-gh-aw-bootstrap echo "STOP: SQUAD_SHA must be an explicit, maintainer-approved 40-character lowercase hex commit SHA." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # Safe-update report shows ONLY the two documented secrets + squad-init → approve once @@ -508,7 +520,7 @@ gh aw compile --strict # final, no --approve; exactly the two document node .github/workflows/shared/squad-install-verifier.mjs \ --verify-install --source-revision "${SQUAD_SHA}" --strict-compile -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git commit -m "ci: add Squad agentic workflow" @@ -566,7 +578,7 @@ gh pr merge --squash # auto-merge before human review. NEVER. `.github/skills/agentic-workflows/SKILL.md`; keep the exact Squad-owned `.github/skills/gh-aw-enlistment/SKILL.md`. - ❌ **Approving unknown safe updates.** Approve ONLY `SQUAD_GITHUB_APP_PRIVATE_KEY`, - `SQUAD_GITHUB_TOKEN`, and `bradygaster/squad/.github/actions/squad-init`. Anything + `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Anything else is a STOP. - ❌ **Treating `--approve` as the final compile.** Always finish with a plain `gh aw compile --strict` (no `--approve`). diff --git a/scripts/gh-aw-hosted-e2e.mjs b/scripts/gh-aw-hosted-e2e.mjs index dce37b8bc..a1b37a7f7 100644 --- a/scripts/gh-aw-hosted-e2e.mjs +++ b/scripts/gh-aw-hosted-e2e.mjs @@ -25,10 +25,10 @@ import { } from '../workflows/shared/squad-install-verifier.mjs'; const TRUSTED_SOURCE = Object.freeze({ - repository: 'bradygaster/squad', + repository: 'github/squad', repositoryId: 1151205052, - owner: 'bradygaster', - ownerId: 41929050, + owner: 'github', + ownerId: 9919, }); const SHA_PATTERN = /^[0-9a-f]{40}$/; const INSTALL_PR_TITLE = 'ci: install Squad agentic workflows'; @@ -1226,9 +1226,9 @@ function hosted(args, repositoryRoot) { // Actions workflow or repository_dispatch job, and must never be run with a repository secret. // Run it from your own workstation, authenticated as yourself (`gh auth login`); `--evidence-in` // is a directory you populate yourself first, e.g. via -// `gh run download --repo bradygaster/squad \ +// `gh run download --repo github/squad \ // --name squad-gh-aw-hosted-e2e- --dir ` -// against the bradygaster/squad repository you already have read access to. Whatever GH_TOKEN is +// against the github/squad repository you already have read access to. Whatever GH_TOKEN is // present in your shell when you run this (your own personal token, never a repo secret) is what // it uses to observe the target repository. // diff --git a/templates/skills/gh-aw-enlistment/SKILL.md b/templates/skills/gh-aw-enlistment/SKILL.md index 0a02b6d01..9c150881f 100644 --- a/templates/skills/gh-aw-enlistment/SKILL.md +++ b/templates/skills/gh-aw-enlistment/SKILL.md @@ -25,7 +25,7 @@ bootstrap pull request** — never an auto-merge. This skill **operationalizes** the supported bootstrap path. It does not summarize it: each step below is a gate with explicit success evidence and **STOP conditions**. The authoritative source is `docs/src/content/docs/guide/gh-aw.md` (mirrored at -`https://bradygaster.github.io/squad/docs/guide/gh-aw/`). If that guide and this +`https://github.github.com/squad/guide/gh-aw/`). If that guide and this skill ever disagree, the guide wins — re-read it before proceeding. GitHub Issues are a hard prerequisite: `/squad` commands arrive as issue @@ -54,16 +54,15 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status -# Prove the exact package-capable compiler version before creating artifacts +# Require stable gh-aw 1.x without pinning the CLI installation to a patch # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -71,8 +70,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -87,21 +86,27 @@ git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> capture both output streams from `gh aw --version`. On any mismatch, remove -> `github/gh-aw`, cleanly install the exact `v0.91.5` pin, and verify both -> streams again. Stop before branch creation or file generation unless that -> second check proves exactly `v0.91.5`; never select a newer release. +> capture both output streams from `gh aw --version`. If absent or 0.x, cleanly +> install the current stable `github/gh-aw` release without `--pin` and verify +> both streams again. Stop unless the result is a stable 1.x release; never +> downgrade a newer major version automatically. The current package validates +> v1.0.1 compiler bytes and immutable action pins. Other 1.x releases require +> a maintainer-reviewed package update, not a consumer-side digest refresh. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. -- **STOP** if exact gh-aw `v0.91.5` cannot be proven after the clean pinned - reinstall. Do not create a branch or generate repository files. +- **STOP** if stable gh-aw 1.x cannot be proven after installation, or the + package's published compiler contract does not cover the installed release. + Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation run and the requested `@copilot` review both depend on it. +- Before installation, record whether `.vscode/settings.json` and + `.github/workflows/agentics-maintenance.yml` already exist. Preserve pre-existing + files; stop and report their diff if gh-aw changes them. ### 1. Require GitHub Issues, then allow Actions-created PRs with a read-only token @@ -193,13 +198,13 @@ published release guidance, then set it once: echo "STOP: SQUAD_SHA must be the exact 40-character commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` The nested `workflows/aw.yml` is the only supported distribution registration. It isolates package auto-discovery from unrelated repository skills and agents, -and installs exactly eight workflows, seventeen runtime resources, and one +and installs exactly eight workflows, twenty-one runtime resources, and one `gh-aw-enlistment` skill at the same resolved revision: - `squad.md` + `squad.lock.yml` @@ -217,7 +222,7 @@ governance-scoped retrospective proposal (see the gh-aw guide's retrospective auto-implementation section); installing it alongside the other seven keeps the full stack consistent and avoids a second bootstrap pass later. -gh-aw v0.91.5 also materializes +gh-aw v1.0.1 also materializes `.github/skills/agentic-workflows/SKILL.md`. That generic tool-owned router is not part of the Squad package and directs agents to mutable prompts from the current `github/gh-aw` repository rather than the pinned Squad revision. Remove @@ -247,7 +252,7 @@ On a clean repo, `gh aw add` reports these expected safe updates and **nothing e - Restricted secrets: **`SQUAD_GITHUB_APP_PRIVATE_KEY`** and **`SQUAD_GITHUB_TOKEN`** -- Action: **`bradygaster/squad/.github/actions/squad-init`** +- Action: **`github/squad/.github/actions/squad-init`** > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets @@ -285,7 +290,7 @@ This must run after any first-install approval and before committing. Success criteria: - All eight workflows compile successfully. -- With gh-aw v0.91.5, require exactly two warnings, one occurrence of each +- With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -335,15 +340,22 @@ If `.github/aw/logs/` lacks a `.gitignore`, add one there: !.gitignore ``` -`gh aw add` may also create `.vscode/settings.json` (enables Copilot for Markdown -workflow files). This is an **optional editor setting** — the stage command below -intentionally leaves it untracked. Delete it if unwanted, or stage it explicitly -if your team wants to share it. Decide deliberately; do not stage it by accident. +gh-aw v1.0.1 may generate two auxiliary outputs: `.vscode/settings.json` +(optional Markdown editor settings) and `.github/workflows/agentics-maintenance.yml` +(the compiler's maintenance workflow). Neither is authenticated by Squad's +package manifest. Leave both outside the bootstrap PR by default; the staging +commands below exclude them. Review and stage an auxiliary file by its exact +path only after explicit approval. + +Only remove an unwanted auxiliary file if it was absent before installation +and was created by this invocation. Never delete or overwrite pre-existing +editor settings or maintenance workflows. Known, newly generated auxiliary +files left untracked are expected output, not an unrelated-change failure. Stage **only** the documented generated surfaces, then verify the staged set: ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -498,7 +510,7 @@ git switch -c chore/squad-gh-aw-bootstrap echo "STOP: SQUAD_SHA must be an explicit, maintainer-approved 40-character lowercase hex commit SHA." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # Safe-update report shows ONLY the two documented secrets + squad-init → approve once @@ -508,7 +520,7 @@ gh aw compile --strict # final, no --approve; exactly the two document node .github/workflows/shared/squad-install-verifier.mjs \ --verify-install --source-revision "${SQUAD_SHA}" --strict-compile -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git commit -m "ci: add Squad agentic workflow" @@ -566,7 +578,7 @@ gh pr merge --squash # auto-merge before human review. NEVER. `.github/skills/agentic-workflows/SKILL.md`; keep the exact Squad-owned `.github/skills/gh-aw-enlistment/SKILL.md`. - ❌ **Approving unknown safe updates.** Approve ONLY `SQUAD_GITHUB_APP_PRIVATE_KEY`, - `SQUAD_GITHUB_TOKEN`, and `bradygaster/squad/.github/actions/squad-init`. Anything + `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Anything else is a STOP. - ❌ **Treating `--approve` as the final compile.** Always finish with a plain `gh aw compile --strict` (no `--approve`). diff --git a/test/gh-aw-activate-fast-path-label-provisioning.test.ts b/test/gh-aw-activate-fast-path-label-provisioning.test.ts index b01448691..929229f32 100644 --- a/test/gh-aw-activate-fast-path-label-provisioning.test.ts +++ b/test/gh-aw-activate-fast-path-label-provisioning.test.ts @@ -254,7 +254,7 @@ describe('gh-aw: native compiled policy remains bounded outside activation', () const prefix = process.env.SQUAD_GH_AW_BIN ? [] : ['aw']; const version = spawnSync(compiler, [...prefix, '--version'], { encoding: 'utf8' }); expect(version.status, 'Supported gh-aw is required; this contract never skips').toBe(0); - expect(`${version.stdout}\n${version.stderr}`).toContain('v0.91.5'); + expect(`${version.stdout}\n${version.stderr}`).toContain('v1.0.1'); const root = workspace('compile-'); execFileSync('git', ['init', '--quiet'], { cwd: root }); cpSync(WORKFLOWS_DIR, join(root, '.github/workflows'), { recursive: true }); diff --git a/test/gh-aw-activation-capacity.test.ts b/test/gh-aw-activation-capacity.test.ts index 148ba9362..86ce23ac4 100644 --- a/test/gh-aw-activation-capacity.test.ts +++ b/test/gh-aw-activation-capacity.test.ts @@ -255,7 +255,7 @@ describe('gh-aw: configured native caps cover both readings of max (#1961)', () const GH_AW_INSTALL_HINT = '`gh aw` is required to compile the workflow this gate inspects. Install it with ' + - '`gh extension install --pin v0.91.5 github/gh-aw` (matches .github/workflows/squad-ci.yml). ' + + '`gh extension install --pin v1.0.1 github/gh-aw` (matches .github/workflows/squad-ci.yml). ' + 'This gate fails closed rather than skipping: an unmeasured contract is ' + 'indistinguishable from a violated one (#1834).'; @@ -267,7 +267,7 @@ describe('gh-aw: compiled runtime proves the capacity contract (#1961)', () => { const prefix = process.env.SQUAD_GH_AW_BIN ? [] : ['aw']; const versionProbe = spawnSync(compiler, [...prefix, '--version'], { encoding: 'utf8' }); if (versionProbe.status !== 0) throw new Error(`gh aw --version failed. ${GH_AW_INSTALL_HINT}`); - expect(`${versionProbe.stdout}\n${versionProbe.stderr}`).toContain('v0.91.5'); + expect(`${versionProbe.stdout}\n${versionProbe.stderr}`).toContain('v1.0.1'); mkdirSync(TEST_WORKSPACES_DIR, { recursive: true }); const workspace = mkdtempSync(join(TEST_WORKSPACES_DIR, 'capacity-')); execFileSync('git', ['init', '--quiet'], { cwd: workspace }); diff --git a/test/gh-aw-activation-finalization.test.ts b/test/gh-aw-activation-finalization.test.ts index c65451ef9..9b9e5cd15 100644 --- a/test/gh-aw-activation-finalization.test.ts +++ b/test/gh-aw-activation-finalization.test.ts @@ -1180,6 +1180,7 @@ describe('trusted synchronous publication completion (source and strict-compiled if (name === join(f.root, 'gh-aw/actions/index.cjs')) return api; if (name === join(f.root, 'gh-aw/actions/sanitize_content.cjs')) return runtime.load('js/sanitize_content.cjs'); if (name === join(f.root, 'gh-aw/actions/issue_body.cjs')) return runtime.load('js/issue_body.cjs'); + if (name === join(f.root, 'gh-aw/actions/report_ast.cjs')) return runtime.load('js/report_ast.cjs'); return createRequire(import.meta.url)(name); }, {}, {}, () => github, ); @@ -1212,11 +1213,21 @@ describe('trusted synchronous publication completion (source and strict-compiled const baselineRun = compiled(baseline); await baselineRun.create(await baselineRun.prepare()); const attributedBody = baseline.writes.find(write => write.method === 'createIssue')!.params.body; + const probeSize = async (units: number) => { + const probe = fixture({ count: 1 }); + probe.comments.get(10)!.body += '\nx'.repeat(units); + const probeRun = compiled(probe); + await probeRun.create(await probeRun.prepare()); + return probe.writes.find(write => write.method === 'createIssue')!.params.body.length; + }; + const firstProbe = await probeSize(100); + const unitSize = (await probeSize(200) - firstProbe) / 100; + const paragraphOffset = firstProbe - attributedBody.length - 100 * unitSize; const f = fixture({ count: 1 }); - const extra = size - attributedBody.length; - const newlines = Math.floor((extra - (unicode ? 3 : 1)) / 3); - f.comments.get(10)!.body += '\n'.repeat(newlines) + (unicode ? '😀' : '') - + 'x'.repeat(extra - newlines * 3 - (unicode ? 2 : 0)); + const extra = size - attributedBody.length - paragraphOffset; + const units = Math.floor((extra - (unicode ? 2 : 0)) / unitSize); + f.comments.get(10)!.body += '\nx'.repeat(units) + (unicode ? '😀' : '') + + 'x'.repeat(extra - units * unitSize - (unicode ? 2 : 0)); const run = compiled(f); const capture = await run.prepare(); if (size > 65536) { diff --git a/test/gh-aw-activation-label-provisioning.test.ts b/test/gh-aw-activation-label-provisioning.test.ts index 646016e96..7be706293 100644 --- a/test/gh-aw-activation-label-provisioning.test.ts +++ b/test/gh-aw-activation-label-provisioning.test.ts @@ -349,7 +349,7 @@ describe('gh-aw: retained native add-labels compiled contract', () => { const prefix = process.env.SQUAD_GH_AW_BIN ? [] : ['aw']; const version = spawnSync(compiler, [...prefix, '--version'], { encoding: 'utf8' }); expect(version.status, 'Supported gh-aw is required; never skip this gate').toBe(0); - expect(`${version.stdout}\n${version.stderr}`).toContain('v0.91.5'); + expect(`${version.stdout}\n${version.stderr}`).toContain('v1.0.1'); const root = workspace('compile-'); execFileSync('git', ['init', '--quiet'], { cwd: root }); cpSync(WORKFLOWS_DIR, join(root, '.github/workflows'), { recursive: true }); diff --git a/test/gh-aw-activation-temporary-ids.test.ts b/test/gh-aw-activation-temporary-ids.test.ts index 9aaac2404..2aa173dc6 100644 --- a/test/gh-aw-activation-temporary-ids.test.ts +++ b/test/gh-aw-activation-temporary-ids.test.ts @@ -137,7 +137,7 @@ describe('gh-aw: create receipts require actual API-return identities', () => { // Native safe-output constraints still apply to non-activation commands. const GH_AW_INSTALL_HINT = '`gh aw` is required to compile the workflow this gate inspects. Install it with ' + - '`gh extension install --pin v0.91.5 github/gh-aw` (matches .github/workflows/squad-ci.yml). ' + + '`gh extension install --pin v1.0.1 github/gh-aw` (matches .github/workflows/squad-ci.yml). ' + 'This gate fails closed rather than skipping: an unmeasured contract is ' + 'indistinguishable from a violated one (#1834).'; @@ -150,7 +150,7 @@ describe('gh-aw: require-temporary-id compiles into the real safe-output config const prefix = process.env.SQUAD_GH_AW_BIN ? [] : ['aw']; const versionProbe = spawnSync(compiler, [...prefix, '--version'], { encoding: 'utf8' }); if (versionProbe.status !== 0) throw new Error(`gh aw --version failed. ${GH_AW_INSTALL_HINT}`); - expect(`${versionProbe.stdout}\n${versionProbe.stderr}`).toContain('v0.91.5'); + expect(`${versionProbe.stdout}\n${versionProbe.stderr}`).toContain('v1.0.1'); mkdirSync(TEST_WORKSPACES_DIR, { recursive: true }); const workspace = mkdtempSync(join(TEST_WORKSPACES_DIR, 'temp-ids-')); execFileSync('git', ['init', '--quiet'], { cwd: workspace }); diff --git a/test/gh-aw-command-authorization.test.ts b/test/gh-aw-command-authorization.test.ts index 8f6f7612f..754a780db 100644 --- a/test/gh-aw-command-authorization.test.ts +++ b/test/gh-aw-command-authorization.test.ts @@ -57,7 +57,7 @@ beforeAll(async () => { // in memory, with no GitHub clients or writes and no approximate sanitizer stubs. const runtimeSha = DIAGNOSTIC_RUNTIME_SHA; expect(fixture.consumerFiles.get('.github/workflows/squad.lock.yml')!.toString()) - .toContain(`github/gh-aw-actions/setup@${runtimeSha} # v0.91.5`); + .toContain(`github/gh-aw-actions/setup@${runtimeSha} # v1.0.1`); const sources = new Map(await Promise.all([ 'sanitize_content.cjs', 'sanitize_content_core.cjs', 'markdown_code_region_balancer.cjs', 'repo_helpers.cjs', 'slash_command_matcher.cjs', 'glob_pattern_helpers.cjs', 'error_codes.cjs', @@ -271,6 +271,31 @@ async function writeComments(items: Item[]) { } describe('compiled Squad command authorization boundary (#2185)', () => { + it('permits pure IP parsing but forbids sockets in the pinned runtime harness', () => { + const sources = new Map([['js/net_probe.cjs', ` + const net = require('net'); + module.exports = { + isIP: net.isIP, + connect: () => require('node:net').connect(), + socket: () => new net.Socket(), + tls: () => require('tls').connect(), + database: () => new (require('node:sqlite').DatabaseSync)('/outside-fixture.db'), + }; + `]]); + const runtime = diagnosticRuntime(sources, scratch, [], {}); + const probe = runtime.load('js/net_probe.cjs'); + expect(probe.isIP('127.0.0.1')).toBe(4); + expect(probe.isIP('::1')).toBe(6); + expect(() => probe.connect()).toThrow('Forbidden external IO: node:net.connect'); + expect(() => probe.socket()).toThrow('Forbidden external IO: net.Socket'); + expect(() => probe.tls()).toThrow('Forbidden external IO: tls.connect'); + expect(() => probe.database()).toThrow('Forbidden external IO: node:sqlite.DatabaseSync'); + expect(runtime.ioErrors).toEqual([ + 'Forbidden external IO: node:net.connect', 'Forbidden external IO: net.Socket', + 'Forbidden external IO: tls.connect', 'Forbidden external IO: node:sqlite.DatabaseSync', + ]); + }); + it('kills a live-source mutation that checks only HTML-comment-stripped authority', async () => { const source = readFileSync(join(trusted, 'squad-command-contract.mjs'), 'utf8'); const mutated = source.replace('const bodies = [rawBody, rawBody.replace(', 'const bodies = [rawBody.replace('); @@ -419,7 +444,7 @@ describe('compiled Squad command authorization boundary (#2185)', () => { expect(Object.keys(comment).sort()).toEqual(['body', 'data', 'item_number', 'temporary_id', 'type']); expect(comment.temporary_id).toMatch(/^aw_[A-Za-z0-9]{8}$/); expect(comment.data).toEqual(data); - expect(comment.body).toBe(`${requests[0].arguments.body}\n\nStructured data:\n\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``); + expect(comment.body).toBe(`## Plan\n\nDraft implementation tasks.\n\nStructured data:\n\n\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``); expect(lifecycle).toEqual({ type: 'upsert_lifecycle_state', body }); const result = await runGuard({ payload: payloadFor('plan'), permission: 'read', items: output.items }); const withoutMetadata = structuredClone(output.items); @@ -701,7 +726,7 @@ describe('compiled Squad command authorization boundary (#2185)', () => { }, ); - it('real pinned handlers expose the original tracking and completion writes when enabled', async () => { + it('real pinned handlers expose tracking and diagnostic writes when enabled', async () => { for (const existingIssue of [false, true]) { for (const [handler, items, env] of [ ['handle_agent_failure.cjs', [{ type: 'report_incomplete', reason: 'Could not finish' }], { GH_AW_FAILURE_REPORT_AS_ISSUE: 'true' }], @@ -722,7 +747,8 @@ describe('compiled Squad command authorization boundary (#2185)', () => { expect(runtime.ioErrors, `${handler}\n${runtime.logs.join('\n')}`).toEqual([]); expect(runtime.writes.length, `${handler}\n${runtime.logs.join('\n')}\n${runtime.failures}`).toBeGreaterThan(0); if (handler === 'notify_comment_error.cjs') { - expect(runtime.writes[0].params.body).toContain('"squad_artifact":"activated"'); + expect(runtime.writes[0].params.body).toContain('failed to deliver outputs'); + expect(runtime.writes[0].params.body).not.toContain('"squad_artifact":"activated"'); } } } diff --git a/test/gh-aw-compiler-compatibility.test.ts b/test/gh-aw-compiler-compatibility.test.ts new file mode 100644 index 000000000..574d5f0a8 --- /dev/null +++ b/test/gh-aw-compiler-compatibility.test.ts @@ -0,0 +1,89 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { execFileSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { + MIN_GH_AW_VERSION, + OWNERSHIP_DESTINATION, + PACKAGE_NAME, + materializeRuntime, + validateCompilerActionPins, + verifyInstall, + verifyStagedInstall, +} from '../workflows/shared/squad-install-verifier.mjs'; +import { createFirstInstallFixture } from './helpers/gh-aw-install-fixture.js'; + +const roots: string[] = []; +const revision = 'a'.repeat(40); + +function consumer(): string { + const root = mkdtempSync(join(tmpdir(), 'squad-compiler-compatibility-')); + roots.push(root); + execFileSync('git', ['init', '--quiet'], { cwd: root }); + const fixture = createFirstInstallFixture(revision, 'mixed'); + for (const [path, content] of fixture.consumerFiles) { + mkdirSync(dirname(join(root, path)), { recursive: true }); + writeFileSync(join(root, path), content); + } + mkdirSync(dirname(join(root, OWNERSHIP_DESTINATION)), { recursive: true }); + writeFileSync(join(root, OWNERSHIP_DESTINATION), JSON.stringify(fixture.provenance)); + materializeRuntime(root); + return root; +} + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +describe('gh-aw 1.x canonical upstream installation contract', () => { + it('binds the current compiler and native ownership to github/squad, not the fork', () => { + expect(MIN_GH_AW_VERSION, 'compiler contract must support the validated v1.0.1 release').toBe('v1.0.1'); + expect(PACKAGE_NAME, 'upstream install must own github/squad/workflows').toBe('github/squad/workflows'); + expect(OWNERSHIP_DESTINATION, 'staging must use the real github/squad ownership path') + .toBe('.github/aw/packages/github-squad-workflows-23a7638f599e.json'); + }); + + it('accepts actual v1.0.1 emitted locks and stages the canonical ownership record', () => { + const root = consumer(); + for (const name of ['squad-bootstrap', 'squad']) { + const path = `.github/workflows/${name}.lock.yml`; + const lock = readFileSync(join(root, path), 'utf8'); + expect(lock, `${path} must bind setup to the approved immutable v1.0.1 action`) + .toContain('github/gh-aw-actions/setup@221ba4f4319de6b8e809d1a15528b3ae6a818aa5'); + expect(() => validateCompilerActionPins(lock), `${path} emitted compiler pins`).not.toThrow(); + } + expect(verifyInstall(root, { expectedRevision: revision }).failures, root).toEqual([]); + execFileSync('git', ['add', '--', '.github/aw/', '.github/workflows/', '.github/skills/'], { cwd: root }); + expect(verifyStagedInstall(root, { expectedRevision: revision }).failures, root).toEqual([]); + }, 120_000); + + it.each([ + ['legacy installer', 'installer', 'gh-aw v0.91.5'], + ['unvalidated future compiler', 'installer', 'gh-aw v1.0.2'], + ['old fork identity', 'package', 'bradygaster/squad/workflows'], + ])('rejects the offending %s without trusting different compiler output', (label, key, value) => { + const root = consumer(); + const path = join(root, OWNERSHIP_DESTINATION); + const ownership = JSON.parse(readFileSync(path, 'utf8')); + ownership[key] = value; + writeFileSync(path, JSON.stringify(ownership)); + expect(verifyInstall(root, { expectedRevision: revision }).failures.join('\n'), `${label}: ${value}`) + .toMatch(/installer|ownership record/); + }, 120_000); + + it('rejects a realistic mutation of the emitted immutable compiler pin and complete lock bytes', () => { + const root = consumer(); + const path = '.github/workflows/squad-bootstrap.lock.yml'; + const lock = readFileSync(join(root, path), 'utf8'); + const mutation = lock.replaceAll( + '221ba4f4319de6b8e809d1a15528b3ae6a818aa5', + '16b430146d5d5646eccef5a1ceb72152333b18b9', + ); + expect(mutation, `${path} must contain the actual 1.0.1 pin before mutation`).not.toBe(lock); + expect(() => validateCompilerActionPins(mutation), `${path}: legacy setup SHA`) + .toThrow(/invalid immutable action pin/); + writeFileSync(join(root, path), mutation); + expect(verifyInstall(root).failures.join('\n'), `${path}: mutated compiler bytes`).toContain(path); + }, 120_000); +}); diff --git a/test/gh-aw-enlistment-skill.test.ts b/test/gh-aw-enlistment-skill.test.ts index 7d9ef7291..3944f575e 100644 --- a/test/gh-aw-enlistment-skill.test.ts +++ b/test/gh-aw-enlistment-skill.test.ts @@ -81,7 +81,7 @@ gh() { return 0 fi if [ "$1" = "extension" ] && [ "$2" = "install" ]; then - printf 'CALL install %s %s\\n' "$3" "$4" >&3 + printf 'CALL install %s %s\\n' "$3" "\${4:-}" >&3 installed=1 return 0 fi @@ -236,7 +236,7 @@ describe('gh-aw-enlistment skill', () => { [ 'SQUAD_GITHUB_APP_PRIVATE_KEY', 'SQUAD_GITHUB_TOKEN', - 'bradygaster/squad/.github/actions/squad-init', + 'github/squad/.github/actions/squad-init', ].sort() ); @@ -249,8 +249,8 @@ describe('gh-aw-enlistment skill', () => { expect(content).toContain(': "${SQUAD_SHA:?STOP: set SQUAD_SHA to an explicit, maintainer-approved 40-character Squad commit SHA before installing.}"'); expect(content).not.toContain('commits/dev'); expect(content).toContain('^' + '[0-9a-f]{40}' + '$'); - expect(content).toContain('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'); - expect(content).toContain('exactly eight workflows, seventeen runtime resources, and one'); + expect(content).toContain('gh aw add "github/squad/workflows@${SQUAD_SHA}"'); + expect(content).toContain('exactly eight workflows, twenty-one runtime resources, and one'); for (const workflow of [ 'squad.md', 'squad-implement-worker.md', @@ -318,7 +318,7 @@ describe('gh-aw-enlistment skill', () => { expect(content).toContain('STOP before branch creation or `gh aw add`'); expect(content.indexOf("issues_enabled=")).toBeLessThan(content.indexOf('git switch -c')); expect(content.indexOf("issues_enabled=")).toBeLessThan( - content.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'), + content.indexOf('gh aw add "github/squad/workflows@${SQUAD_SHA}"'), ); }); @@ -346,12 +346,13 @@ describe('gh-aw-enlistment skill', () => { expect(content).toContain('[Agentic Research] owner/repo — initial proposals'); }); - it('pins and verifies the package-capable gh-aw compiler', () => { + it('installs stable 1.x without a CLI patch pin and retains the separate compiler contract', () => { expect(content).toContain('gh_aw_version_output="$(gh aw --version 2>&1)"'); expect(content).toContain('gh extension remove gh-aw'); - expect(content).toContain('required_gh_aw_version="v0.91.5"'); - expect(content).toContain('gh extension install --pin "${required_gh_aw_version}" github/gh-aw'); - expect(content).toContain('never select a newer release'); + expect(content).toContain('gh extension install github/gh-aw'); + expect(content).not.toContain('gh extension install --pin'); + expect(content).toContain('never\n> downgrade a newer major version automatically'); + expect(content).toContain('v1.0.1 compiler bytes and immutable action pins'); expect(content).toContain('PowerShell'); }); @@ -394,42 +395,42 @@ describe('gh-aw-enlistment skill', () => { const agentGuide = readLF(AGENT_GUIDE); const versionGate = extractVersionGate(guide); - it('accepts an existing exact v0.91.5 installation without reinstalling', () => { - const result = runVersionGate(versionGate, 'v0.91.5', 'v0.91.5'); + it('accepts an existing exact v1.0.1 installation without reinstalling', () => { + const result = runVersionGate(versionGate, 'v1.0.1', 'v1.0.1'); expect(result.status).toBe(0); expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(1); expect(result.stderr).not.toContain('CALL remove'); expect(result.stderr).not.toContain('CALL install'); }); - it('captures exact v0.91.5 version output emitted on stderr', () => { - const result = runVersionGate(versionGate, 'v0.91.5', 'v0.91.5', 'stderr'); + it('captures exact v1.0.1 version output emitted on stderr', () => { + const result = runVersionGate(versionGate, 'v1.0.1', 'v1.0.1', 'stderr'); expect(result.status).toBe(0); expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(1); expect(result.stderr).not.toContain('CALL remove'); expect(result.stderr).not.toContain('CALL install'); }); - it('removes pre-existing v0.89.21 and verifies a clean v0.91.5 install', () => { - const result = runVersionGate(versionGate, 'v0.89.21', 'v0.91.5'); + it('removes pre-existing v0.89.21 and verifies a clean v1.0.1 install', () => { + const result = runVersionGate(versionGate, 'v0.89.21', 'v1.0.1'); expect(result.status).toBe(0); expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(2); expect(result.stderr.match(/^CALL remove$/gm)).toHaveLength(1); - expect(result.stderr.match(/^CALL install --pin v0\.91\.5$/gm)).toHaveLength(1); + expect(result.stderr.match(/^CALL install github\/gh-aw *$/gm)).toHaveLength(1); }); it('fails closed when a clean reinstall persistently reports v0.89.21', () => { const result = runVersionGate(versionGate, 'v0.89.21', 'v0.89.21'); expect(result.status).toBe(1); - expect(result.stderr).toContain('required gh-aw v0.91.5, but found v0.89.21'); + expect(result.stderr).toContain('stable gh-aw 1.x is required, but found v0.89.21'); expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(2); expect(result.stderr.match(/^CALL remove$/gm)).toHaveLength(1); - expect(result.stderr.match(/^CALL install --pin v0\.91\.5$/gm)).toHaveLength(1); + expect(result.stderr.match(/^CALL install github\/gh-aw *$/gm)).toHaveLength(1); expect(guide.indexOf(VERSION_GATE_END)).toBeLessThan( guide.indexOf('git switch -c chore/squad-gh-aw-bootstrap'), ); expect(guide.indexOf(VERSION_GATE_END)).toBeLessThan( - guide.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'), + guide.indexOf('gh aw add "github/squad/workflows@${SQUAD_SHA}"'), ); }); @@ -437,6 +438,21 @@ describe('gh-aw-enlistment skill', () => { expect(extractVersionGate(readLF(CANONICAL))).toBe(versionGate); }); + it.each(['v1.0.2', 'v1.12.3'])('does not pin or downgrade stable 1.x %s in the family preflight', (version) => { + const result = runVersionGate(versionGate, version, 'v1.0.1'); + expect(result.status, `stable 1.x preflight rejected ${version}`).toBe(0); + expect(result.stderr).not.toContain('CALL install'); + expect(result.stderr).not.toContain('CALL remove'); + }); + + it.each(['v1.0.1-preview', 'v2.0.0', 'unknown'])('rejects %s without automatically replacing a non-0.x installation', (version) => { + const result = runVersionGate(versionGate, version, 'v1.0.1'); + expect(result.status, `unsupported compiler family ${version} passed preflight`).toBe(1); + expect(result.stderr).toContain(`stable gh-aw 1.x is required, but found ${version}`); + expect(result.stderr).not.toContain('CALL install'); + expect(result.stderr).not.toContain('CALL remove'); + }); + it('checks the staged installation before every bootstrap commit', () => { expect(guide.match(/--verify-staged-install --stage-ownership --source-revision "\$\{SQUAD_SHA\}" \|\| exit 1/g)) .toHaveLength(2); @@ -478,7 +494,7 @@ describe('gh-aw-enlistment skill', () => { expect(guide).toContain('do not continue to `gh aw add`'); expect(issuesCheck).toBeLessThan(guide.indexOf('git switch -c chore/squad-gh-aw-bootstrap')); expect(issuesCheck).toBeLessThan( - guide.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'), + guide.indexOf('gh aw add "github/squad/workflows@${SQUAD_SHA}"'), ); expect(agentGuide).toContain('verifies that GitHub Issues are enabled'); expect(agentGuide).toContain('bootstrap creates a research/proposals issue'); @@ -489,7 +505,7 @@ describe('gh-aw-enlistment skill', () => { const readmeInstall = readme.slice(readme.indexOf('### Install')); expect(readmeInstall.indexOf("issues_enabled=")).toBeGreaterThan(-1); expect(readmeInstall.indexOf("issues_enabled=")).toBeLessThan( - readmeInstall.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'), + readmeInstall.indexOf('gh aw add "github/squad/workflows@${SQUAD_SHA}"'), ); expect(readmeInstall).toContain( 'test "$(gh api "repos/${owner_repo}" --jq \'.has_issues\')" = "true" || {', @@ -527,14 +543,14 @@ describe('gh-aw-enlistment skill', () => { }); it('makes public-guide package verification fail fast and coherent', () => { - expect(guide).toContain('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'); + expect(guide).toContain('gh aw add "github/squad/workflows@${SQUAD_SHA}"'); expect(guide).toContain('squad-install-verifier.mjs --materialize-runtime'); expect(guide).toContain('--verify-install'); expect(guide).toContain('--source-revision "${SQUAD_SHA}"'); expect(guide).toContain('--strict-compile'); expect(guide).toContain('package ownership metadata'); const upgrade = guide.slice(guide.indexOf('## Upgrading')); - const add = upgrade.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" --force'); + const add = upgrade.indexOf('gh aw add "github/squad/workflows@${SQUAD_SHA}" --force'); const cleanup = upgrade.indexOf('rm -f .github/skills/agentic-workflows/SKILL.md'); const compile = upgrade.indexOf('gh aw compile --strict'); const verify = upgrade.indexOf('squad-install-verifier.mjs \\\n --verify-install'); diff --git a/test/gh-aw-hosted-e2e.test.ts b/test/gh-aw-hosted-e2e.test.ts index 1de628462..a1d8cc7bf 100644 --- a/test/gh-aw-hosted-e2e.test.ts +++ b/test/gh-aw-hosted-e2e.test.ts @@ -36,7 +36,7 @@ const packageArtifactCases = [ ...CONTRACT.runtime.map(({ packageDestination }) => ['runtime package destination', packageDestination]), ...CONTRACT.runtime.map(({ destination }) => ['materialized runtime destination', destination]), ['installed manifest', '.github/aw/squad-workflows.manifest.json'], - ['package ownership metadata', '.github/aw/packages/bradygaster-squad-workflows-3632054824e8.json'], + ['package ownership metadata', '.github/aw/packages/github-squad-workflows-23a7638f599e.json'], ...CONTRACT.skills.map(({ destination }) => ['installed skill', destination]), ['trigger sentinel', '.github/workflows/shared/squad-bootstrap-trigger-probe.json'], ['package namespace residue', '.github/aw/squad/unknown-stale-file.md'], @@ -245,8 +245,10 @@ describe('Squad gh-aw hosted E2E controller', () => { }); it('binds source and target identities without caller-selected privileged code', () => { - expect(SCRIPT).toContain("repository: 'bradygaster/squad'"); + expect(SCRIPT).toContain("repository: 'github/squad'"); expect(SCRIPT).toContain('repositoryId: 1151205052'); + expect(SCRIPT).toContain("owner: 'github'"); + expect(SCRIPT).toContain('ownerId: 9919'); expect(SCRIPT).toContain('sourceRef !== `refs/heads/${info.default_branch}`'); expect(SCRIPT).toContain('branch.protected !== true || branch.sha !== sourceSha'); expect(SCRIPT).toContain('info.full_name !== target'); @@ -256,7 +258,7 @@ describe('Squad gh-aw hosted E2E controller', () => { it('loads only the exact canonical manifest and has no fallback contract', () => { const contract = loadBundleContract(ROOT); - expect(contract.package).toBe('bradygaster/squad/workflows'); + expect(contract.package).toBe('github/squad/workflows'); expect(contract.workflows).toHaveLength(8); expect(contract.runtime).toHaveLength(21); expect(contract.skills).toHaveLength(1); diff --git a/test/gh-aw-implement-workflow.test.ts b/test/gh-aw-implement-workflow.test.ts index 980b079db..9e8102310 100644 --- a/test/gh-aw-implement-workflow.test.ts +++ b/test/gh-aw-implement-workflow.test.ts @@ -262,7 +262,7 @@ describe('gh-aw implement workflows', () => { it('documents one immutable nested native package installation', () => { const normalizedGuide = guide.replace(/\r\n/g, '\n'); - expect(normalizedGuide).toContain('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'); + expect(normalizedGuide).toContain('gh aw add "github/squad/workflows@${SQUAD_SHA}"'); expect(normalizedGuide).toContain('exactly eight agentic workflows, twenty-one runtime'); expect(normalizedGuide).toContain('one enlistment skill'); expect(normalizedGuide).not.toMatch(/gh aw add \\\n\s+bradygaster\/squad\/workflows\/squad\.md/); @@ -1002,7 +1002,10 @@ describe('gh-aw implement worker: retro-origin provenance enforcement', () => { function assertRelay(lock: string) { const { jobs } = parse(lock); expect(jobs.repair_activated_lifecycle.if).toContain('!cancelled()'); - expect(jobs.repair_activated_lifecycle.if).not.toContain('${{'); + expect(jobs.repair_activated_lifecycle.if).toMatch(/^\$\{\{[\s\S]*\}\}$/); + expect(jobs.repair_activated_lifecycle.if.match(/\$\{\{/g)).toHaveLength(1); + expect(jobs.repair_activated_lifecycle.if).toContain("needs.detection.result == 'success'"); + expect(jobs.repair_activated_lifecycle.if).toContain("needs.detection.outputs.detection_success == 'true'"); for (const [jobName, stepName, following] of [ ['agent', 'Refuse merge relay without a clearing independent review', 'Execute GitHub Copilot CLI'], ['safe_outputs', 'Recheck clearing verdict before relay outputs', 'Process Safe Outputs'], diff --git a/test/gh-aw-install-staging.test.ts b/test/gh-aw-install-staging.test.ts index c22e6c461..13c535748 100644 --- a/test/gh-aw-install-staging.test.ts +++ b/test/gh-aw-install-staging.test.ts @@ -75,6 +75,27 @@ afterEach(() => { }); describe('gh-aw: verified ownership staging under consumer ignore rules', () => { + it('excludes unapproved gh-aw auxiliary outputs without deleting existing editor settings', () => { + const root = consumer(); + const settings = '.vscode/settings.json'; + const maintenance = '.github/workflows/agentics-maintenance.yml'; + const editorContent = '{"editor.tabSize":3,"github.copilot.enable":{"markdown":false}}\n'; + write(root, settings, editorContent); + write(root, maintenance, 'name: tool-generated maintenance\n'); + const guide = readFileSync(resolve('docs/src/content/docs/guide/gh-aw.md'), 'utf8'); + const staging = guide.match(/^git add -- .*$/m)![0]; + const args = staging.match(/'[^']*'|\S+/g)!.slice(1) + .map(argument => argument.startsWith("'") ? argument.slice(1, -1) : argument); + git(root, ...args); + expect(stagedPaths(root), `Unapproved auxiliary output staged by: ${staging}`) + .not.toContain(maintenance); + expect(stagedPaths(root)).not.toContain(settings); + expect(readFileSync(join(root, settings), 'utf8')).toBe(editorContent); + expect(readFileSync(join(root, maintenance), 'utf8')).toBe('name: tool-generated maintenance\n'); + expect(verifyStagedInstall(root, { expectedRevision: revision, stageOwnership: true }).failures) + .toEqual([]); + }); + it('installs a coherent reset-capable package and excludes only the named historical Cast', async () => { const root = consumer(); const reset = { @@ -227,7 +248,7 @@ describe('gh-aw: verified ownership staging under consumer ignore rules', () => ); expect(rejected.stderr).toContain([ 'Safe recovery:', - ` gh aw add bradygaster/squad/workflows@${revision} --force`, + ` gh aw add github/squad/workflows@${revision} --force`, ` rm -f ${UNOWNED_MUTABLE_ROUTER_SKILL}`, ' gh aw compile --strict', ' node .github/workflows/shared/squad-install-verifier.mjs --verify-install --strict-compile', diff --git a/test/gh-aw-quality.test.ts b/test/gh-aw-quality.test.ts index ed634f12c..68e658dd1 100644 --- a/test/gh-aw-quality.test.ts +++ b/test/gh-aw-quality.test.ts @@ -33,6 +33,7 @@ import { import { CONTRACT_DESTINATION, CONTRACT_SOURCE, + COMPILER_ACTION_PINS, MIN_GH_AW_VERSION, OWNERSHIP_ENTRY_COUNT, PACKAGE_NAME, @@ -1729,7 +1730,7 @@ describe('gh-aw: compiled workflow shell input security contract', () => { ref: '${{ github.workflow_sha }}', 'persist-credentials': false, path: '.squad-activation-trusted-base', }); expect(step('Setup pinned issue creation API').uses) - .toBe('github/gh-aw-actions/setup@16b430146d5d5646eccef5a1ceb72152333b18b9'); + .toBe('github/gh-aw-actions/setup@221ba4f4319de6b8e809d1a15528b3ae6a818aa5'); const prepare = step('Freeze and validate activation inputs'); const capture = step('Persist frozen activation capture'); const create = step('Reserve activation and record actual create results'); @@ -1783,16 +1784,15 @@ describe('gh-aw: compiled workflow shell input security contract', () => { const mutantPath = join(workspace, '.github', 'workflows', 'squad.md'); writeFileSync(mutantPath, readText(mutantPath).replace(safeExpression, `activation-comments: ${unsafeExpression}`)); - execFileSync('gh', ['aw', 'compile', mutantPath, '--strict', '--approve'], { + const compile = spawnSync('gh', ['aw', 'compile', mutantPath, '--strict', '--approve'], { cwd: workspace, encoding: 'utf8', stdio: 'pipe', }); - const mutantLock = readText(join(workspace, '.github', 'workflows', 'squad.lock.yml')); - expect(mutantLock).toMatch( - /\$\{\{[^}\n]*\\\\u0026\\\\u0026[^}\n]*\}\}/, - ); + expect(compile.status, `${mutantPath}: unsafe activation-comments expression must fail strict compilation`).not.toBe(0); + expect(`${compile.stdout}\n${compile.stderr}`, `${mutantPath}: compiler must identify the offending expression`) + .toContain('invalid Actions expression'); }, 20000); it('compiles the lifecycle upsert as a post-safe-output job (#1916)', () => { @@ -1936,11 +1936,13 @@ describe('gh-aw: compiled workflow shell input security contract', () => { /- name: Install Squad CLI from standalone release[\s\S]*?(?=\n\s+- name:)/, )?.[0]; expect(install, 'compiled squad.lock.yml must retain the standalone installer').toContain( - 'uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f', + 'uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f', ); expect(install, 'compiled squad.lock.yml must omit version to use the pinned action latest default') .not.toMatch(/^\s+version:/m); expect(install).toContain('skip-init: "true"'); + expect(install, 'the immutable action must not use its legacy fork release default') + .toContain('repository: github/squad'); expect(compiled, 'compiled squad.lock.yml must not contain the obsolete release resolver') .not.toContain('squad-release'); expect(compiled).not.toContain('vars.SQUAD_CLI_VERSION'); @@ -3610,7 +3612,7 @@ describe('gh-aw: shared bootstrap health-before-dispatch contract (#1605)', () = const healthLine = lines[healthLineIdx]; expect(healthLine, 'health must invoke the installed squad binary').toMatch(/\bsquad health --json/); expect(sharedContent).toContain( - 'uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f', + 'uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f', ); expect(sharedContent).not.toContain('squad-release'); expect(sharedContent).toContain('SQUAD_CLI_VERSION: ${{ steps.squad-cli.outputs.version }}'); @@ -4058,14 +4060,14 @@ describe('gh-aw: canonical package integrity contract', () => { destination: entry.destination, sha256: createHash('sha256').update(readFileSync(join(root, entry.destination))).digest('hex'), })).sort((left, right) => left.destination.localeCompare(right.destination)); - const ownership = join(root, '.github/aw/packages/bradygaster-squad-workflows-test.json'); + const ownership = join(root, '.github/aw/packages/github-squad-workflows-test.json'); mkdirSync(dirname(ownership), { recursive: true }); writeFileSync(ownership, `${JSON.stringify({ schemaVersion: 1, package: PACKAGE_NAME, source: `${PACKAGE_NAME}@${revision}`, resolvedCommit: revision, - installer: 'gh-aw v0.91.5 test', + installer: 'gh-aw v1.0.1 test', files: owned, }, null, 2)}\n`); return root; @@ -4124,7 +4126,7 @@ describe('gh-aw: canonical package integrity contract', () => { })); expect(contract.skills).toHaveLength(SKILL_TUPLES.length); expect(contract.skills).toHaveLength(1); - expect(contract.package).toBe('bradygaster/squad/workflows'); + expect(contract.package).toBe('github/squad/workflows'); expect(contract.manifest).toBe('workflows/aw.yml'); expect(contract.bootstrap.trigger_probe).toBe(TRIGGER_PROBE); expect(contract.shared_runtime.some((entry: { path: string }) => entry.path === TRIGGER_PROBE)).toBe(false); @@ -4192,7 +4194,7 @@ describe('gh-aw: canonical package integrity contract', () => { const root = makeConsumer(); expect(verifyInstall(root, { expectedRevision: revisionA }).failures).toEqual([]); const record = JSON.parse(readFileSync( - join(root, '.github/aw/packages/bradygaster-squad-workflows-test.json'), + join(root, '.github/aw/packages/github-squad-workflows-test.json'), 'utf8', )); expect(record.files).toHaveLength(OWNERSHIP_ENTRY_COUNT); @@ -4213,6 +4215,7 @@ describe('gh-aw: canonical package integrity contract', () => { if (name === 'squad-bootstrap') { expect(lock.jobs.conclusion.permissions).toEqual({ actions: 'read', + checks: 'read', issues: 'write', 'pull-requests': 'read', }); @@ -4312,14 +4315,14 @@ describe('gh-aw: canonical package integrity contract', () => { } }); - it.each(['v0.89.22', 'v0.91.4', 'v0.91.50', 'v0.91.5-preview'])( + it.each(['v0.89.22', 'v0.91.4', 'v1.0.10', 'v1.0.1-preview'])( 'rejects ownership from unsupported installer %s', version => { const root = makeConsumer(); - const path = join(root, '.github/aw/packages/bradygaster-squad-workflows-test.json'); + const path = join(root, '.github/aw/packages/github-squad-workflows-test.json'); const record = JSON.parse(readText(path)); record.installer = `gh-aw ${version}`; writeFileSync(path, JSON.stringify(record)); - expect(verifyInstall(root).failures.join('\n')).toContain('Package ownership installer must be gh-aw v0.91.5'); + expect(verifyInstall(root).failures.join('\n')).toContain('Package ownership installer must be gh-aw v1.0.1'); }, ); @@ -4397,8 +4400,12 @@ describe('gh-aw: canonical package integrity contract', () => { .toContain('Installed digest mismatch for .github/workflows/squad.lock.yml'); writeFileSync(lockPath, original); - for (const key of Object.keys(pins.entries)) { - for (const value of [undefined, MIN_GH_AW_VERSION, '0'.repeat(40)]) { + for (const { repo, version } of COMPILER_ACTION_PINS) { + const key = `${repo}@${version}`; + const values = repo.startsWith('github/gh-aw-actions/') + ? [undefined, MIN_GH_AW_VERSION, '0'.repeat(40)] + : [MIN_GH_AW_VERSION, '0'.repeat(40)]; + for (const value of values) { const altered = structuredClone(pins); if (value === undefined) delete altered.entries[key]; else altered.entries[key].sha = value; @@ -4440,23 +4447,22 @@ describe('gh-aw: canonical package integrity contract', () => { execFileSync('git', ['remote', 'add', 'origin', 'https://github.com/example/squad-consumer.git'], { cwd: root }); // A deliberately invalid test credential prevents fallback to local keychain authentication. const env = { ...process.env, GH_TOKEN: 'invalid-test-token', GITHUB_TOKEN: '' }; - const compile = () => execFileSync('gh', ['aw', 'compile', '--strict', '--no-check-update'], { - cwd: root, env, stdio: 'pipe', timeout: 120_000, + const compile = () => spawnSync('gh', ['aw', 'compile', '--strict', '--no-check-update'], { + cwd: root, env, encoding: 'utf8', timeout: 120_000, }); const lockPath = join(root, '.github/workflows/squad.lock.yml'); - compile(); - const unpinned = readText(lockPath); - expect(createHash('sha256').update(normalizeCompiledLock(unpinned, revisionA)).digest('hex')) - .not.toBe(JSON.parse(readText(join(root, CONTRACT_DESTINATION))).workflows - .find((entry: { name: string }) => entry.name === 'squad').package_lock_sha256); - expect(verifyInstall(root).failures.join('\n')).toContain('Installed digest mismatch'); + const unseeded = compile(); + expect(unseeded.status, `${root}: unseeded compilation with invalid credentials must fail closed`).not.toBe(0); + expect(`${unseeded.stdout}\n${unseeded.stderr}`, `${root}: report immutable action-resolution failure`) + .toMatch(/401|unauthorized|resolve/i); const seedPins = () => spawnSync(process.execPath, [helperPath], { cwd: root, env, encoding: 'utf8', timeout: 120_000, }); const seeded = seedPins(); expect(seeded.status, seeded.stderr).toBe(0); - compile(); + const compiled = compile(); + expect(compiled.status, `${compiled.stdout}\n${compiled.stderr}`).toBe(0); expect(verifyInstall(root, { expectedRevision: revisionA, strictCompile: true }).failures).toEqual([]); const contract = JSON.parse(readText(join(root, CONTRACT_DESTINATION))); for (const entry of contract.workflows) { @@ -4476,7 +4482,7 @@ describe('gh-aw: canonical package integrity contract', () => { }, 120_000); function updateOwnedDigest(root: string, destination: string): void { - const path = join(root, '.github/aw/packages/bradygaster-squad-workflows-test.json'); + const path = join(root, '.github/aw/packages/github-squad-workflows-test.json'); const record = JSON.parse(readFileSync(path, 'utf8')); const entry = record.files.find((file: { destination: string }) => file.destination === destination); entry.sha256 = createHash('sha256').update(readFileSync(join(root, destination))).digest('hex'); @@ -4488,8 +4494,8 @@ describe('gh-aw: canonical package integrity contract', () => { const sourcePath = '.github/workflows/squad-review.md'; const lockPath = '.github/workflows/squad-review.lock.yml'; const mutations: Array<[string, (text: string) => string]> = [ - ['wrong owner', text => text.replaceAll('bradygaster/squad', 'attacker/squad')], - ['wrong repo', text => text.replaceAll('bradygaster/squad', 'bradygaster/other')], + ['wrong owner', text => text.replaceAll('github/squad', 'attacker/squad')], + ['wrong repo', text => text.replaceAll('github/squad', 'bradygaster/other')], ['wrong package', text => text.replaceAll('/workflows', '/other')], ['wrong workflow', text => text.replaceAll(source, `${PACKAGE_NAME}/package/squad.md@${revisionA}`)], ['wrong revision', text => text.replaceAll(revisionA, revisionB)], @@ -4509,7 +4515,7 @@ describe('gh-aw: canonical package integrity contract', () => { const lockMutations: Array<[string, (text: string) => string]> = [ ...mutations.slice(0, 6), - ['wrong URL', text => text.replace('/bradygaster/squad/blob/', '/attacker/squad/blob/')], + ['wrong URL', text => text.replace('/github/squad/blob/', '/attacker/squad/blob/')], ['mixed annotation', text => text.replace(`GH_AW_WORKFLOW_SOURCE: "${source}"`, 'GH_AW_WORKFLOW_SOURCE: "unknown"')], ['missing annotation', text => text.replace(` GH_AW_INFO_FRONTMATTER_SOURCE: "${source}"\n`, '')], ['duplicate annotation', text => text.replace(`GH_AW_WORKFLOW_SOURCE: "${source}"`, `GH_AW_WORKFLOW_SOURCE: "${source}"\n GH_AW_WORKFLOW_SOURCE: "${source}"`)], @@ -4674,14 +4680,14 @@ describe('gh-aw: canonical package integrity contract', () => { it('rejects ownership mismatches and mixed revisions', () => { const root = makeConsumer(); - const ownershipPath = join(root, '.github/aw/packages/bradygaster-squad-workflows-test.json'); + const ownershipPath = join(root, '.github/aw/packages/github-squad-workflows-test.json'); const ownership = JSON.parse(readFileSync(ownershipPath, 'utf8')); ownership.source = `${PACKAGE_NAME}@${revisionB}`; writeFileSync(ownershipPath, `${JSON.stringify(ownership, null, 2)}\n`); expect(verifyInstall(root).failures.join('\n')).toContain('Package ownership source'); const extra = makeConsumer(); - const extraPath = join(extra, '.github/aw/packages/bradygaster-squad-workflows-test.json'); + const extraPath = join(extra, '.github/aw/packages/github-squad-workflows-test.json'); const extraOwnership = JSON.parse(readFileSync(extraPath, 'utf8')); extraOwnership.files.push(extraOwnership.files[0]); writeFileSync(extraPath, `${JSON.stringify(extraOwnership, null, 2)}\n`); diff --git a/test/gh-aw-review-workflow.test.ts b/test/gh-aw-review-workflow.test.ts index c5ef1f6c2..d8dd43669 100644 --- a/test/gh-aw-review-workflow.test.ts +++ b/test/gh-aw-review-workflow.test.ts @@ -378,12 +378,12 @@ describe('gh-aw enforcing Squad reviewer', () => { it('declares the complete native package for the pinned compiler job', () => { const manifest = read('workflows/aw.yml'); - expect(manifest).toContain('min-version: v0.91.5'); + expect(manifest).toContain('min-version: v1.0.1'); expect(manifest.match(/destination: \.github\/workflows\/squad(?:-[\w-]+)?\.md/g)).toHaveLength(8); expect(manifest.match(/source: package\/squad(?:-[\w-]+)?\.md/g)).toHaveLength(8); expect(manifest).toContain(' - skills/gh-aw-enlistment'); expect(read('.github/workflows/squad-ci.yml')).toContain( - 'gh extension install --force --pin v0.91.5 github/gh-aw', + 'gh extension install --force --pin v1.0.1 github/gh-aw', ); }); @@ -415,11 +415,11 @@ describe('gh-aw enforcing Squad reviewer', () => { it('keeps all consumer install surfaces on the isolated native package', () => { for (const surface of [GUIDE, README, AGENT_GUIDE, SHARED_BOOTSTRAP]) { - expect(surface).toContain('bradygaster/squad/workflows@${SQUAD_SHA}'); + expect(surface).toContain('github/squad/workflows@${SQUAD_SHA}'); expect(surface).not.toMatch(/gh aw add \\\n\s+bradygaster\/squad\/workflows\/squad\.md/); } expect(DEMO).toContain("gh-aw guide's install command"); - expect(DEMO).not.toContain('gh aw add bradygaster/squad/workflows/squad.md@latest'); + expect(DEMO).not.toContain('gh aw add github/squad/workflows/squad.md@latest'); }); it('documents enforcement, explicit override, and the independent human approval requirement', () => { diff --git a/test/gh-aw-verify-resource.test.ts b/test/gh-aw-verify-resource.test.ts index f2418ad46..9854269b3 100644 --- a/test/gh-aw-verify-resource.test.ts +++ b/test/gh-aw-verify-resource.test.ts @@ -18,7 +18,7 @@ const workflowMutations: ReadonlyArray< readonly [string, (text: string, source: string) => string] > = [ ['owner', (text, source) => - text.replace(source, source.replace('bradygaster/', 'attacker/'))], + text.replace(source, source.replace('github/', 'attacker/'))], ['repo', (text, source) => text.replace(source, source.replace('/squad/', '/other/'))], ['workflow', (text, source) => diff --git a/test/helpers/gh-aw-diagnostic-runtime.ts b/test/helpers/gh-aw-diagnostic-runtime.ts index c43d00d0b..efc6d15de 100644 --- a/test/helpers/gh-aw-diagnostic-runtime.ts +++ b/test/helpers/gh-aw-diagnostic-runtime.ts @@ -3,7 +3,7 @@ import { createRequire } from 'node:module'; import { dirname, posix } from 'node:path'; import { readFileSync, writeFileSync } from 'node:fs'; -export const DIAGNOSTIC_RUNTIME_SHA = '16b430146d5d5646eccef5a1ceb72152333b18b9'; +export const DIAGNOSTIC_RUNTIME_SHA = '221ba4f4319de6b8e809d1a15528b3ae6a818aa5'; const requireNode = createRequire(import.meta.url); const entrypoints = [ 'handle_agent_failure.cjs', 'handle_noop_message.cjs', 'handle_detection_runs.cjs', @@ -105,6 +105,8 @@ export function diagnosticRuntime( }; const runtimeEnv: Record = { GITHUB_REPOSITORY: 'owner/repo', RUNNER_TEMP: scratch, GITHUB_WORKSPACE: scratch, + GITHUB_REPOSITORY_ID: '123456789', GITHUB_RUN_ID: '1', GITHUB_RUN_ATTEMPT: '1', + GITHUB_JOB: 'safe_outputs', GH_AW_JOB_CHECK_RUN_ID: '101', GH_AW_WORKFLOW_ID: 'squad', GH_AW_WORKFLOW_NAME: 'Squad', GH_AW_RUN_URL: 'https://github.com/owner/repo/actions/runs/1', GH_AW_JOB_RESULTS: JSON.stringify({ upsert_lifecycle_state: { result: 'failure' } }), GH_AW_JOB_DISPLAY_NAMES: JSON.stringify({ upsert_lifecycle_state: 'upsert_lifecycle_state' }), @@ -153,15 +155,23 @@ export function diagnosticRuntime( if (request === 'fs' || request === 'node:fs') return filesystem; if (request === 'os' || request === 'node:os') return { ...requireNode(request), tmpdir: () => scratch }; if (['path', 'node:path', 'crypto', 'node:crypto', 'util', 'node:util', 'vm', 'node:vm', - 'buffer', 'events', 'string_decoder'].includes(request)) return requireNode(request); - if (['https', 'http', 'child_process'].includes(request)) return new Proxy({}, { - get: (_target, method: string) => (command: string) => { - if (request === 'child_process' && method === 'execSync' && command === 'git rev-parse --abbrev-ref HEAD') return 'dev\n'; - ioErrors.push(`Forbidden external IO: ${request}.${method}`); - throw new Error(ioErrors.at(-1)); + 'buffer', 'events', 'string_decoder', 'node:string_decoder', + 'async_hooks', 'node:async_hooks', 'perf_hooks', 'node:perf_hooks', + 'stream', 'node:stream', 'stream/promises', 'node:stream/promises', + 'zlib', 'node:zlib'].includes(request)) return requireNode(request); + if (['https', 'http', 'child_process', 'net', 'tls', 'sqlite'].includes(request.replace(/^node:/, ''))) return new Proxy({}, { + get: (_target, method: string) => { + if (['net', 'node:net'].includes(request) + && ['isIP', 'isIPv4', 'isIPv6'].includes(method)) return requireNode('node:net')[method]; + return function (command: string) { + if (['child_process', 'node:child_process'].includes(request) + && method === 'execSync' && command === 'git rev-parse --abbrev-ref HEAD') return 'dev\n'; + ioErrors.push(`Forbidden external IO: ${request}.${method}`); + throw new Error(ioErrors.at(-1)); + }; }, }); - throw new Error(`Forbidden runtime dependency: ${request}`); + throw new Error(`Forbidden runtime dependency: ${request} required by ${name}`); }; compileFunction(source, ['module', 'exports', 'require', '__dirname', '__filename'], { parsingContext: sandbox })(module, module.exports, require, dirname(name), name); diff --git a/test/helpers/gh-aw-install-fixture.ts b/test/helpers/gh-aw-install-fixture.ts index 7900ab948..7d7ac68ba 100644 --- a/test/helpers/gh-aw-install-fixture.ts +++ b/test/helpers/gh-aw-install-fixture.ts @@ -85,7 +85,7 @@ function withSource(content: Buffer, source: string, revision: string): Buffer { const end = normalized.indexOf(marker, 4); if (!normalized.startsWith('---\n') || end < 0) throw new Error(`Invalid workflow source: ${source}`); return Buffer.from( - `${normalized.slice(0, end)}\nsource: bradygaster/squad/${source}@${revision}${normalized.slice(end)}` + `${normalized.slice(0, end)}\nsource: github/squad/${source}@${revision}${normalized.slice(end)}` .replace(/\n/g, eol), ); } @@ -170,7 +170,7 @@ export function createFirstInstallFixture( package: PACKAGE_NAME, source: `${PACKAGE_NAME}@${revision}`, resolvedCommit: revision, - installer: 'gh-aw v0.91.5 test', + installer: 'gh-aw v1.0.1 test', files, }, consumerFiles, diff --git a/test/squad-cli-latest.test.ts b/test/squad-cli-latest.test.ts index 5306eb3f8..d261930c9 100644 --- a/test/squad-cli-latest.test.ts +++ b/test/squad-cli-latest.test.ts @@ -117,8 +117,9 @@ describe('Squad standalone activation latest-release default', () => { expect(install, 'workflows/shared/squad.md must retain the standalone install step').toBeDefined(); expect(install).toContain( - `uses: bradygaster/squad/.github/actions/squad-init@${revision}`, + `uses: github/squad/.github/actions/squad-init@${revision}`, ); + expect(install).toContain("repository: 'github/squad'"); expect(install).toContain("skip-init: 'true'"); expect(install, 'workflows/shared/squad.md must use the action default, not a version input') .not.toMatch(/^\s+version:/m); diff --git a/workflows/README.md b/workflows/README.md index 8754c68ad..44cba8229 100644 --- a/workflows/README.md +++ b/workflows/README.md @@ -4,7 +4,7 @@ This nested `gh-aw` package installs the complete Squad workflow bundle from one immutable commit: ```bash -gh aw add bradygaster/squad/workflows@<40-character-commit-sha> +gh aw add github/squad/workflows@<40-character-commit-sha> ``` The package contains exactly eight workflows, seventeen runtime resources, and diff --git a/workflows/aw.yml b/workflows/aw.yml index 2b851ba61..c6272ba63 100644 --- a/workflows/aw.yml +++ b/workflows/aw.yml @@ -1,5 +1,5 @@ manifest-version: "1" -min-version: v0.91.5 +min-version: v1.0.1 name: Squad Agentic Workflows emoji: "🤖" description: Complete, integrity-checked Squad workflow bundle for issue-driven planning and implementation. diff --git a/workflows/package/squad-bootstrap.md b/workflows/package/squad-bootstrap.md index cec5d6258..3199f90d3 100644 --- a/workflows/package/squad-bootstrap.md +++ b/workflows/package/squad-bootstrap.md @@ -153,7 +153,7 @@ pre-agent-steps: node --check "$path" >/dev/null } # BEGIN GENERATED RESOURCE DIGESTS - check_hash "$install_verifier" "d12cf4de38e716dd6d0bbb03fda22675477a4559573d3a8601b8f5b2f88f544e" + check_hash "$install_verifier" "337ab03a93e1fa5537629f1ea7bb4f85728d55cae74608c85b3ddc436132ff8b" check_hash "$cast_validator" "15f0d47917d269b5b967dc2a782a0eb761c39af7a92ddb64fed687a427070760" check_hash "$bootstrap_validator" "d552d041f006249bfaa67b10a75877f813796b7698c718ac7eb7cf16f3a72e31" # END GENERATED RESOURCE DIGESTS diff --git a/workflows/package/squad-deps-worker.md b/workflows/package/squad-deps-worker.md index 25a4dc758..f5010c06f 100644 --- a/workflows/package/squad-deps-worker.md +++ b/workflows/package/squad-deps-worker.md @@ -646,8 +646,9 @@ jobs: permission-contents: read - name: Install Squad CLI from standalone release id: squad-cli - uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f + uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f with: + repository: github/squad skip-init: "true" - name: Initialize Squad team env: diff --git a/workflows/package/squad-implement-worker.md b/workflows/package/squad-implement-worker.md index 349ca5394..6900ace10 100644 --- a/workflows/package/squad-implement-worker.md +++ b/workflows/package/squad-implement-worker.md @@ -781,8 +781,9 @@ jobs: permission-contents: read - name: Install Squad CLI from standalone release id: squad-cli - uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f + uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f with: + repository: github/squad skip-init: "true" - name: Initialize Squad team env: diff --git a/workflows/package/squad-retro.md b/workflows/package/squad-retro.md index 438ca7ff7..15500f52d 100644 --- a/workflows/package/squad-retro.md +++ b/workflows/package/squad-retro.md @@ -766,8 +766,9 @@ jobs: permission-contents: read - name: Install Squad CLI from standalone release id: squad-cli - uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f + uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f with: + repository: github/squad skip-init: "true" - name: Initialize Squad team env: diff --git a/workflows/package/squad-review.md b/workflows/package/squad-review.md index 2268dacdf..6136d6ad4 100644 --- a/workflows/package/squad-review.md +++ b/workflows/package/squad-review.md @@ -84,6 +84,7 @@ jobs: actions: read review: name: review + detection-gate: status-only if: always() needs: - agent diff --git a/workflows/package/squad.md b/workflows/package/squad.md index e9a82ee41..0828c88a0 100644 --- a/workflows/package/squad.md +++ b/workflows/package/squad.md @@ -366,7 +366,7 @@ safe-outputs: persist-credentials: false path: .squad-activation-trusted-base - name: Setup pinned issue creation API - uses: github/gh-aw-actions/setup@v0.91.5 + uses: github/gh-aw-actions/setup@v1.0.1 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Freeze and validate activation inputs @@ -411,7 +411,11 @@ safe-outputs: const actionsDir = join(process.env.RUNNER_TEMP, 'gh-aw/actions'); const { setupGlobals, createIssue } = require(join(actionsDir, 'index.cjs')); const { sanitizeContent } = require(join(actionsDir, 'sanitize_content.cjs')); - const { formatIssueBody } = require(join(actionsDir, 'issue_body.cjs')); + const { buildIssueBodyReport } = require(join(actionsDir, 'issue_body.cjs')); + const { renderReport } = require(join(actionsDir, 'report_ast.cjs')); + // Measure before the pinned runtime can redact oversized plan context. + const formatIssueBody = (body, options) => + renderReport(buildIssueBodyReport('Issue', body, options)).body.trimEnd(); setupGlobals(core, github, context, exec, io, getOctokit); const activation = await import(pathToFileURL(join(process.env.GITHUB_WORKSPACE, '.squad-activation-trusted-base/.github/workflows/shared/squad-activation.mjs')).href); @@ -999,8 +1003,9 @@ jobs: permission-contents: read - name: Install Squad CLI from standalone release id: squad-cli - uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f + uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f with: + repository: github/squad skip-init: "true" - name: Initialize Squad team env: @@ -2673,7 +2678,7 @@ gate `create-pull-request`. It diagnoses a `cast_failure` and outputs run separately after the agent; this diagnosis cannot prevent a pull request that is materialized concurrently. -Pinned gh-aw v0.91.5 makes `report_incomplete` fail the conclusion step. +Pinned gh-aw v1.0.1 makes `report_incomplete` fail the conclusion step. Automatic failure, failed-job, detection, no-op tracking issues and generic activation/completion comments are disabled in the dispatcher and router: conclusion runs independently of safe-output authorization and completion diff --git a/workflows/shared/squad-command-contract.mjs b/workflows/shared/squad-command-contract.mjs index 7688b71e6..ee1498ecb 100644 --- a/workflows/shared/squad-command-contract.mjs +++ b/workflows/shared/squad-command-contract.mjs @@ -347,9 +347,9 @@ export async function authorizeSquadCommand({ payload, eventName, actor, resolve } function serializedPlanBody(body, data) { - // gh-aw v0.91.5 appends this suffix in safe_output_type_validator.cjs. + // gh-aw v1.0.1's report renderer separates the data label and fence. // Validate, rather than rewrite, so the writer retains the planning artifact. - const match = /(?:^|\n\n)Structured data:\n```json\n([\s\S]*?)\n```$/.exec(body); + const match = /(?:^|\n\n)Structured data:\n(?:\n)?```json\n([\s\S]*?)\n```$/.exec(body); let envelope; try { envelope = match && JSON.parse(match[1]); diff --git a/workflows/shared/squad-install-verifier.mjs b/workflows/shared/squad-install-verifier.mjs index 1ddc96b9f..4666c9a43 100644 --- a/workflows/shared/squad-install-verifier.mjs +++ b/workflows/shared/squad-install-verifier.mjs @@ -18,14 +18,14 @@ import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'; -export const PACKAGE_NAME = 'bradygaster/squad/workflows'; +export const PACKAGE_NAME = 'github/squad/workflows'; export const PACKAGE_MANIFEST = 'workflows/aw.yml'; export const CONTRACT_SOURCE = 'workflows/squad-workflows.manifest.json'; export const CONTRACT_DESTINATION = '.github/aw/squad-workflows.manifest.json'; -export const MIN_GH_AW_VERSION = 'v0.91.5'; +export const MIN_GH_AW_VERSION = 'v1.0.1'; export const OWNERSHIP_ENTRY_COUNT = 30; export const OWNERSHIP_DESTINATION = - '.github/aw/packages/bradygaster-squad-workflows-3632054824e8.json'; + '.github/aw/packages/github-squad-workflows-23a7638f599e.json'; export const UNOWNED_MUTABLE_ROUTER_SKILL = '.github/skills/agentic-workflows/SKILL.md'; export const TRIGGER_PROBE = 'shared/squad-bootstrap-trigger-probe.json'; @@ -35,9 +35,22 @@ export const TRIGGER_PROBE_DESTINATION = const SHA256_PATTERN = /^[0-9a-f]{64}$/; const REVISION_PATTERN = /^[0-9a-f]{40}$/; const LOCK_REVISION_PLACEHOLDER = 'f'.repeat(40); -const COMPILER_ACTION_VERSION = 'v0.91.5'; -const COMPILER_ACTION_SHA = '16b430146d5d5646eccef5a1ceb72152333b18b9'; +const COMPILER_ACTION_VERSION = 'v1.0.1'; +const COMPILER_ACTION_SHA = '221ba4f4319de6b8e809d1a15528b3ae6a818aa5'; const COMPILER_ACTION_REPOS = ['github/gh-aw-actions/setup', 'github/gh-aw-actions/setup-cli']; +export const COMPILER_ACTION_PINS = Object.freeze([ + ...COMPILER_ACTION_REPOS.map(repo => ({ + repo, version: COMPILER_ACTION_VERSION, sha: COMPILER_ACTION_SHA, + })), + { repo: 'actions/checkout', version: 'v7.0.1', sha: '3d3c42e5aac5ba805825da76410c181273ba90b1' }, + { repo: 'actions/github-script', version: 'v9.0.0', sha: '3a2844b7e9c422d3c10d287c895573f7108da1b3' }, + { repo: 'actions/setup-node', version: 'v7.1.0', sha: '949feb2413d6458794dcd2491c4babbbce0c15c1' }, + { repo: 'actions/download-artifact', version: 'v8.0.2', sha: '9000827ccba6bdab643e8b6fd33ac0654aef8333' }, + { repo: 'actions/upload-artifact', version: 'v7.0.2', sha: 'cf430e030ddbb5b0abf93d22962f4752f3646cd9' }, + { repo: 'actions/create-github-app-token', version: 'v3.2.0', sha: 'bcd2ba49218906704ab6c1aa796996da409d3eb1' }, + { repo: 'actions/download-artifact', version: 'v8.0.1', sha: '3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c' }, + { repo: 'actions/upload-artifact', version: 'v7.0.1', sha: '043fb46d1a93c77aae656e7c1c64a875d1fc6a0a' }, +]); const REPO_CONFIG_PATH = '.github/workflows/aw.json'; const FAILURE_EXPIRY_VARIANTS = Object.freeze([24]); @@ -429,19 +442,24 @@ export function compileWithPinnedActions(root, env = process.env) { } const path = resolve(root, '.github/aw/actions-lock.json'); const pins = { - entries: Object.fromEntries(COMPILER_ACTION_REPOS.map(repo => [ - `${repo}@${COMPILER_ACTION_VERSION}`, - { repo, version: COMPILER_ACTION_VERSION, sha: COMPILER_ACTION_SHA }, + entries: Object.fromEntries(COMPILER_ACTION_PINS.map(pin => [ + `${pin.repo}@${pin.version}`, + pin, ])), }; if (existsSync(path)) { const existing = JSON.parse(readFileSync(path, 'utf8')); for (const [key, pin] of Object.entries(pins.entries)) { const actual = existing.entries?.[key]; + if (actual === undefined && !COMPILER_ACTION_REPOS.includes(pin.repo)) continue; if (!actual || actual.repo !== pin.repo || actual.version !== pin.version || actual.sha !== pin.sha) { throw new Error(`Compiler action lock has a missing or noncanonical pin: ${key}`); } } + writeFileSync(path, stableJson({ + ...existing, + entries: { ...existing.entries, ...pins.entries }, + })); } else { mkdirSync(dirname(path), { recursive: true }); writeFileSync(path, stableJson(pins), { flag: 'wx' }); @@ -740,8 +758,8 @@ function verifyOwnership(root, contract, expectedRevision) { if (record.source !== `${PACKAGE_NAME}@${record.resolvedCommit}`) { throw new Error(`Package ownership source must be ${PACKAGE_NAME}@${record.resolvedCommit}.`); } - if (typeof record.installer !== 'string' || !/^gh-aw v0\.91\.5(?:\s|$)/.test(record.installer)) { - throw new Error('Package ownership installer must be gh-aw v0.91.5.'); + if (typeof record.installer !== 'string' || !/^gh-aw v1\.0\.1(?:\s|$)/.test(record.installer)) { + throw new Error('Package ownership installer must be gh-aw v1.0.1.'); } assertArray(record.files, OWNERSHIP_ENTRY_COUNT, 'Package ownership files'); const expected = expectedOwnership(contract); @@ -778,7 +796,7 @@ function verifyWorkflowSourceBinding(root, entry, revision, lockEntry = entry) { .filter(index => index >= 0); const sourceBindings = new Map([ [`source: ${PACKAGE_NAME}@${revision}`, lockEntry.package_lock_sha256], - [`source: bradygaster/squad/${entry.source}@${revision}`, lockEntry.lock_sha256], + [`source: github/squad/${entry.source}@${revision}`, lockEntry.lock_sha256], ]); const sourceIndex = sourceIndexes[0]; const sourceBinding = lines[sourceIndex]; @@ -1112,12 +1130,12 @@ export function writeLocalTestOwnership(root, revision) { ...entry, sha256: fileDigest(root, entry.destination), })); - writePath(root, '.github/aw/packages/bradygaster-squad-workflows-local-test.json', stableJson({ + writePath(root, OWNERSHIP_DESTINATION, stableJson({ schemaVersion: 1, package: PACKAGE_NAME, source: `${PACKAGE_NAME}@${revision}`, resolvedCommit: revision, - installer: 'gh-aw v0.91.5 local package contract test', + installer: 'gh-aw v1.0.1 local package contract test', files, })); } diff --git a/workflows/shared/squad.md b/workflows/shared/squad.md index b501b99be..9091bca63 100644 --- a/workflows/shared/squad.md +++ b/workflows/shared/squad.md @@ -1,10 +1,10 @@ --- # Squad Bootstrap Component — installs and initializes Squad -# (https://github.com/bradygaster/squad) in the activation job, then hands off +# (https://github.com/github/squad) in the activation job, then hands off # the generated team state to the agent job. This is the DISTRIBUTION version, # living under workflows/shared/ so users can pull the standard stack from one # immutable nested native package: -# gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +# gh aw add "github/squad/workflows@${SQUAD_SHA}" # # Adapted from Peli de Halleux's gh-aw integration: # https://github.com/github/gh-aw/blob/main/.github/workflows/shared/squad.md @@ -537,8 +537,9 @@ jobs: - name: Install Squad CLI from standalone release id: squad-cli - uses: bradygaster/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f + uses: github/squad/.github/actions/squad-init@5c662ba015ec4f99befa51b0e8ca4f2148b0497f with: + repository: 'github/squad' skip-init: 'true' - name: Initialize Squad team diff --git a/workflows/skills/gh-aw-enlistment/SKILL.md b/workflows/skills/gh-aw-enlistment/SKILL.md index 0a02b6d01..9c150881f 100644 --- a/workflows/skills/gh-aw-enlistment/SKILL.md +++ b/workflows/skills/gh-aw-enlistment/SKILL.md @@ -25,7 +25,7 @@ bootstrap pull request** — never an auto-merge. This skill **operationalizes** the supported bootstrap path. It does not summarize it: each step below is a gate with explicit success evidence and **STOP conditions**. The authoritative source is `docs/src/content/docs/guide/gh-aw.md` (mirrored at -`https://bradygaster.github.io/squad/docs/guide/gh-aw/`). If that guide and this +`https://github.github.com/squad/guide/gh-aw/`). If that guide and this skill ever disagree, the guide wins — re-read it before proceeding. GitHub Issues are a hard prerequisite: `/squad` commands arrive as issue @@ -54,16 +54,15 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status -# Prove the exact package-capable compiler version before creating artifacts +# Require stable gh-aw 1.x without pinning the CLI installation to a patch # gh-aw-exact-version-start -required_gh_aw_version="v0.91.5" gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" -if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then - echo "Installing exact supported gh-aw ${required_gh_aw_version}." +if [ -z "${gh_aw_version}" ] || [[ "${gh_aw_version}" =~ ^v0\. ]]; then + echo "Installing the current stable gh-aw release." gh extension remove gh-aw >/dev/null 2>&1 || true - gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh extension install github/gh-aw gh_aw_version_output="$(gh aw --version 2>&1)" || { echo "STOP: gh-aw version could not be verified after clean installation." >&2 exit 1 @@ -71,8 +70,8 @@ if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" fi -test "${gh_aw_version}" = "${required_gh_aw_version}" || { - echo "STOP: required gh-aw v0.91.5, but found ${gh_aw_version:-unavailable} after clean installation." >&2 +[[ "${gh_aw_version}" =~ ^v1\.[0-9]+\.[0-9]+$ ]] || { + echo "STOP: stable gh-aw 1.x is required, but found ${gh_aw_version:-unavailable}." >&2 exit 1 } # gh-aw-exact-version-end @@ -87,21 +86,27 @@ git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> capture both output streams from `gh aw --version`. On any mismatch, remove -> `github/gh-aw`, cleanly install the exact `v0.91.5` pin, and verify both -> streams again. Stop before branch creation or file generation unless that -> second check proves exactly `v0.91.5`; never select a newer release. +> capture both output streams from `gh aw --version`. If absent or 0.x, cleanly +> install the current stable `github/gh-aw` release without `--pin` and verify +> both streams again. Stop unless the result is a stable 1.x release; never +> downgrade a newer major version automatically. The current package validates +> v1.0.1 compiler bytes and immutable action pins. Other 1.x releases require +> a maintainer-reviewed package update, not a consumer-side digest refresh. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. -- **STOP** if exact gh-aw `v0.91.5` cannot be proven after the clean pinned - reinstall. Do not create a branch or generate repository files. +- **STOP** if stable gh-aw 1.x cannot be proven after installation, or the + package's published compiler contract does not cover the installed release. + Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation run and the requested `@copilot` review both depend on it. +- Before installation, record whether `.vscode/settings.json` and + `.github/workflows/agentics-maintenance.yml` already exist. Preserve pre-existing + files; stop and report their diff if gh-aw changes them. ### 1. Require GitHub Issues, then allow Actions-created PRs with a read-only token @@ -193,13 +198,13 @@ published release guidance, then set it once: echo "STOP: SQUAD_SHA must be the exact 40-character commit SHA, not a branch name or shortened hash." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md ``` The nested `workflows/aw.yml` is the only supported distribution registration. It isolates package auto-discovery from unrelated repository skills and agents, -and installs exactly eight workflows, seventeen runtime resources, and one +and installs exactly eight workflows, twenty-one runtime resources, and one `gh-aw-enlistment` skill at the same resolved revision: - `squad.md` + `squad.lock.yml` @@ -217,7 +222,7 @@ governance-scoped retrospective proposal (see the gh-aw guide's retrospective auto-implementation section); installing it alongside the other seven keeps the full stack consistent and avoids a second bootstrap pass later. -gh-aw v0.91.5 also materializes +gh-aw v1.0.1 also materializes `.github/skills/agentic-workflows/SKILL.md`. That generic tool-owned router is not part of the Squad package and directs agents to mutable prompts from the current `github/gh-aw` repository rather than the pinned Squad revision. Remove @@ -247,7 +252,7 @@ On a clean repo, `gh aw add` reports these expected safe updates and **nothing e - Restricted secrets: **`SQUAD_GITHUB_APP_PRIVATE_KEY`** and **`SQUAD_GITHUB_TOKEN`** -- Action: **`bradygaster/squad/.github/actions/squad-init`** +- Action: **`github/squad/.github/actions/squad-init`** > **These are referenced names, not prerequisites.** `gh aw add` lists the secrets @@ -285,7 +290,7 @@ This must run after any first-install approval and before committing. Success criteria: - All eight workflows compile successfully. -- With gh-aw v0.91.5, require exactly two warnings, one occurrence of each +- With gh-aw v1.0.1, require exactly two warnings, one occurrence of each exact diagnostic header below (including its workflow path): @@ -335,15 +340,22 @@ If `.github/aw/logs/` lacks a `.gitignore`, add one there: !.gitignore ``` -`gh aw add` may also create `.vscode/settings.json` (enables Copilot for Markdown -workflow files). This is an **optional editor setting** — the stage command below -intentionally leaves it untracked. Delete it if unwanted, or stage it explicitly -if your team wants to share it. Decide deliberately; do not stage it by accident. +gh-aw v1.0.1 may generate two auxiliary outputs: `.vscode/settings.json` +(optional Markdown editor settings) and `.github/workflows/agentics-maintenance.yml` +(the compiler's maintenance workflow). Neither is authenticated by Squad's +package manifest. Leave both outside the bootstrap PR by default; the staging +commands below exclude them. Review and stage an auxiliary file by its exact +path only after explicit approval. + +Only remove an unwanted auxiliary file if it was absent before installation +and was created by this invocation. Never delete or overwrite pre-existing +editor settings or maintenance workflows. Known, newly generated auxiliary +files left untracked are expected output, not an unrelated-change failure. Stage **only** the documented generated surfaces, then verify the staged set: ```bash -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git diff --cached --stat @@ -498,7 +510,7 @@ git switch -c chore/squad-gh-aw-bootstrap echo "STOP: SQUAD_SHA must be an explicit, maintainer-approved 40-character lowercase hex commit SHA." >&2 exit 1 } -gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}" +gh aw add "github/squad/workflows@${SQUAD_SHA}" rm -f .github/skills/agentic-workflows/SKILL.md # Safe-update report shows ONLY the two documented secrets + squad-init → approve once @@ -508,7 +520,7 @@ gh aw compile --strict # final, no --approve; exactly the two document node .github/workflows/shared/squad-install-verifier.mjs \ --verify-install --source-revision "${SQUAD_SHA}" --strict-compile -git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ +git add -- .gitattributes .github/aw/ .github/workflows/ .github/skills/ ':(exclude).github/workflows/agentics-maintenance.yml' node .github/workflows/shared/squad-install-verifier.mjs \ --verify-staged-install --stage-ownership --source-revision "${SQUAD_SHA}" || exit 1 git commit -m "ci: add Squad agentic workflow" @@ -566,7 +578,7 @@ gh pr merge --squash # auto-merge before human review. NEVER. `.github/skills/agentic-workflows/SKILL.md`; keep the exact Squad-owned `.github/skills/gh-aw-enlistment/SKILL.md`. - ❌ **Approving unknown safe updates.** Approve ONLY `SQUAD_GITHUB_APP_PRIVATE_KEY`, - `SQUAD_GITHUB_TOKEN`, and `bradygaster/squad/.github/actions/squad-init`. Anything + `SQUAD_GITHUB_TOKEN`, and `github/squad/.github/actions/squad-init`. Anything else is a STOP. - ❌ **Treating `--approve` as the final compile.** Always finish with a plain `gh aw compile --strict` (no `--approve`). diff --git a/workflows/squad-bootstrap.md b/workflows/squad-bootstrap.md index 4d3066197..ad5e3571b 100644 --- a/workflows/squad-bootstrap.md +++ b/workflows/squad-bootstrap.md @@ -160,7 +160,7 @@ pre-agent-steps: node --check "$path" >/dev/null } # BEGIN GENERATED RESOURCE DIGESTS - check_hash "$install_verifier" "d12cf4de38e716dd6d0bbb03fda22675477a4559573d3a8601b8f5b2f88f544e" + check_hash "$install_verifier" "337ab03a93e1fa5537629f1ea7bb4f85728d55cae74608c85b3ddc436132ff8b" check_hash "$cast_validator" "15f0d47917d269b5b967dc2a782a0eb761c39af7a92ddb64fed687a427070760" check_hash "$bootstrap_validator" "d552d041f006249bfaa67b10a75877f813796b7698c718ac7eb7cf16f3a72e31" # END GENERATED RESOURCE DIGESTS diff --git a/workflows/squad-review.md b/workflows/squad-review.md index 187a20b8e..6de5bcafc 100644 --- a/workflows/squad-review.md +++ b/workflows/squad-review.md @@ -77,6 +77,7 @@ jobs: actions: read review: name: review + detection-gate: status-only if: always() needs: [agent, safe_outputs] runs-on: ubuntu-latest diff --git a/workflows/squad-workflows.manifest.json b/workflows/squad-workflows.manifest.json index bddad02ad..9aaba2f6d 100644 --- a/workflows/squad-workflows.manifest.json +++ b/workflows/squad-workflows.manifest.json @@ -1,8 +1,8 @@ { "schema_version": 2, - "package": "bradygaster/squad/workflows", + "package": "github/squad/workflows", "manifest": "workflows/aw.yml", - "minimum_gh_aw_version": "v0.91.5", + "minimum_gh_aw_version": "v1.0.1", "revision_policy": { "kind": "immutable-git-commit", "pattern": "^[0-9a-f]{40}$", @@ -15,45 +15,45 @@ "source": "workflows/package/squad.md", "destination": ".github/workflows/squad.md", "lock": ".github/workflows/squad.lock.yml", - "source_sha256": "0720c948a2513ac7994bc5fb65cbdb875da7c6ae3a2a4f5fda4842bab0098b44", - "lock_sha256": "930f5583a0931706164b4d48f770faeb0330ad12b29880fa2667f3cd37c2ad95", - "package_lock_sha256": "b3de24942556d64ab1c149762c7d46cf45cb576a86a25b549337978cfba9e22e" + "source_sha256": "eecfd5137baabea6a8d17caeb3ff76133d27d5c0a8fad387682d6ecb0d126be8", + "lock_sha256": "1b1fca60b28d5578218fb0c0ab6602a811af02f1483f4f35315c31c94c89d55d", + "package_lock_sha256": "1289746d1486a32d6fb9c9ebdc212a58433c62245c7c69c269d5985549eeb3bc" }, { "name": "squad-implement-worker", "source": "workflows/package/squad-implement-worker.md", "destination": ".github/workflows/squad-implement-worker.md", "lock": ".github/workflows/squad-implement-worker.lock.yml", - "source_sha256": "c18889c0fb2dc5a389c04e745bf8398993f07da8a9a1c6511101f3902ed326cd", - "lock_sha256": "079c5ee80259dc9a51f6dd8a3793f8f26586b4adda14078e40b22db7f7f7a73e", - "package_lock_sha256": "bc7611b14ad4cda7b826de290091a36d4e6b8ba05feea6670c75f4bbf3c5e64e" + "source_sha256": "b94694e5613a273c9201d6630c39d54b83bb973cde297309fa361fe9b0f31c86", + "lock_sha256": "b51c6ce92dca175ca265460100ebf2b1dd022b5c0748599974c56b96a4a10d95", + "package_lock_sha256": "af54091bf56d49d5789e73ee5bf0a9d065ce02b7aee92a2f02a1b357ff989294" }, { "name": "squad-review", "source": "workflows/package/squad-review.md", "destination": ".github/workflows/squad-review.md", "lock": ".github/workflows/squad-review.lock.yml", - "source_sha256": "f620707fd8d117d235c8c3ea1b90fdb198ebbb99a9fe87363b5229674abebc57", - "lock_sha256": "218a034ef788e06951cf8d511679364e37cafb2c470cb0a29d605b5aeb477b91", - "package_lock_sha256": "befaddd9feecfe436722f0e36127756dd9b9bcdbd9a73758dd9c0dc228864dd9" + "source_sha256": "b30d6ab16ce058fe524790dd71dabfa303cbc7774254310b5e80a3f1649f007d", + "lock_sha256": "e7e5f2f610aec8e8acc946f6b271af688ad0fb799cf388f668845d567a2147bc", + "package_lock_sha256": "d06d9e7e40df9e68337e00eb1865eb233df6a9aadee1131b914b27d31a5195cd" }, { "name": "squad-deps-worker", "source": "workflows/package/squad-deps-worker.md", "destination": ".github/workflows/squad-deps-worker.md", "lock": ".github/workflows/squad-deps-worker.lock.yml", - "source_sha256": "c0de841e77708fc07cb126dc2fe3899a7e9c955b756e68ef21c5ad927621f853", - "lock_sha256": "2462182e6392b145d40853d1687d0bfdb83ac31757bbb28b3786d533160c8921", - "package_lock_sha256": "0e9e12f7c7b0786e7bec4bbc6ae8b334488a5c62defa37a9f5c13c649b39daad" + "source_sha256": "5ed770a39f939940adfc3da3784acdd02038bc93e75113387f8cf5201e1ef874", + "lock_sha256": "21601f59accbe2f94307c03daf0ae4a011393138573d8e3076c786bbaa6ba68a", + "package_lock_sha256": "347e8b9302e076ddd08d3f82473c6ccb4d104ea79348713e37233b438104f4c2" }, { "name": "squad-retro", "source": "workflows/package/squad-retro.md", "destination": ".github/workflows/squad-retro.md", "lock": ".github/workflows/squad-retro.lock.yml", - "source_sha256": "d5d34a97409b2fec7be2606ce26eeec5fa675891956331669342155118c259d1", - "lock_sha256": "ad730dedf19602e9f8ca3680b91ab9b992c4b14a2d04feb619576c684ec83376", - "package_lock_sha256": "cabfa606daae655f9fd2ebbb5baeda51767cb33a3b03dffe7f3cf4d1316b1c4a" + "source_sha256": "62d5542cd3802f8059810836297940a26103fa8039beaa3828d6a9c2c91e1b1f", + "lock_sha256": "e327142c5b5e28499e96bcdb390976b32b60c2cad77f413548fbad3d4d1058d8", + "package_lock_sha256": "22388ab5d5d2e38549e6d2bcfe2e8dc493ee3fed10b5bbb1de72734f1066d10e" }, { "name": "squad-improvement-worker", @@ -61,17 +61,17 @@ "destination": ".github/workflows/squad-improvement-worker.md", "lock": ".github/workflows/squad-improvement-worker.lock.yml", "source_sha256": "1215304b71346cc13939a9b7f3e186bc20581d67ddba5ee47b21a9d4bdbc67c7", - "lock_sha256": "ce56c2428fb85a35b6b36e6f86f06ede07ca29f18a7e255b41292189287e95d2", - "package_lock_sha256": "1f0b2c4e528d08ca40b66dadefc321451fdade7109c0063b5eb00557b44f30a0" + "lock_sha256": "ef595d86a478288476fd0782904d51b541bde877fc1ee4b02a6f13ae1f0a7ed8", + "package_lock_sha256": "f2ee5a61f7852125216c15ae02c143d3c780574cecd5977a69ebd1020efacdb5" }, { "name": "squad-bootstrap", "source": "workflows/package/squad-bootstrap.md", "destination": ".github/workflows/squad-bootstrap.md", "lock": ".github/workflows/squad-bootstrap.lock.yml", - "source_sha256": "134046b4aab2ee0eee8a4f0a59f53847afa6387bbccde13b76f1308dad8e649f", - "lock_sha256": "49cce70f353f069b70016f23c51c9a2dee36af5276d8847221fd96a671969975", - "package_lock_sha256": "794f325069499495b132d61b30e40a4ef92c67a70201e6e42704a84f58ca6729" + "source_sha256": "e7234d9300899860db59fe0c034c9fb56e49d2c48ad32fa7d2fd505553e8bd42", + "lock_sha256": "4a7275506a51ea30063c6f2b69d61417f3f322d40fd2996ca106a3fe52427186", + "package_lock_sha256": "5e487f463026e607d7fc971db59efa497ab7f0b9aefd92703ebb771308f19ffb" }, { "name": "squad-command-router", @@ -79,8 +79,8 @@ "destination": ".github/workflows/squad-command-router.md", "lock": ".github/workflows/squad-command-router.lock.yml", "source_sha256": "34d495b2e899dbbfb270135c3d6bc531c510eef91d705a91821e4a5b85f6b92c", - "lock_sha256": "04c2c877eb9e5e594b5b1d804e5fdfd19c9efdf0d0a76fa214cdbb614197fa6c", - "package_lock_sha256": "9a6d72873cc8d39ca2de9854c1e4eaac88818fde755a398a8c7ca59b9e3a88c0" + "lock_sha256": "63debf97d16754bd6d003219a1daa9419e07cb8c18f45e5fdf38af47926fe53b", + "package_lock_sha256": "6360dde016acfc90a50aee77ac4cc21b64e29c4a138067524d7c28ea29dd91a6" } ], "lock_variants": [ @@ -89,43 +89,43 @@ "workflows": [ { "name": "squad", - "lock_sha256": "930f5583a0931706164b4d48f770faeb0330ad12b29880fa2667f3cd37c2ad95", - "package_lock_sha256": "b3de24942556d64ab1c149762c7d46cf45cb576a86a25b549337978cfba9e22e" + "lock_sha256": "1b1fca60b28d5578218fb0c0ab6602a811af02f1483f4f35315c31c94c89d55d", + "package_lock_sha256": "1289746d1486a32d6fb9c9ebdc212a58433c62245c7c69c269d5985549eeb3bc" }, { "name": "squad-implement-worker", - "lock_sha256": "8efb5da6e4042953620a73d4b33687202921c97942b9184d54e75f6bc4315b7d", - "package_lock_sha256": "755365ad065a8d843fbc56ea995e9c9fa7e2220dc89540884104c01a292d2f4a" + "lock_sha256": "fa63b9882427071446c6983ba3d61c346854de2d83f726e1686324ace1328ac0", + "package_lock_sha256": "a0d204d7545cda7b731c824ab95c21977186e8582a84dd4fff42c22ec9089293" }, { "name": "squad-review", - "lock_sha256": "2b69ede359f9c52602abc19bd11a6e963da056ada14844333ac5ba1e0085893c", - "package_lock_sha256": "decb18305210e737d2b1146a937e0720f5abd7378929e78683876afbe2e01b67" + "lock_sha256": "e885021f3a770e27a9c3f86b8a7b00ce6e0c62d8eb1de90f4a9beec3e4885cac", + "package_lock_sha256": "310bd684f4ea39d403b586daa5ab399c3cedb6d89b29bda72673e63d80707e2c" }, { "name": "squad-deps-worker", - "lock_sha256": "5b7c7aeb1ce2c0720b20b558b991eb3c5b838cbfeba9aad212ca894efefca21a", - "package_lock_sha256": "c83549cdb00d7f03312f0176a8993f3d60e0325eb4204d2cef33b1fb01974f0b" + "lock_sha256": "569ef012e77848573ab149ae1a733669d4630099f7ffa939011dc6740955eb4b", + "package_lock_sha256": "ec51a23d65d39ffa1b670b05dd4c8c9a99e9d87aca2a2c11ba1fe4087a223558" }, { "name": "squad-retro", - "lock_sha256": "1d10cc6eb8bf9387d8d0bb3450dcdaa7d8f60cf5f64d4ac47e14bfaa71feb1fc", - "package_lock_sha256": "4cbe6807df873ad68727a0fbf524cd598f4f4819da116e2b229dbd4b02c0f251" + "lock_sha256": "4ea80602843307b6c1d492d936526a67366357256848763478af383ae5bfb8b3", + "package_lock_sha256": "fe26e17ef815c1b1367153d2be74ee350a8ff1dec8e6c008363fb8f9774c0740" }, { "name": "squad-improvement-worker", - "lock_sha256": "16d8991ddd3620708a31d0b787c0e04e0760f7a6a18c62201be8edc804c919d4", - "package_lock_sha256": "f55ea3e4f93fce18873556d491a278fd419c961424d2b8465adb30e73e318363" + "lock_sha256": "90fc0fc30d3b7bd0bae330250a075502979bcee33c6f5a2c36e923980861b8ae", + "package_lock_sha256": "a07ecf6b61193067df114a9edff374bfc1b58eecdb54af9f4f28ae517fdfcd3e" }, { "name": "squad-bootstrap", - "lock_sha256": "7cc2667bd9611e46764e2f38c675b1d43fe167754158ec4397a46a22d9e9e19e", - "package_lock_sha256": "1899588770c9a5e9fbc2edfe385ab8618d35c4a0a111e5018fe34af59e5f9ca5" + "lock_sha256": "de8e686b43b1d6e45db542912de2bdef9d505b3768c0073950a918d9e2b67660", + "package_lock_sha256": "1353b676fea03e142331a35e79ec378bf341432551a0ca6ef632e94744ad5865" }, { "name": "squad-command-router", - "lock_sha256": "04c2c877eb9e5e594b5b1d804e5fdfd19c9efdf0d0a76fa214cdbb614197fa6c", - "package_lock_sha256": "9a6d72873cc8d39ca2de9854c1e4eaac88818fde755a398a8c7ca59b9e3a88c0" + "lock_sha256": "63debf97d16754bd6d003219a1daa9419e07cb8c18f45e5fdf38af47926fe53b", + "package_lock_sha256": "6360dde016acfc90a50aee77ac4cc21b64e29c4a138067524d7c28ea29dd91a6" } ] } @@ -169,7 +169,7 @@ "package_destination": ".github/workflows/shared/squad-install-verifier.mjs", "destination": ".github/workflows/shared/squad-install-verifier.mjs", "ownership": "manifest", - "sha256": "d12cf4de38e716dd6d0bbb03fda22675477a4559573d3a8601b8f5b2f88f544e" + "sha256": "337ab03a93e1fa5537629f1ea7bb4f85728d55cae74608c85b3ddc436132ff8b" }, { "path": "shared/squad-command-contract.mjs", @@ -177,7 +177,7 @@ "package_destination": ".github/workflows/shared/squad-command-contract.mjs", "destination": ".github/workflows/shared/squad-command-contract.mjs", "ownership": "manifest", - "sha256": "9f044d9ab402d893f58eb0477e3d3620540f0b992056ed3a61d090daa50aea4a" + "sha256": "5bb8db22d1bcadc28bbc424bb4c732b698208fe78c056bb5e814024aff28fadd" }, { "path": "shared/squad-evidence-provider.mjs", @@ -241,7 +241,7 @@ "package_destination": ".github/aw/squad/runtime/shared/squad.md", "destination": ".github/workflows/shared/squad.md", "ownership": "manifest", - "sha256": "bfe0417921cd23551afb3511aac03e3414d73412a842c9983cf39015700a8bf3" + "sha256": "488fa00dc3853ec06009d519b3e455583fd8f241e80d62bb7e9fd0938196e976" }, { "path": "shared/squad-planning-ontology.md", @@ -305,7 +305,7 @@ "name": "gh-aw-enlistment", "source": "workflows/skills/gh-aw-enlistment/SKILL.md", "destination": ".github/skills/gh-aw-enlistment/SKILL.md", - "sha256": "b982dfa4572c9b16ffd3ddf3ed3102562dce5098b9ec14d27b76ad0ffc964800" + "sha256": "90eb31539115f11ee1399e5b305a96dabb83b03d9ab23d17867d0a327b13be61" } ], "bootstrap": { diff --git a/workflows/squad.md b/workflows/squad.md index 1b2449b1e..210a3f6c3 100644 --- a/workflows/squad.md +++ b/workflows/squad.md @@ -440,7 +440,7 @@ safe-outputs: persist-credentials: false path: .squad-activation-trusted-base - name: Setup pinned issue creation API - uses: github/gh-aw-actions/setup@v0.91.5 + uses: github/gh-aw-actions/setup@v1.0.1 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Freeze and validate activation inputs @@ -485,7 +485,11 @@ safe-outputs: const actionsDir = join(process.env.RUNNER_TEMP, 'gh-aw/actions'); const { setupGlobals, createIssue } = require(join(actionsDir, 'index.cjs')); const { sanitizeContent } = require(join(actionsDir, 'sanitize_content.cjs')); - const { formatIssueBody } = require(join(actionsDir, 'issue_body.cjs')); + const { buildIssueBodyReport } = require(join(actionsDir, 'issue_body.cjs')); + const { renderReport } = require(join(actionsDir, 'report_ast.cjs')); + // Measure before the pinned runtime can redact oversized plan context. + const formatIssueBody = (body, options) => + renderReport(buildIssueBodyReport('Issue', body, options)).body.trimEnd(); setupGlobals(core, github, context, exec, io, getOctokit); const activation = await import(pathToFileURL(join(process.env.GITHUB_WORKSPACE, '.squad-activation-trusted-base/.github/workflows/shared/squad-activation.mjs')).href); @@ -1471,7 +1475,7 @@ gate `create-pull-request`. It diagnoses a `cast_failure` and outputs run separately after the agent; this diagnosis cannot prevent a pull request that is materialized concurrently. -Pinned gh-aw v0.91.5 makes `report_incomplete` fail the conclusion step. +Pinned gh-aw v1.0.1 makes `report_incomplete` fail the conclusion step. Automatic failure, failed-job, detection, no-op tracking issues and generic activation/completion comments are disabled in the dispatcher and router: conclusion runs independently of safe-output authorization and completion