Skip to content

Commit 0f2586e

Browse files
authored
Merge pull request #2075 from bradygaster/bradygaster-e2e-testing-gh-aw-bootstrap
Harden gh-aw distribution and add hosted bootstrap E2E
2 parents a5893d4 + e299d76 commit 0f2586e

39 files changed

Lines changed: 11653 additions & 674 deletions
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@bradygaster/squad-cli": patch
3+
"@bradygaster/squad-sdk": patch
4+
---
5+
6+
Install Squad's seven agentic workflows, fifteen runtime resources, and
7+
enlistment skill from one isolated native package, with fail-closed manifest,
8+
ownership, path, and hosted bootstrap verification.

‎.github/agents.md‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,8 @@ GitHub Agentic Workflows (`gh-aw`) are composable AI workflows triggered by slas
3737
The quick start installs this workflow set:
3838

3939
```bash
40-
gh aw add \
41-
bradygaster/squad/workflows/squad.md@dev \
42-
bradygaster/squad/workflows/squad-implement-worker.md@dev \
43-
bradygaster/squad/workflows/squad-review.md@dev \
44-
bradygaster/squad/workflows/squad-deps-worker.md@dev \
45-
bradygaster/squad/workflows/squad-retro.md@dev \
46-
bradygaster/squad/workflows/squad-improvement-worker.md@dev \
47-
bradygaster/squad/workflows/squad-bootstrap.md@dev
40+
SQUAD_SHA="$(gh api repos/bradygaster/squad/commits/dev --jq '.sha')"
41+
gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"
4842
```
4943

5044
This command:

‎.github/workflows/squad-ci.yml‎

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,20 @@ jobs:
739739
steps:
740740
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
741741

742-
- name: Install gh-aw v0.87.10 (pinned)
743-
run: gh extension install --pin v0.87.10 github/gh-aw
742+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v6
743+
with:
744+
node-version: 22
745+
cache: npm
746+
747+
- name: Install verifier dependencies
748+
run: |
749+
npm config set registry "https://packagefeedproxy.microsoft.io/npm/"
750+
npm ci --ignore-scripts
751+
752+
- name: Install gh-aw v0.89.21 (pinned)
753+
run: |
754+
gh extension install --force --pin v0.89.21 github/gh-aw
755+
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.21
744756
env:
745757
GH_TOKEN: ${{ github.token }}
746758

@@ -750,68 +762,38 @@ jobs:
750762
gh aw --version | tee -a "$GITHUB_STEP_SUMMARY"
751763
echo "" >> "$GITHUB_STEP_SUMMARY"
752764
753-
- name: Set up deploy layout
754-
# Mirror workflows/ → <tmpdir>/.github/workflows/ then git init so
755-
# gh aw compile sees the directory structure it expects in a consumer
756-
# repo after `gh aw add`.
757-
run: |
758-
COMPILE_DIR=$(mktemp -d)
759-
echo "COMPILE_DIR=$COMPILE_DIR" >> "$GITHUB_ENV"
760-
mkdir -p "$COMPILE_DIR/.github/workflows"
761-
cp -r workflows/. "$COMPILE_DIR/.github/workflows/"
762-
git -C "$COMPILE_DIR" init --quiet
765+
- name: Verify canonical package manifest and generated digests
766+
run: npm run gh-aw:integrity:check
763767

764-
- name: Compile all seven workflows (--strict) and verify lock files
765-
# Failures accumulate rather than short-circuit so every result is
766-
# visible in one run. A compiler that exits 0 without emitting a lock
767-
# file is treated as failure — silent-success is a gate gap.
768+
- name: Verify a clean native package consumer
769+
env:
770+
SQUAD_SOURCE_REVISION: ${{ github.sha }}
768771
run: |
769772
set -euo pipefail
770-
FAILED=0
771-
echo "### Compile results" >> "$GITHUB_STEP_SUMMARY"
772-
for WF in squad squad-implement-worker squad-review squad-deps-worker squad-retro squad-improvement-worker; do
773-
printf -- '--- Compiling %s ---\n' "$WF"
774-
if (cd "$COMPILE_DIR" && gh aw compile "$WF" --strict --approve --no-check-update 2>&1); then
775-
printf ' => OK\n'
776-
echo "✅ \`$WF\`" >> "$GITHUB_STEP_SUMMARY"
777-
else
778-
echo "::error::gh aw compile $WF --strict failed"
779-
echo "❌ \`$WF\` compile failed" >> "$GITHUB_STEP_SUMMARY"
780-
FAILED=$((FAILED + 1))
781-
fi
782-
done
783-
printf -- '--- Compiling squad-bootstrap ---\n'
784-
if (cd "$COMPILE_DIR" && gh aw compile squad-bootstrap --strict --approve --no-check-update 2>&1); then
785-
printf ' => OK\n'
786-
echo "✅ \`squad-bootstrap\`" >> "$GITHUB_STEP_SUMMARY"
787-
else
788-
echo "::error::gh aw compile squad-bootstrap --strict failed"
789-
echo "❌ \`squad-bootstrap\` compile failed" >> "$GITHUB_STEP_SUMMARY"
790-
FAILED=$((FAILED + 1))
791-
fi
792-
echo "" >> "$GITHUB_STEP_SUMMARY"
793-
echo "### Lock files" >> "$GITHUB_STEP_SUMMARY"
794-
for LOCK in squad.lock.yml squad-implement-worker.lock.yml squad-review.lock.yml squad-deps-worker.lock.yml squad-retro.lock.yml squad-improvement-worker.lock.yml; do
795-
if [ ! -f "$COMPILE_DIR/.github/workflows/$LOCK" ]; then
796-
echo "::error::$LOCK not emitted — compiler exited 0 without writing output"
797-
echo "❌ missing: \`$LOCK\`" >> "$GITHUB_STEP_SUMMARY"
798-
FAILED=$((FAILED + 1))
799-
else
800-
echo "✅ \`$LOCK\`" >> "$GITHUB_STEP_SUMMARY"
801-
fi
802-
done
803-
if [ ! -f "$COMPILE_DIR/.github/workflows/squad-bootstrap.lock.yml" ]; then
804-
echo "::error::squad-bootstrap.lock.yml not emitted — compiler exited 0 without writing output"
805-
echo "❌ missing: \`squad-bootstrap.lock.yml\`" >> "$GITHUB_STEP_SUMMARY"
806-
FAILED=$((FAILED + 1))
807-
else
808-
echo "✅ \`squad-bootstrap.lock.yml\`" >> "$GITHUB_STEP_SUMMARY"
809-
fi
810-
if [ "$FAILED" -gt 0 ]; then
811-
echo "" >> "$GITHUB_STEP_SUMMARY"
812-
echo "**❌ $FAILED failure(s) — gate fails closed**" >> "$GITHUB_STEP_SUMMARY"
813-
echo "::error::$FAILED failure(s) — gate fails closed"
814-
exit 1
815-
fi
816-
echo "" >> "$GITHUB_STEP_SUMMARY"
817-
echo "**✅ All seven workflows compiled, all seven lock files emitted**" >> "$GITHUB_STEP_SUMMARY"
773+
CONSUMER_DIR="$GITHUB_WORKSPACE/.gh-aw-consumer"
774+
rm -rf "$CONSUMER_DIR"
775+
trap 'rm -rf "$CONSUMER_DIR"' EXIT
776+
mkdir -p "$CONSUMER_DIR"
777+
git -C "$CONSUMER_DIR" init --quiet
778+
git -C "$CONSUMER_DIR" remote add origin https://github.com/example/squad-consumer.git
779+
(
780+
cd "$CONSUMER_DIR"
781+
gh aw add "$GITHUB_WORKSPACE/workflows"
782+
node .github/workflows/shared/squad-install-verifier.mjs \
783+
--write-local-test-ownership \
784+
--source-revision "$SQUAD_SOURCE_REVISION"
785+
node .github/workflows/shared/squad-install-verifier.mjs --materialize-runtime
786+
test "$(find .github/workflows -maxdepth 1 -name 'squad*.md' | wc -l | tr -d ' ')" = 7
787+
test "$(find .github/workflows/shared -type f ! -name 'squad-bootstrap-trigger-probe.json' | wc -l | tr -d ' ')" = 15
788+
test "$(find .github/skills/gh-aw-enlistment -type f | wc -l | tr -d ' ')" = 1
789+
gh aw compile --strict --approve --no-check-update
790+
for workflow in squad squad-implement-worker squad-review squad-deps-worker squad-retro squad-improvement-worker squad-bootstrap; do
791+
gh aw compile "$workflow" --strict --no-check-update
792+
test -f ".github/workflows/${workflow}.lock.yml"
793+
done
794+
gh aw compile --strict --no-check-update
795+
node .github/workflows/shared/squad-install-verifier.mjs \
796+
--verify-install \
797+
--source-revision "$SQUAD_SOURCE_REVISION" \
798+
--strict-compile
799+
)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Squad gh-aw hosted E2E
2+
3+
# This controller is intentionally available only through repository_dispatch,
4+
# which GitHub loads from the default branch. The squad-gh-aw-e2e environment
5+
# must additionally restrict deployment branches to the protected `dev` branch.
6+
# Configure these environment variables:
7+
# - SQUAD_GH_AW_E2E_TARGET_REPOSITORY (canonical owner/name)
8+
# - SQUAD_GH_AW_E2E_TARGET_REPOSITORY_ID (numeric repository ID)
9+
# - SQUAD_GH_AW_E2E_TARGET_OWNER_ID (numeric owner ID)
10+
# - SQUAD_GH_AW_E2E_PAT_ACTOR_LOGIN and SQUAD_GH_AW_E2E_PAT_ACTOR_ID
11+
# The SQUAD_GH_AW_E2E_TOKEN secret is scoped only to that one public consumer.
12+
on:
13+
repository_dispatch:
14+
types: [squad-gh-aw-hosted-e2e]
15+
16+
permissions:
17+
contents: read
18+
19+
concurrency:
20+
group: squad-gh-aw-hosted-e2e
21+
cancel-in-progress: false
22+
23+
jobs:
24+
hosted-e2e:
25+
name: Install, merge, bootstrap, and probe
26+
if: >-
27+
github.repository == 'bradygaster/squad'
28+
&& github.ref_name == github.event.repository.default_branch
29+
runs-on: ubuntu-latest
30+
timeout-minutes: 45
31+
environment: squad-gh-aw-e2e
32+
steps:
33+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
34+
with:
35+
ref: ${{ github.event.repository.default_branch }}
36+
fetch-depth: 0
37+
persist-credentials: false
38+
39+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v6
40+
with:
41+
node-version: 22
42+
cache: npm
43+
44+
- name: Install trusted controller dependencies
45+
run: |
46+
npm config set registry "https://packagefeedproxy.microsoft.io/npm/"
47+
npm ci --ignore-scripts
48+
49+
- name: Install pinned gh-aw
50+
env:
51+
GH_TOKEN: ${{ github.token }}
52+
run: |
53+
gh extension install --force --pin v0.89.21 github/gh-aw
54+
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.21
55+
56+
- name: Verify trusted default-branch controller
57+
env:
58+
GH_TOKEN: ${{ github.token }}
59+
run: |
60+
set -euo pipefail
61+
npm run gh-aw:integrity:check
62+
node scripts/gh-aw-hosted-e2e.mjs source-preflight \
63+
--source-repository "$GITHUB_REPOSITORY" \
64+
--source-repository-id "$GITHUB_REPOSITORY_ID" \
65+
--source-ref "$GITHUB_REF" \
66+
--source-sha "$GITHUB_SHA"
67+
test -z "$(git status --porcelain --untracked-files=no)"
68+
69+
- name: Run trusted hosted journey
70+
env:
71+
GH_TOKEN: ${{ secrets.SQUAD_GH_AW_E2E_TOKEN }}
72+
TARGET_REPOSITORY: ${{ vars.SQUAD_GH_AW_E2E_TARGET_REPOSITORY }}
73+
TARGET_REPOSITORY_ID: ${{ vars.SQUAD_GH_AW_E2E_TARGET_REPOSITORY_ID }}
74+
TARGET_OWNER_ID: ${{ vars.SQUAD_GH_AW_E2E_TARGET_OWNER_ID }}
75+
PAT_ACTOR_LOGIN: ${{ vars.SQUAD_GH_AW_E2E_PAT_ACTOR_LOGIN }}
76+
PAT_ACTOR_ID: ${{ vars.SQUAD_GH_AW_E2E_PAT_ACTOR_ID }}
77+
SOURCE_READ_TOKEN: ${{ github.token }}
78+
run: |
79+
set -euo pipefail
80+
node scripts/gh-aw-hosted-e2e.mjs hosted \
81+
--target "$TARGET_REPOSITORY" \
82+
--target-repository-id "$TARGET_REPOSITORY_ID" \
83+
--target-owner-id "$TARGET_OWNER_ID" \
84+
--pat-actor-login "$PAT_ACTOR_LOGIN" \
85+
--pat-actor-id "$PAT_ACTOR_ID" \
86+
--source-repository "$GITHUB_REPOSITORY" \
87+
--source-repository-id "$GITHUB_REPOSITORY_ID" \
88+
--source-ref "$GITHUB_REF" \
89+
--source-sha "$GITHUB_SHA" \
90+
--evidence "$RUNNER_TEMP/squad-gh-aw-hosted-e2e"
91+
92+
- name: Upload hosted evidence
93+
if: always()
94+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7
95+
with:
96+
name: squad-gh-aw-hosted-e2e-${{ github.run_id }}
97+
path: ${{ runner.temp }}/squad-gh-aw-hosted-e2e/
98+
if-no-files-found: error
99+
retention-days: 30

0 commit comments

Comments
 (0)