Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/bright-gh-aw-central-ops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@bradygaster/squad-cli": patch
"@bradygaster/squad-sdk": patch
---

Require gh-aw v0.89.22 across the Squad workflow package, enlistment guidance, integrity contract, CI, and hosted E2E controller for central agentic ops compatibility. Validate isolated bootstrap candidates against the trusted checkout's Git history so materialization can create the Cast PR and research issue.
8 changes: 4 additions & 4 deletions .github/workflows/squad-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,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.89.21 github/gh-aw
run: gh extension install --pin v0.89.22 github/gh-aw
env:
GH_TOKEN: ${{ github.token }}
- name: Build
Expand Down Expand Up @@ -749,10 +749,10 @@ jobs:
npm config set registry "https://packagefeedproxy.microsoft.io/npm/"
npm ci --ignore-scripts

- name: Install gh-aw v0.89.21 (pinned)
- name: Install gh-aw v0.89.22 (pinned)
run: |
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.21
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.22
env:
GH_TOKEN: ${{ github.token }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/squad-gh-aw-hosted-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.21
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version 2>&1 | awk '{print $NF}')" = v0.89.22

- name: Verify trusted default-branch controller
env:
Expand Down
8 changes: 4 additions & 4 deletions .squad-templates/skills/gh-aw-enlistment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.n
echo "Repo: ${owner_repo} Default branch: ${default_branch}"

# Install the package-capable compiler version used by the distribution contract
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.21"
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22"

# Git state must be understood and clean enough to isolate the install
git status --short
```

> **Portability — compiler check:** use the equivalent PowerShell commands to
> force-install `github/gh-aw` at `v0.89.21`, then confirm `gh aw --version`
> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version`
> reports that exact version before installation.

- **STOP** if `gh auth status` is not logged in, or is logged in as the wrong
Expand Down Expand Up @@ -222,7 +222,7 @@ This must run after any first-install approval and before committing. Success
criteria:

- All eight workflows compile successfully.
- With gh-aw v0.89.21, require exactly two warnings, one occurrence of each
- With gh-aw v0.89.22, require exactly two warnings, one occurrence of each
exact diagnostic header below (including its workflow path):

<!-- compile-warning-allowlist-start -->
Expand Down
10 changes: 5 additions & 5 deletions docs/src/content/docs/guide/gh-aw.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ set -euo pipefail
gh auth status
owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')"
default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')"
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.21"
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22"

# 2. Require GitHub Issues, then allow GitHub Actions to create pull requests
issues_enabled="$(gh api "repos/${owner_repo}" --jq '.has_issues')"
Expand Down Expand Up @@ -341,7 +341,7 @@ gh aw compile --strict
```

Run this exact command after any required first-install approval and before
committing. With gh-aw v0.89.21, require exactly two warnings, one occurrence
committing. With gh-aw v0.89.22, require exactly two warnings, one occurrence
of each exact diagnostic header below (including its workflow path):

<!-- compile-warning-allowlist-start -->
Expand Down Expand Up @@ -1849,7 +1849,7 @@ 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.89.21 emits
`package_lock_sha256` for a package-root annotation. gh-aw v0.89.22 emits
`bradygaster/squad/workflows@SHA` for direct package includes, but can emit
`bradygaster/squad/workflows/package/<workflow>.md@SHA` when installing dispatched
dependencies. Fresh and forced installs can therefore contain different mixtures.
Expand All @@ -1859,7 +1859,7 @@ URLs, action pins, permissions and runtime bytes remain integrity-checked.
No additional fields are removed during lock normalization.

Manifest generation and installation test fixtures seed isolated compiler action
locks with the immutable `setup` and `setup-cli` pins for gh-aw v0.89.21. Both
locks with the immutable `setup` and `setup-cli` pins for gh-aw v0.89.22. 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.n
echo "Repo: ${owner_repo} Default branch: ${default_branch}"

# Install the package-capable compiler version used by the distribution contract
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.21"
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22"

# Git state must be understood and clean enough to isolate the install
git status --short
```

> **Portability — compiler check:** use the equivalent PowerShell commands to
> force-install `github/gh-aw` at `v0.89.21`, then confirm `gh aw --version`
> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version`
> reports that exact version before installation.

- **STOP** if `gh auth status` is not logged in, or is logged in as the wrong
Expand Down Expand Up @@ -222,7 +222,7 @@ This must run after any first-install approval and before committing. Success
criteria:

- All eight workflows compile successfully.
- With gh-aw v0.89.21, require exactly two warnings, one occurrence of each
- With gh-aw v0.89.22, require exactly two warnings, one occurrence of each
exact diagnostic header below (including its workflow path):

<!-- compile-warning-allowlist-start -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.n
echo "Repo: ${owner_repo} Default branch: ${default_branch}"

# Install the package-capable compiler version used by the distribution contract
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.21"
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22"

# Git state must be understood and clean enough to isolate the install
git status --short
```

> **Portability — compiler check:** use the equivalent PowerShell commands to
> force-install `github/gh-aw` at `v0.89.21`, then confirm `gh aw --version`
> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version`
> reports that exact version before installation.

- **STOP** if `gh auth status` is not logged in, or is logged in as the wrong
Expand Down Expand Up @@ -222,7 +222,7 @@ This must run after any first-install approval and before committing. Success
criteria:

- All eight workflows compile successfully.
- With gh-aw v0.89.21, require exactly two warnings, one occurrence of each
- With gh-aw v0.89.22, require exactly two warnings, one occurrence of each
exact diagnostic header below (including its workflow path):

<!-- compile-warning-allowlist-start -->
Expand Down
8 changes: 4 additions & 4 deletions scripts/validate-gh-aw-cast.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ function committedRegistry(root, errors) {
}
}

function parseRegistry(root, errors) {
function parseRegistry(root, errors, gitRoot = root) {
let registryRaw;
let historyRaw;
try {
Expand All @@ -543,7 +543,7 @@ function parseRegistry(root, errors) {
}
const registry = parseCastingPair(registryRaw, historyRaw, 'registry', errors);
if (!registry) return [];
const base = committedRegistry(root, errors);
const base = committedRegistry(gitRoot, errors);
if (base) {
const baseRevision = base.schema === 'squad-agent-provenance/v1' ? base.revision : 0;
if (registry.revision <= baseRevision) {
Expand Down Expand Up @@ -631,7 +631,7 @@ function validateCapabilities(coordinator, active, routingRows, errors) {
}
}

export function validateCastTree({ root, payloadPath }) {
export function validateCastTree({ root, payloadPath, gitRoot = root }) {
const errors = [];
let payloadValue;
try {
Expand Down Expand Up @@ -660,7 +660,7 @@ export function validateCastTree({ root, payloadPath }) {
if (!payload.includes(required)) errors.push(`payload: missing required path ${required}`);
}

const active = parseRegistry(root, errors);
const active = parseRegistry(root, errors, gitRoot);
const activeNames = new Set(active.map(({ name }) => name));
const activeCharters = active.map(({ id }) => `.squad/agents/${id}/charter.md`);
const expectedPayload = new Set([...CORE_PAYLOAD, ...activeCharters, ...REQUIRED_BUILTIN_CHARTERS]);
Expand Down
8 changes: 4 additions & 4 deletions templates/skills/gh-aw-enlistment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.n
echo "Repo: ${owner_repo} Default branch: ${default_branch}"

# Install the package-capable compiler version used by the distribution contract
gh extension install --force --pin v0.89.21 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.21"
gh extension install --force --pin v0.89.22 github/gh-aw
test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22"

# Git state must be understood and clean enough to isolate the install
git status --short
```

> **Portability — compiler check:** use the equivalent PowerShell commands to
> force-install `github/gh-aw` at `v0.89.21`, then confirm `gh aw --version`
> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version`
> reports that exact version before installation.

- **STOP** if `gh auth status` is not logged in, or is logged in as the wrong
Expand Down Expand Up @@ -222,7 +222,7 @@ This must run after any first-install approval and before committing. Success
criteria:

- All eight workflows compile successfully.
- With gh-aw v0.89.21, require exactly two warnings, one occurrence of each
- With gh-aw v0.89.22, require exactly two warnings, one occurrence of each
exact diagnostic header below (including its workflow path):

<!-- compile-warning-allowlist-start -->
Expand Down
25 changes: 24 additions & 1 deletion test/gh-aw-bootstrap-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from 'node:fs';
import { execFileSync, spawnSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import { dirname, join, resolve } from 'node:path';
import { dirname, join, relative, resolve } from 'node:path';
import { tmpdir } from 'node:os';
import { fileURLToPath } from 'node:url';
import { parse } from 'yaml';
Expand All @@ -31,6 +31,7 @@ import {
findBootstrapResearchArtifacts,
isBootstrapResearchSeed,
reconstructBootstrapPayload,
validateBootstrapPayload,
} from '../workflows/shared/squad-bootstrap-validator.mjs';

const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
Expand Down Expand Up @@ -601,6 +602,27 @@ describe('automatic Squad bootstrap workflow', () => {
const result = validateFixture(fixture);
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toBe('Squad bootstrap validation passed.\n');
});

it('validates an isolated candidate against the trusted checkout Git history', () => {
const fixture = createFixture();
const candidate = mkdtempSync(join(tmpdir(), 'gh-aw-bootstrap-candidate-'));
workspaces.push(candidate);
cpSync(fixture.root, candidate, {
recursive: true,
filter: source => relative(fixture.root, source).split('/')[0] !== '.git',
});
const options = {
root: candidate,
payloadPath: join(candidate, 'payload.json'),
repository: 'octo/example',
defaultBranch: 'main',
linkMode: 'placeholder',
};
expect(validateBootstrapPayload(options)).toContainEqual(
expect.stringContaining('registry base: committed HEAD is unavailable'),
);
expect(validateBootstrapPayload({ ...options, gitRoot: fixture.root })).toEqual([]);

const resolved = {
...fixture.payload,
Expand Down Expand Up @@ -849,6 +871,7 @@ describe('automatic Squad bootstrap workflow', () => {
expect(lock).not.toMatch(/"materialize-bootstrap":\{"inputs":\{"payload":/);
expect(lock).toContain('reconstructBootstrapPayload(items[0])');
expect(lock).toContain("mkdtempSync(join(tmpdir(), 'squad-bootstrap-candidate-'))");
expect(lock).toContain('gitRoot: checkout');
expect(lock).toContain('Bootstrap payload path crosses a symbolic link');
expect(lock.indexOf("validate(payload, 'placeholder')"))
.toBeLessThan(lock.indexOf('safeTarget(checkout, file.path)'));
Expand Down
2 changes: 1 addition & 1 deletion test/gh-aw-enlistment-skill.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('gh-aw-enlistment skill', () => {
});

it('pins and verifies the package-capable gh-aw compiler', () => {
expect(content).toContain('gh extension install --force --pin v0.89.21 github/gh-aw');
expect(content).toContain('gh extension install --force --pin v0.89.22 github/gh-aw');
expect(content).toContain('gh aw --version');
expect(content).toContain('PowerShell');
});
Expand Down
8 changes: 4 additions & 4 deletions test/gh-aw-quality.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3829,7 +3829,7 @@ describe('gh-aw: canonical package integrity contract', () => {
package: PACKAGE_NAME,
source: `${PACKAGE_NAME}@${revision}`,
resolvedCommit: revision,
installer: 'gh-aw v0.89.21 test',
installer: 'gh-aw v0.89.22 test',
files: owned,
}, null, 2)}\n`);
return root;
Expand Down Expand Up @@ -3961,8 +3961,8 @@ describe('gh-aw: canonical package integrity contract', () => {
expect(mutable).not.toContain(actionReference);
expect(createHash('sha256').update(normalizeCompiledLock(mutable, revisionA)).digest('hex'))
.toBe(sourceBinding === 'workflow'
? '8456d8129241269c107cdf4b16ae079e89a98ef944152df36f53ec0decf3f30d'
: 'bac4d8b90269d827fc9e626dd02c1b536bccde7105e9037971740054cda4c19b');
? 'a3290dad380577fd6d64c92169b9d74a7f5248851b110d8eafc6260b34f772d9'
: 'fd7c735e2de5088954e8d0d647a15e5f95ed5850947f201c1a4ce17433d66632');
expect(() => validateCompilerActionPins(mutable)).toThrow(/invalid immutable action pin/);
writeFileSync(lockPath, mutable);
expect(verifyInstall(root).failures.join('\n'))
Expand Down Expand Up @@ -4016,7 +4016,7 @@ describe('gh-aw: canonical package integrity contract', () => {
compile();
const unpinned = readText(lockPath);
expect(createHash('sha256').update(normalizeCompiledLock(unpinned, revisionA)).digest('hex'))
.toBe('bac4d8b90269d827fc9e626dd02c1b536bccde7105e9037971740054cda4c19b');
.toBe('fd7c735e2de5088954e8d0d647a15e5f95ed5850947f201c1a4ce17433d66632');
expect(verifyInstall(root).failures.join('\n')).toContain('Installed digest mismatch');

const seedPins = () => spawnSync(process.execPath, ['--input-type=module', '-e', seed!], {
Expand Down
4 changes: 2 additions & 2 deletions test/gh-aw-review-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.89.21');
expect(manifest).toContain('min-version: v0.89.22');
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.89.21 github/gh-aw',
'gh extension install --force --pin v0.89.22 github/gh-aw',
);
});

Expand Down
2 changes: 1 addition & 1 deletion test/helpers/gh-aw-install-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export function createFirstInstallFixture(
package: PACKAGE_NAME,
source: `${PACKAGE_NAME}@${revision}`,
resolvedCommit: revision,
installer: 'gh-aw v0.89.21 test',
installer: 'gh-aw v0.89.22 test',
files,
},
consumerFiles,
Expand Down
2 changes: 1 addition & 1 deletion workflows/aw.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
manifest-version: "1"
min-version: v0.89.21
min-version: v0.89.22
name: Squad Agentic Workflows
emoji: "🤖"
description: Complete, integrity-checked Squad workflow bundle for issue-driven planning and implementation.
Expand Down
7 changes: 4 additions & 3 deletions workflows/package/squad-bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ pre-agent-steps:
node --check "$path" >/dev/null
}
# BEGIN GENERATED RESOURCE DIGESTS
check_hash "$install_verifier" "40753edd5995c5f7ba058f57fbcc5aff0ccf3341c721b764fa0cf1dc70eba3f1"
check_hash "$cast_validator" "0988e04aeef316f4d7a0107c902bbbcf6538b8899b9fffba5f62150717967685"
check_hash "$bootstrap_validator" "4fc1bcc79b887bb4f2f78e7eef8693d5c1eaf817d8715ce3c92169934aa225b7"
check_hash "$install_verifier" "cf474be9b04d339f7e7a18c65e776b8a53e84bea5b4b85abfe65ed11f7b782ce"
check_hash "$cast_validator" "c6d0b92aac71dc6f6d5727cac418a323b0bc9c12047400faa12d96150d548ada"
check_hash "$bootstrap_validator" "6f2ff60104a238c7c171031e737fd8dcb57dd3eeffccbf8c0aeaad016d85ee4e"
# END GENERATED RESOURCE DIGESTS
node "$bootstrap_validator" \
--encode-payload "${GITHUB_WORKSPACE:?}/.github/workflows/squad-bootstrap-payload.json" \
Expand Down Expand Up @@ -316,6 +316,7 @@ safe-outputs:
writeFileSync(candidatePayloadPath, `${JSON.stringify(candidatePayload)}\n`);
const errors = validatorModule.validateBootstrapPayload({
root: candidate,
gitRoot: checkout,
payloadPath: candidatePayloadPath,
repository: context.repo.owner + '/' + context.repo.repo,
defaultBranch: process.env.SQUAD_BOOTSTRAP_DEFAULT_BRANCH,
Expand Down
2 changes: 1 addition & 1 deletion workflows/package/squad.md
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ pre-agent-steps:
validator_script="$(cd "$(dirname "$validator_script")" && pwd -P)/$(basename "$validator_script")"

# BEGIN GENERATED RESOURCE DIGEST
validator_expected_sha256="0988e04aeef316f4d7a0107c902bbbcf6538b8899b9fffba5f62150717967685"
validator_expected_sha256="c6d0b92aac71dc6f6d5727cac418a323b0bc9c12047400faa12d96150d548ada"
# END GENERATED RESOURCE DIGEST
: > "$stderr_file"
validator_actual_sha256="$(
Expand Down
3 changes: 2 additions & 1 deletion workflows/shared/squad-bootstrap-validator.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ export function createBootstrapResearchComment(issueBodyText, issueNumber) {

export function validateBootstrapPayload({
root,
gitRoot = root,
payloadPath,
repository,
defaultBranch,
Expand Down Expand Up @@ -588,7 +589,7 @@ export function validateBootstrapPayload({
try {
const castPayloadPath = join(tempDir, 'cast-paths.json');
writeFileSync(castPayloadPath, `${JSON.stringify(castPaths)}\n`);
errors.push(...validateCastTree({ root, payloadPath: castPayloadPath }));
errors.push(...validateCastTree({ root, gitRoot, payloadPath: castPayloadPath }));
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
Expand Down
Loading
Loading