Repository navigation
deps: Bump the minor-patch group across 1 directory with 21 updates #287
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Squad Release Verify | |
| # Fail-closed verification at an EXACT commit, run before any release side effect | |
| # (tag, GitHub release, npm publish, standalone bundles) and on release-prep PRs. | |
| # | |
| # It produces the immutable evidence bundle (`release-evidence-<sha>` artifact): | |
| # - npm-ci.json clean external `npm ci` on the COMMITTED lockfiles (no repair), | |
| # public registry only, isolated HOME and empty user npmrc | |
| # - lockfile-registry.json every tracked package-lock.json resolves to registry.npmjs.org (sha512) | |
| # - policy-gates.json workspace integrity, prerelease guard, publish policy + allowlist, | |
| # changelog heading, changeset drain — no label/variable bypass | |
| # - vitest-report.json + test-reconciliation.json every test bucketed; counts must sum | |
| # - pack-evidence.json + both .tgz + .sha256 exact packs, integrity, file lists, | |
| # export-target validation, privacy scan | |
| # - registry-preflight.json read-only npm version/tag, Git tag-ref and GitHub release classification | |
| # - squad-2.0-verification-manifest-<sha>.json/.md + provenance.json + manifest.schema.json | |
| # | |
| # No skip labels and no SQUAD_*_CHECK repository variables are consulted here. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| sha: | |
| description: 'Full lowercase 40-hex candidate commit SHA to check out and verify' | |
| required: true | |
| type: string | |
| workflow_call: | |
| inputs: | |
| source_sha: | |
| description: 'Full 40-hex commit SHA to verify (checkout must resolve to exactly this)' | |
| required: true | |
| type: string | |
| expected_version: | |
| description: 'If set, package.json at source_sha must read exactly this version' | |
| required: false | |
| default: '' | |
| type: string | |
| outputs: | |
| version: | |
| description: 'Root package.json version at source_sha' | |
| value: ${{ jobs.verify.outputs.version }} | |
| evidence_artifact: | |
| description: 'Name of the uploaded evidence artifact' | |
| value: ${{ jobs.verify.outputs.evidence_artifact }} | |
| sdk_sha256: | |
| description: 'sha256 of the packed @bradygaster/squad-sdk tarball' | |
| value: ${{ jobs.verify.outputs.sdk_sha256 }} | |
| cli_sha256: | |
| description: 'sha256 of the packed @bradygaster/squad-cli tarball' | |
| value: ${{ jobs.verify.outputs.cli_sha256 }} | |
| pull_request: | |
| branches: [dev, main] | |
| paths: | |
| - '.github/workflows/squad-release*.yml' | |
| - '.github/workflows/squad-npm-publish.yml' | |
| - 'scripts/release/**' | |
| - 'scripts/build-standalone.mjs' | |
| - 'package.json' | |
| - 'package-lock.json' | |
| - 'packages/*/package.json' | |
| - 'packages/squad-sdk/src/platform/comms-teams.ts' | |
| - 'CHANGELOG.md' | |
| - 'docs/src/content/docs/whatsnew.md' | |
| - '.gitattributes' | |
| - '.changeset/**' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.source_sha || inputs.sha || github.event.pull_request.head.sha }} | |
| cancel-in-progress: false | |
| jobs: | |
| verify-windows-platform: | |
| name: Verify Windows-only release tests | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| env: | |
| SOURCE_SHA: ${{ inputs.source_sha || inputs.sha || github.event.pull_request.head.sha }} | |
| EVIDENCE_DIR: ${{ github.workspace }}\evidence-windows | |
| steps: | |
| - name: Validate requested SHA | |
| shell: pwsh | |
| run: | | |
| if ($env:SOURCE_SHA -notmatch '^[0-9a-f]{40}$') { throw "sha must be a full lowercase 40-hex SHA, got '$env:SOURCE_SHA'" } | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7 | |
| with: | |
| ref: ${{ inputs.source_sha || inputs.sha || github.event.pull_request.head.sha }} | |
| fetch-depth: 0 | |
| - name: Assert checkout is exactly the requested SHA | |
| shell: pwsh | |
| run: | | |
| if ($env:SOURCE_SHA -notmatch '^[0-9a-f]{40}$') { throw "source_sha must be a full lowercase 40-hex SHA, got '$env:SOURCE_SHA'" } | |
| $head = git rev-parse HEAD | |
| if ($head -ne $env:SOURCE_SHA) { throw "checkout HEAD $head != requested $env:SOURCE_SHA" } | |
| New-Item -ItemType Directory -Force -Path $env:EVIDENCE_DIR | Out-Null | |
| - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 #v6 | |
| with: | |
| node-version: '22.23.4' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build workspace packages | |
| env: | |
| SKIP_BUILD_BUMP: '1' | |
| run: npm run build | |
| - name: Run Windows platform suite with JSON report | |
| run: npx vitest run test/mcp-root-write.test.ts test/memory-providers.test.ts --reporter=default --reporter=json --outputFile="$env:EVIDENCE_DIR\vitest-report.json" | |
| - name: Require the Windows-only test to execute | |
| if: always() | |
| run: node scripts/release/test-reconciliation.mjs --report "$env:EVIDENCE_DIR\vitest-report.json" --out "$env:EVIDENCE_DIR" --platform win32 --require-platform-executions --fail-on-unexplained | |
| - name: Upload Windows platform evidence | |
| if: always() | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 #v7 | |
| with: | |
| name: release-windows-platform-evidence-${{ env.SOURCE_SHA }} | |
| path: evidence-windows/ | |
| retention-days: 90 | |
| if-no-files-found: warn | |
| verify: | |
| name: Verify exact SHA and build evidence | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| evidence_artifact: ${{ steps.artifact.outputs.name }} | |
| sdk_sha256: ${{ steps.pack.outputs.sdk_sha256 }} | |
| cli_sha256: ${{ steps.pack.outputs.cli_sha256 }} | |
| env: | |
| SOURCE_SHA: ${{ inputs.source_sha || inputs.sha || github.event.pull_request.head.sha }} | |
| EVIDENCE_DIR: ${{ github.workspace }}/evidence | |
| steps: | |
| - name: Validate requested SHA | |
| run: | | |
| set -euo pipefail | |
| [[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]] || { echo "::error::sha must be a full lowercase 40-hex SHA, got '$SOURCE_SHA'"; exit 1; } | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7 | |
| with: | |
| ref: ${{ inputs.source_sha || inputs.sha || github.event.pull_request.head.sha }} | |
| fetch-depth: 0 | |
| - name: Assert checkout is exactly the requested SHA | |
| run: | | |
| set -euo pipefail | |
| [[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]] || { echo "::error::source_sha must be a full lowercase 40-hex SHA, got '$SOURCE_SHA'"; exit 1; } | |
| head="$(git rev-parse HEAD)" | |
| test "$head" = "$SOURCE_SHA" || { echo "::error::checkout HEAD $head != requested $SOURCE_SHA"; exit 1; } | |
| echo "tree=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_OUTPUT" | |
| echo "Verifying $SOURCE_SHA (tree $(git rev-parse 'HEAD^{tree}'))" | |
| mkdir -p "$EVIDENCE_DIR" | |
| - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 #v6 | |
| with: | |
| node-version: '22.23.4' | |
| - name: Resolve version | |
| id: version | |
| env: | |
| EXPECTED_VERSION: ${{ inputs.expected_version }} | |
| run: | | |
| set -euo pipefail | |
| version="$(node -p 'require("./package.json").version')" | |
| if [ -n "$EXPECTED_VERSION" ] && [ "$version" != "$EXPECTED_VERSION" ]; then | |
| echo "::error::package.json version '$version' != expected '$EXPECTED_VERSION'"; exit 1 | |
| fi | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: "Gate: lockfiles resolve only to registry.npmjs.org (fail closed)" | |
| run: | | |
| set -euo pipefail | |
| node scripts/release/check-lockfile-registry.mjs --json > "$EVIDENCE_DIR/lockfile-registry.json" | |
| node scripts/release/check-lockfile-registry.mjs | |
| - name: "Proof: clean external npm ci on the committed lockfiles (no repair)" | |
| run: | | |
| set -euo pipefail | |
| iso="$RUNNER_TEMP/npm-ci-proof" | |
| mkdir -p "$iso/home" "$iso/cache" | |
| : > "$iso/empty.npmrc" | |
| cmd='npm ci --registry=https://registry.npmjs.org/' | |
| set +e | |
| HOME="$iso/home" NPM_CONFIG_USERCONFIG="$iso/empty.npmrc" NPM_CONFIG_CACHE="$iso/cache" npm ci --registry=https://registry.npmjs.org/ | |
| root_exit=$? | |
| ( cd docs && HOME="$iso/home" NPM_CONFIG_USERCONFIG="$iso/empty.npmrc" NPM_CONFIG_CACHE="$iso/cache" npm ci --registry=https://registry.npmjs.org/ ) | |
| docs_exit=$? | |
| set -e | |
| node scripts/release/write-npm-ci-evidence.mjs "$cmd" "$root_exit" "$docs_exit" "$SOURCE_SHA" | |
| cat "$EVIDENCE_DIR/npm-ci.json" | |
| test "$root_exit" -eq 0 || { echo "::error::root npm ci against the public registry failed (exit $root_exit)"; exit 1; } | |
| test "$docs_exit" -eq 0 || { echo "::error::docs npm ci against the public registry failed (exit $docs_exit)"; exit 1; } | |
| git diff --quiet -- package-lock.json docs/package-lock.json || { echo "::error::npm ci modified a committed lockfile"; git --no-pager diff --stat -- package-lock.json docs/package-lock.json; exit 1; } | |
| - 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 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Resolve Playwright version | |
| id: playwright | |
| run: echo "version=$(node -p "require('playwright/package.json').version")" >> "$GITHUB_OUTPUT" | |
| - name: Cache Playwright browsers | |
| id: playwright-cache | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-${{ runner.os }}-${{ steps.playwright.outputs.version }} | |
| - name: Install Playwright browsers | |
| run: | | |
| if [ "${{ steps.playwright-cache.outputs.cache-hit }}" = "true" ]; then | |
| npx playwright install-deps chromium | |
| else | |
| npx playwright install chromium --with-deps | |
| fi | |
| - name: Build | |
| run: npm run build | |
| - name: "Gate: release policy (no label or variable bypass)" | |
| env: | |
| # Pull requests validate pending changesets in CI mode. Both side-effect-free dispatches | |
| # and workflow_call from squad-release.yml enforce the release drain before publication. | |
| POLICY_MODE: ${{ (inputs.source_sha != '' || inputs.sha != '') && 'release' || 'ci' }} | |
| run: | | |
| set -euo pipefail | |
| node scripts/release/policy-gates.mjs "--mode=$POLICY_MODE" --json > "$EVIDENCE_DIR/policy-gates.json" || true | |
| node scripts/release/policy-gates.mjs "--mode=$POLICY_MODE" | |
| - name: "Gate: changeset drift (fail mode)" | |
| run: node scripts/check-changeset-drift.mjs --mode=fail | |
| - name: "Gate: shebang EOL" | |
| run: node scripts/check-shebang-eol.mjs | |
| - name: "Gate: exports map matches barrel files" | |
| run: node scripts/check-exports-map.mjs | |
| - name: "Gate: every SDK subpath export imports" | |
| run: node scripts/release/smoke-sdk-exports.mjs | |
| - name: Verify product/team isolation | |
| run: npm run verify:team-isolation | |
| - name: Type-check | |
| run: npm run lint | |
| - name: Lint source and tests | |
| run: npm run lint:eslint | |
| - name: Lint docs | |
| run: npm run lint:docs | |
| - name: Run full vitest suite with JSON report | |
| run: npx vitest run --reporter=default --reporter=json --outputFile="$EVIDENCE_DIR/vitest-report.json" | |
| - name: Run node:test suites | |
| run: node --test test/*.test.cjs | |
| - name: Reconcile skip / todo / xfail buckets (counts must sum) | |
| if: always() | |
| run: node scripts/release/test-reconciliation.mjs --report "$EVIDENCE_DIR/vitest-report.json" --out "$EVIDENCE_DIR" --fail-on-unexplained | |
| - name: Build docs site | |
| run: npm run docs:build | |
| - name: Pack evidence (exact tarballs, hashes, file lists, export targets, privacy scan) | |
| id: pack | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| node scripts/release/pack-evidence.mjs --out "$EVIDENCE_DIR" --expect-version "$VERSION" --pin-sdk-dep-exact --expect-sdk-dep-exact | |
| node scripts/release/emit-pack-evidence-hashes.mjs | |
| - name: Isolated-prefix install of the exact packed pair (self-upgrade shape) | |
| env: | |
| SQUAD_RELEASE_PACK_INSTALL: '1' | |
| SQUAD_RELEASE_EVIDENCE_DIR: ${{ env.EVIDENCE_DIR }} | |
| run: npx vitest run test/release-pack-install.test.ts | |
| - name: Build verification manifest, provenance sidecar and validate against the shipped schema | |
| env: | |
| BRANCH: ${{ github.base_ref || github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| node scripts/release/build-manifest.mjs --out "$EVIDENCE_DIR" --sha "$SOURCE_SHA" --branch "$BRANCH" --vitest-report "$EVIDENCE_DIR/vitest-report.json" --baseline-commit f22847a9898d5c90d70a679ee63d9d5f49cd5fed | |
| manifest="$(ls "$EVIDENCE_DIR"/squad-2.0-verification-manifest-*.json)" | |
| node scripts/release/validate-manifest.mjs "$manifest" --provenance "$EVIDENCE_DIR/provenance.json" | |
| { | |
| echo "## Release evidence at \`$SOURCE_SHA\`" | |
| echo | |
| echo '```' | |
| cat "$EVIDENCE_DIR/provenance.json" | |
| echo '```' | |
| echo | |
| sha256sum "$EVIDENCE_DIR"/*.tgz | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Check out read-only registry preflight tooling from the workflow revision | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7 | |
| with: | |
| ref: ${{ github.workflow_sha }} | |
| path: .release-preflight-tooling | |
| sparse-checkout: scripts/release | |
| persist-credentials: false | |
| - name: Record read-only npm registry and GitHub release preflight | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| REQUIRE_ABSENCE: ${{ (inputs.source_sha != '' || inputs.sha != '') && '1' || '0' }} | |
| run: | | |
| set -euo pipefail | |
| absence_args=() | |
| if [ "$REQUIRE_ABSENCE" = "1" ]; then absence_args+=(--require-absence); fi | |
| node .release-preflight-tooling/scripts/release/registry-preflight.mjs \ | |
| --version "$VERSION" \ | |
| --pack-evidence "$EVIDENCE_DIR/pack-evidence.json" \ | |
| --registry https://registry.npmjs.org/ \ | |
| --repository "$GITHUB_REPOSITORY" \ | |
| --tag "v${VERSION}" \ | |
| --out "$EVIDENCE_DIR/registry-preflight.json" \ | |
| "${absence_args[@]}" | |
| cat "$EVIDENCE_DIR/registry-preflight.json" | |
| - name: Name evidence artifact | |
| id: artifact | |
| if: always() | |
| run: echo "name=release-evidence-${SOURCE_SHA}" >> "$GITHUB_OUTPUT" | |
| - name: Upload evidence bundle (also on failure, for diagnosis) | |
| if: always() | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 #v7 | |
| with: | |
| name: ${{ steps.artifact.outputs.name }} | |
| path: evidence/ | |
| retention-days: 90 | |
| if-no-files-found: warn |