fix(release): accept canonical workflow pagination links #1530
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: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: read | |
| jobs: | |
| metadata_scope: | |
| name: metadata-scope | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| metadata_only: ${{ steps.classify.outputs.metadata_only }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24.17.0 | |
| - name: Classify metadata-only change | |
| id: classify | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -eu | |
| METADATA_ONLY="$(node scripts/ci-scope.mjs --event pull_request --base "$BASE_SHA" --head "$HEAD_SHA")" | |
| case "$METADATA_ONLY" in | |
| true|false) ;; | |
| *) echo "Malformed metadata-only scope output" >&2; exit 1 ;; | |
| esac | |
| printf 'metadata_only=%s\n' "$METADATA_ONLY" >> "$GITHUB_OUTPUT" | |
| changesets: | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Require changeset for user-facing changes | |
| env: | |
| BASE_REF: origin/${{ github.event.pull_request.base.ref }} | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| PR_AUTHOR: ${{ github.event.pull_request.user.login }} | |
| run: node scripts/check-changesets.mjs | |
| validate: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Lint | |
| run: pnpm lint | |
| - name: Build Cache Config | |
| run: pnpm check:build-cache | |
| - name: Build | |
| run: pnpm build | |
| - name: Typecheck | |
| run: pnpm typecheck | |
| - name: Source Tests | |
| # `hono-node-roundtrip` needs a Docker daemon — the first suite in | |
| # `pnpm test` ever to, since previously only the `*-docker` jobs did. It | |
| # SKIPS without one so a contributor with no Docker can still run the | |
| # suite, and this flag is the other half of that bargain: on a runner, | |
| # which always has Docker, a skip means the coverage was lost silently, | |
| # so the flag turns it into a hard failure instead. | |
| env: | |
| DAWN_REQUIRE_DOCKER: "1" | |
| run: pnpm test | |
| - name: Release Inventory | |
| run: pnpm check:release-inventory | |
| - name: Release Controller Tests | |
| run: pnpm test:release-controller | |
| - name: Docs Check | |
| run: node scripts/check-docs.mjs | |
| - name: Pack Check | |
| run: pnpm pack:check | |
| - name: TypeScript Tooling Pack Smoke | |
| run: pnpm verify:typescript-tooling-pack | |
| - name: Harness Coordinator Self-Test | |
| run: pnpm verify:harness:self-test | |
| - name: Framework Verification | |
| run: pnpm verify:harness:framework | |
| - name: Runtime Contract Verification | |
| run: pnpm verify:harness:runtime | |
| - name: Smoke Harness Verification | |
| run: pnpm verify:harness:smoke | |
| - name: Upload Harness Artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: harness-artifacts | |
| path: artifacts/testing/ | |
| retention-days: 7 | |
| testing-windows: | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build testing dependency closure | |
| # The focused test starts the CLI from its built dist output. The | |
| # trailing ellipsis selects @dawn-ai/testing and its dependencies. | |
| run: pnpm --filter @dawn-ai/testing... build | |
| - name: Native Windows subprocess shutdown tests | |
| # Exercise the real win32 taskkill tree and the injected stale-dispatch | |
| # guard without running broader Windows HMR coverage. | |
| run: pnpm --filter @dawn-ai/testing exec vitest --run --config vitest.config.ts test/subprocess.test.ts --testNamePattern "Windows process tree|injected Windows tree kill" | |
| - name: Dependency security regressions | |
| run: pnpm exec vitest --run --config test/security-dependencies/vitest.config.ts test/security-dependencies/dependency-resolution.test.ts test/security-dependencies/hono-serve-static-windows.test.ts | |
| dependency-security-browser: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Install Chromium | |
| run: pnpm exec playwright install --with-deps chromium | |
| - name: Dependency security browser regressions | |
| run: | | |
| pnpm exec tsc -p test/security-dependencies/tsconfig.json --noEmit | |
| pnpm exec playwright test --config test/security-dependencies/playwright.config.ts | |
| sandbox-docker: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build sandbox package | |
| run: pnpm --filter @dawn-ai/sandbox... build | |
| - name: Pull sandbox workload image | |
| run: | | |
| SANDBOX_IMAGE="$( | |
| pnpm exec tsx -e 'import { loadCompatibilityPolicy } from "./scripts/kubernetes-compat/policy.ts"; loadCompatibilityPolicy().then((policy) => process.stdout.write(policy.images.sandboxWorkload))' | |
| )" | |
| docker pull "$SANDBOX_IMAGE" | |
| - name: Real-Docker sandbox conformance + e2e | |
| run: DAWN_TEST_DOCKER=1 pnpm --filter @dawn-ai/sandbox test docker-sandbox.integration | |
| pgvector-docker: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build packages | |
| # Full topological build — @dawn-ai/memory-pgvector (and @dawn-ai/testing) | |
| # compile from source against @dawn-ai/cli/@dawn-ai/workspace etc., so a | |
| # narrow per-package filter fails to build those deps first (TS2307). | |
| run: pnpm build | |
| - name: Real-Postgres pgvector tests | |
| run: DAWN_TEST_PGVECTOR=1 pnpm --filter @dawn-ai/memory-pgvector test | |
| postgres-storage-docker: | |
| runs-on: ubuntu-latest | |
| # Five test files (four in @dawn-ai/postgres-storage, one in @dawn-ai/cli) | |
| # each start their own postgres:16 container, and a cold runner also pulls | |
| # the image. 30 minutes leaves headroom for a slow pull plus the | |
| # per-container startup timeout without masking a hung suite. | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build packages | |
| # Full topological build — @dawn-ai/postgres-storage (and @dawn-ai/testing) | |
| # compile from source against @dawn-ai/cli/@dawn-ai/workspace etc., so a | |
| # narrow per-package filter fails to build those deps first (TS2307). | |
| run: pnpm build | |
| - name: Real-Postgres storage tests | |
| run: DAWN_TEST_PGSTORAGE=1 pnpm --filter @dawn-ai/postgres-storage test | |
| - name: Real-Postgres Agent Protocol pending-interrupts tests | |
| # GET /threads/:id/pending_interrupts is purely checkpoint-backed, so the | |
| # spec asks for it against both checkpointer fixtures. This job already | |
| # has Docker and a built workspace, so the gated @dawn-ai/cli lane rides | |
| # here rather than paying for a fourth Postgres job. | |
| # | |
| # A filename filter passed to the package's OWN test script, not a | |
| # spelled-out `exec vitest`: nobody runs this lane locally, so a config | |
| # move or a new setupFiles in that script must not leave this one lane | |
| # silently running a different vitest from every other lane. | |
| # | |
| # Green here means the Postgres assertions RAN, not merely that nothing | |
| # failed. Two different mistakes are covered by two different | |
| # mechanisms: a filter that matches no file exits 1 on its own | |
| # (`passWithNoTests` is false by default in vitest 4), and a suite that | |
| # matches but skips is caught by the "gated Postgres lane" self-check in | |
| # the test file — vitest has no fail-on-skipped flag to do it from here. | |
| run: DAWN_TEST_PGSTORAGE=1 pnpm --filter @dawn-ai/cli test pending-interrupts-endpoint | |
| edge-workerd: | |
| runs-on: ubuntu-latest | |
| # Postgres + a wsproxy container, plus `wrangler dev` booting real workerd. | |
| # 30 minutes leaves headroom for a cold image pull and the workerd binary | |
| # download without masking a hung startup. | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| # The workerd binary arrives through wrangler's postinstall, which pnpm | |
| # 10 blocks unless the package is in `onlyBuiltDependencies` — it is, in | |
| # pnpm-workspace.yaml. Without that the lane fails with no binary to exec. | |
| run: pnpm install --frozen-lockfile | |
| - name: Build packages | |
| # Full topological build, not a filtered one: the lane builds a fixture | |
| # app with `dawn build` and then resolves @dawn-ai/* from dist exactly as | |
| # a deployed bundle does, so every workspace package must be compiled | |
| # first (same #320 lesson as inspector-e2e below). | |
| run: pnpm build | |
| - name: Real-workerd edge lane | |
| # The JSON report is this job's receipt, read by the step below. | |
| run: | | |
| DAWN_TEST_WORKERD=1 pnpm --filter @dawn-ai/cli test workerd-lane \ | |
| --reporter=default --reporter=json \ | |
| --outputFile.json="${{ runner.temp }}/workerd-lane-report.json" | |
| - name: Assert the workerd lane did not skip | |
| # `workerd-lane.test.ts` gates itself on DAWN_TEST_WORKERD, and the step | |
| # above is the ONLY place that flag is set. So any drift between the two | |
| # strings — a rename on either side — turns this merge gate into a no-op | |
| # THAT STILL REPORTS GREEN: every test skips and vitest exits 0. | |
| # (Verified: with the flag unset, "1 skipped", exit 0, success: true.) | |
| # | |
| # Same bargain `DAWN_REQUIRE_DOCKER=1` strikes on validate's Source | |
| # Tests: the escape hatch that lets a contributor run the suite without | |
| # Docker and a workerd binary must not become a way to lose the coverage | |
| # on a runner that has both. | |
| # | |
| # Deliberately NOT `if: always()` — a lane that genuinely FAILED has | |
| # already reddened the job and reported a better message than this one. | |
| # The case this exists for is the lane exiting 0 having run nothing. | |
| run: | | |
| node -e ' | |
| const fs = require("node:fs") | |
| const path = process.argv[1] | |
| if (!fs.existsSync(path)) { | |
| throw new Error("no vitest report at " + path + " — the lane produced no run at all.") | |
| } | |
| const report = JSON.parse(fs.readFileSync(path, "utf8")) | |
| const passed = report.numPassedTests ?? 0 | |
| const skipped = report.numPendingTests ?? 0 | |
| if (passed === 0 || skipped > 0) { | |
| throw new Error( | |
| "the workerd lane reported " + passed + " passed and " + skipped + " skipped. " + | |
| "This job is the only place DAWN_TEST_WORKERD=1 is set, so a skip here means the " + | |
| "merge gate ran nothing while still exiting 0. Check that the flag name in " + | |
| "packages/cli/test/workerd-lane.test.ts still matches the one this job exports.", | |
| ) | |
| } | |
| console.log("workerd lane ran: " + passed + " passed, 0 skipped.") | |
| ' "${{ runner.temp }}/workerd-lane-report.json" | |
| copilotkit-examples-e2e: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Install Chromium | |
| run: pnpm --filter @dawn-example/chat-web exec playwright install --with-deps chromium | |
| - name: Build example workspace dependencies | |
| run: pnpm --filter @dawn-ai/ag-ui build | |
| - name: Verify chat transport | |
| run: pnpm --filter @dawn-example/chat-web test:e2e | |
| - name: Verify research transport | |
| run: pnpm --filter @dawn-example/research-web test:e2e | |
| vercel-native: | |
| if: >- | |
| (github.event_name == 'push' && github.ref == 'refs/heads/main') || | |
| (github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| environment: vercel-preview | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build packages | |
| run: pnpm build | |
| - name: Prepare native Vercel artifact directory | |
| run: install -d -m 0700 -- "${{ runner.temp }}/vercel-native" | |
| - name: Run native Vercel previews | |
| id: native-vercel | |
| env: | |
| DAWN_TEST_VERCEL: "1" | |
| DAWN_VERCEL_TOKEN: ${{ secrets.DAWN_VERCEL_TOKEN }} | |
| DAWN_VERCEL_ORG_ID: ${{ secrets.DAWN_VERCEL_ORG_ID }} | |
| DAWN_VERCEL_PROJECT_ID: ${{ secrets.DAWN_VERCEL_PROJECT_ID }} | |
| DAWN_VERCEL_DATABASE_URL: ${{ secrets.DAWN_VERCEL_DATABASE_URL }} | |
| DAWN_VERCEL_ARTIFACT_DIR: ${{ runner.temp }}/vercel-native | |
| run: >- | |
| pnpm --filter @dawn-ai/cli test vercel-native-lane.test.ts | |
| --reporter=json | |
| --outputFile.json="${{ runner.temp }}/vercel-native/vitest.json" | |
| - name: Reconcile and remove native Vercel resources | |
| id: native-vercel-cleanup | |
| if: always() | |
| env: | |
| DAWN_VERCEL_TOKEN: ${{ secrets.DAWN_VERCEL_TOKEN }} | |
| DAWN_VERCEL_ORG_ID: ${{ secrets.DAWN_VERCEL_ORG_ID }} | |
| DAWN_VERCEL_PROJECT_ID: ${{ secrets.DAWN_VERCEL_PROJECT_ID }} | |
| DAWN_VERCEL_DATABASE_URL: ${{ secrets.DAWN_VERCEL_DATABASE_URL }} | |
| DAWN_VERCEL_ARTIFACT_DIR: ${{ runner.temp }}/vercel-native | |
| run: node packages/cli/test/helpers/vercel-native-cleanup.mjs --cleanup | |
| - name: Assert closed native Vercel receipt | |
| env: | |
| DAWN_VERCEL_ARTIFACT_DIR: ${{ runner.temp }}/vercel-native | |
| run: node packages/cli/test/helpers/vercel-native-cleanup.mjs --assert-receipt | |
| - name: Prepare native Vercel diagnostics | |
| id: native_vercel_diagnostics | |
| if: always() | |
| env: | |
| DAWN_VERCEL_TOKEN: ${{ secrets.DAWN_VERCEL_TOKEN }} | |
| DAWN_VERCEL_ORG_ID: ${{ secrets.DAWN_VERCEL_ORG_ID }} | |
| DAWN_VERCEL_PROJECT_ID: ${{ secrets.DAWN_VERCEL_PROJECT_ID }} | |
| DAWN_VERCEL_DATABASE_URL: ${{ secrets.DAWN_VERCEL_DATABASE_URL }} | |
| DAWN_VERCEL_ARTIFACT_DIR: ${{ runner.temp }}/vercel-native | |
| run: node packages/cli/test/helpers/vercel-native-cleanup.mjs --prepare-artifacts | |
| - name: Upload native Vercel diagnostics | |
| if: failure() && steps.native_vercel_diagnostics.outcome == 'success' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: vercel-native-diagnostics | |
| path: ${{ runner.temp }}/vercel-native/upload/ | |
| if-no-files-found: error | |
| retention-days: 3 | |
| inspector-e2e: | |
| runs-on: ubuntu-latest | |
| # 35, not 20: the browser lane below adds a chromium download, a second | |
| # standalone boot and 19 single-worker spec files (44 tests) on top of the | |
| # vitest lane. | |
| timeout-minutes: 35 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build inspector + workspace deps | |
| # The `...` suffix builds @dawn-ai/inspector AND its workspace deps in | |
| # topological order (`next build` compiles against @dawn-ai/core and | |
| # @dawn-ai/memory dist — the #320 pgvector-lane lesson: partial builds | |
| # break). The e2e tests boot the built .next/standalone server. | |
| run: pnpm turbo run build --filter=@dawn-ai/inspector... | |
| - name: Inspector standalone e2e | |
| run: DAWN_TEST_INSPECTOR=1 pnpm --filter @dawn-ai/inspector test | |
| - name: Install Playwright browsers | |
| # `--filter` is required, not stylistic: @playwright/test is a dependency of | |
| # packages/inspector only, so a bare root `pnpm exec playwright` fails with | |
| # ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL / Command "playwright" not found. | |
| run: pnpm --filter @dawn-ai/inspector exec playwright install --with-deps chromium | |
| - name: Inspector browser verification | |
| # Boots the same .next/standalone artifact the vitest lane above uses (`Inspector | |
| # standalone e2e`, not the browser-install step immediately above), against a | |
| # seeded 1250-record store. `workers: 1` in playwright.config.ts is load-bearing: | |
| # the specs share one store and several mutate it. | |
| run: pnpm --filter @dawn-ai/inspector test:e2e | |
| - name: Upload Playwright traces | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: inspector-playwright-traces | |
| path: packages/inspector/test-results | |
| retention-days: 7 | |
| chart-validate: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| - name: Install kubeconform | |
| # This step extracts a tarball from the internet and `sudo install`s it | |
| # into /usr/local/bin — the same trust boundary as a GitHub Action, and | |
| # every action in this repo is SHA-pinned. So pin the artifact too. | |
| # | |
| # The checksum is a literal on purpose. Fetching the release CHECKSUMS | |
| # file over the same channel and trusting it verifies nothing: whoever | |
| # can serve a bad tarball can serve a matching checksum. That is the | |
| # mistake upstream kind.sh makes. This value was read from the v0.8.0 | |
| # release CHECKSUMS and confirmed against a locally computed sha256 of | |
| # the downloaded artifact. | |
| # | |
| # --fail so a 429/5xx is an error rather than an HTML error page written | |
| # into the tarball (which surfaced as "tar: Error is not recoverable"), | |
| # and --retry so a transient blip is retried instead of failing CI. | |
| run: | | |
| set -euo pipefail | |
| expected=9bc2bffbf71f261128533edaf912153948b7ff238f9a531ae6d34466ec287883 | |
| curl --fail --retry 5 --retry-all-errors --retry-delay 2 -sSL -o /tmp/kubeconform.tar.gz \ | |
| https://github.com/yannh/kubeconform/releases/download/v0.8.0/kubeconform-linux-amd64.tar.gz | |
| actual="$(sha256sum /tmp/kubeconform.tar.gz | cut -d' ' -f1)" | |
| if [ "$actual" != "$expected" ]; then | |
| echo "kubeconform-linux-amd64.tar.gz checksum mismatch" >&2 | |
| echo " expected $expected" >&2 | |
| echo " actual $actual" >&2 | |
| exit 1 | |
| fi | |
| tar -xzf /tmp/kubeconform.tar.gz -C /tmp kubeconform | |
| sudo install /tmp/kubeconform /usr/local/bin/kubeconform | |
| kubeconform -v | |
| - name: Helm lint (strict) — dawn-sandbox-infra | |
| run: helm lint --strict charts/dawn-sandbox-infra | |
| - name: Reaper unit test | |
| run: sh charts/dawn-sandbox-infra/test/reaper.test.sh | |
| - name: Render assertions — dawn-sandbox-infra | |
| run: sh charts/dawn-sandbox-infra/test/render.sh | |
| - name: kubeconform (default values) — dawn-sandbox-infra | |
| run: | | |
| helm template test charts/dawn-sandbox-infra \ | |
| | kubeconform -strict -summary -ignore-missing-schemas | |
| - name: kubeconform (restricted PSS, reaper disabled) — dawn-sandbox-infra | |
| run: | | |
| helm template test charts/dawn-sandbox-infra \ | |
| --set podSecurityStandard.enforce=restricted \ | |
| --set reaper.enabled=false \ | |
| | kubeconform -strict -summary -ignore-missing-schemas | |
| - name: Helm lint (strict) — dawn-app | |
| run: helm lint --strict charts/dawn-app | |
| - name: Render assertions — dawn-app | |
| run: sh charts/dawn-app/test/render.sh | |
| - name: kubeconform (default values) — dawn-app | |
| run: | | |
| helm template test charts/dawn-app --set image.repository=example/app \ | |
| | kubeconform -strict -summary -ignore-missing-schemas | |
| - name: kubeconform (full override) — dawn-app | |
| run: | | |
| helm template test charts/dawn-app \ | |
| --set image.repository=example/app \ | |
| --set ingress.enabled=true \ | |
| --set ingress.host=app.example.com \ | |
| --set autoscaling.enabled=true \ | |
| --set podDisruptionBudget.enabled=true \ | |
| | kubeconform -strict -summary -ignore-missing-schemas | |
| sandbox-k8s: | |
| needs: metadata_scope | |
| if: ${{ always() && (github.event_name != 'pull_request' || needs.metadata_scope.result != 'success' || needs.metadata_scope.outputs.metadata_only != 'true') }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 35 | |
| env: | |
| DAWN_TEST_K8S_CONTEXT: kind-dawn-k8s-canonical | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| with: | |
| version: v4.2.3 | |
| - name: Verify chart/provider permission parity | |
| env: | |
| DAWN_REQUIRE_HELM: "1" | |
| run: pnpm exec vitest --run --config test/k8s-compat/vitest.config.ts chart-rbac | |
| # helm/kind-action installs kind and kubectl with `curl -sSLo` and no | |
| # `--fail`, so a transient upstream 429/5xx writes the error page into | |
| # the checksum file and the step dies with "no properly formatted | |
| # checksum lines found". Priming RUNNER_TOOL_CACHE with verified | |
| # binaries makes the action's `[[ ! -x ... ]]` guards skip both | |
| # downloads entirely. | |
| # | |
| # The versions here must match the `version:` and `kubectl_version:` | |
| # inputs on the step below. If any of them ever drift, this step primes | |
| # a path the action does not read, the action downloads that tool as it | |
| # does today, and CI is degraded — not broken. | |
| - name: Prime kind tool cache | |
| run: scripts/prime-kind-cache.sh v0.32.0 v1.35.6 | |
| - name: Create kind cluster | |
| uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0 | |
| with: | |
| version: v0.32.0 | |
| kubectl_version: v1.35.6 | |
| node_image: kindest/node:v1.35.5@sha256:ce977ae6d65918d0b58a5f8b5e940429c2ce42fa3a5619ec2bbc60b949c0ac95 | |
| config: .github/kind/kind-calico.yaml | |
| cluster_name: dawn-k8s-canonical | |
| - name: Prepare verified Calico manifest | |
| env: | |
| CALICO_MANIFEST: ${{ runner.temp }}/dawn-calico.yaml | |
| run: pnpm exec tsx scripts/kubernetes-compat/workflow.ts prepare-calico --output "$CALICO_MANIFEST" | |
| - name: Install verified Calico | |
| env: | |
| CALICO_MANIFEST: ${{ runner.temp }}/dawn-calico.yaml | |
| run: | | |
| set -eu | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" apply --filename "$CALICO_MANIFEST" | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n kube-system rollout status daemonset/calico-node --timeout=180s | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" wait --for=condition=Ready nodes --all --timeout=180s | |
| - name: Run Kubernetes 1.35 compatibility harness | |
| run: pnpm verify:k8s:compat -- --target 1.35 --context "$DAWN_TEST_K8S_CONTEXT" | |
| - name: Upload Kubernetes compatibility artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: kubernetes-compat-canonical | |
| path: artifacts/testing/kubernetes-compat/** | |
| if-no-files-found: warn | |
| retention-days: 7 | |
| sandbox-k8s-e2e: | |
| # Full-arc smoke: a deployed Dawn app (built the user-facing way via | |
| # `dawn build`'s node target, run as `node .dawn/build/server.mjs`) drives | |
| # kubernetesSandbox to spawn a REAL sandbox Pod, then tears it down. Mirrors | |
| # sandbox-k8s's kind+Calico setup; adds a Verdaccio-published image build and | |
| # both Helm charts (cross-namespace: app in dawn-app, sandboxes in | |
| # dawn-sandboxes). Determinism comes from a baked aimock (no model key). | |
| needs: metadata_scope | |
| if: ${{ always() && (github.event_name != 'pull_request' || needs.metadata_scope.result != 'success' || needs.metadata_scope.outputs.metadata_only != 'true') }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| # Marks this as the gated full-arc e2e lane (distinct from sandbox-k8s). | |
| DAWN_TEST_SMOKE_E2E: "1" | |
| KIND_CLUSTER: dawn-smoke | |
| DAWN_TEST_K8S_CONTEXT: kind-dawn-smoke | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build | |
| # Full build so every published-to-Verdaccio @dawn-ai/* package has a | |
| # dist/ (publishWorkspace packs dist as-is). | |
| run: pnpm build | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| with: | |
| version: v4.2.3 | |
| - name: Verify chart/provider permission parity | |
| env: | |
| DAWN_REQUIRE_HELM: "1" | |
| run: pnpm exec vitest --run --config test/k8s-compat/vitest.config.ts chart-rbac | |
| # See the sandbox-k8s lane: primes the tool cache so the action skips its | |
| # own no-`--fail` kind and kubectl downloads. Keep these versions and | |
| # the `version:`/`kubectl_version:` inputs below in lockstep. | |
| - name: Prime kind tool cache | |
| run: scripts/prime-kind-cache.sh v0.32.0 v1.35.6 | |
| - name: Create kind cluster | |
| uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0 | |
| with: | |
| version: v0.32.0 | |
| kubectl_version: v1.35.6 | |
| node_image: kindest/node:v1.35.5@sha256:ce977ae6d65918d0b58a5f8b5e940429c2ce42fa3a5619ec2bbc60b949c0ac95 | |
| config: .github/kind/kind-calico.yaml | |
| cluster_name: dawn-smoke | |
| - name: Prepare verified Calico manifest | |
| env: | |
| CALICO_MANIFEST: ${{ runner.temp }}/dawn-calico.yaml | |
| run: pnpm exec tsx scripts/kubernetes-compat/workflow.ts prepare-calico --output "$CALICO_MANIFEST" | |
| - name: Install verified Calico | |
| env: | |
| CALICO_MANIFEST: ${{ runner.temp }}/dawn-calico.yaml | |
| run: | | |
| set -eu | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" apply --filename "$CALICO_MANIFEST" | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n kube-system rollout status daemonset/calico-node --timeout=180s | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" wait --for=condition=Ready nodes --all --timeout=180s | |
| - name: Preload sandbox workload image into kind | |
| # Pull through the node's CRI so containerd records the canonical digest | |
| # reference that the sandbox Pod uses during the packaged-app proof. | |
| run: | | |
| SANDBOX_IMAGE="$( | |
| pnpm exec tsx -e 'import { loadCompatibilityPolicy } from "./scripts/kubernetes-compat/policy.ts"; loadCompatibilityPolicy().then((policy) => process.stdout.write(policy.images.sandboxWorkload))' | |
| )" | |
| docker exec "${KIND_CLUSTER}-control-plane" crictl pull "$SANDBOX_IMAGE" | |
| docker exec "${KIND_CLUSTER}-control-plane" crictl inspecti "$SANDBOX_IMAGE" >/dev/null | |
| - name: Build and load smoke app image (Verdaccio) | |
| # Start the local registry (bound 0.0.0.0 so the in-image npm install can | |
| # reach it via host.docker.internal), publish the workspace, build the app | |
| # image the user-facing way (build-image.sh → node-target Dockerfile), then | |
| # load it into kind. The registry only needs to live for this step. | |
| run: | | |
| set -eu | |
| URLFILE="$(mktemp)" | |
| pnpm exec tsx test/k8s-smoke/serve-registry.ts "$URLFILE" & | |
| REG_PID=$! | |
| for _ in $(seq 1 180); do | |
| [ -s "$URLFILE" ] && break | |
| kill -0 "$REG_PID" 2>/dev/null || { echo "serve-registry exited before publishing"; exit 1; } | |
| sleep 1 | |
| done | |
| [ -s "$URLFILE" ] || { echo "registry URL never became ready"; kill "$REG_PID" 2>/dev/null || true; exit 1; } | |
| REG_URL="$(cat "$URLFILE")" | |
| echo "registry ready at $REG_URL" | |
| sh test/k8s-smoke/build-image.sh k8s "$REG_URL" | |
| kill "$REG_PID" 2>/dev/null || true | |
| kind load docker-image dawn-smoke-app:k8s --name "$KIND_CLUSTER" | |
| - name: Build and load aimock image | |
| run: | | |
| docker build -t dawn-smoke-aimock:latest -f test/k8s-smoke/aimock/Dockerfile test/k8s-smoke | |
| kind load docker-image dawn-smoke-aimock:latest --name "$KIND_CLUSTER" | |
| - name: Create app namespace | |
| run: kubectl --context "$DAWN_TEST_K8S_CONTEXT" create namespace dawn-app | |
| - name: Install sandbox-infra chart | |
| run: | | |
| helm --kube-context "$DAWN_TEST_K8S_CONTEXT" install dawn-sandbox-infra charts/dawn-sandbox-infra \ | |
| -n dawn-app \ | |
| -f test/k8s-smoke/values-sandbox-infra.yaml --wait | |
| - name: Deploy aimock | |
| run: | | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" apply -f test/k8s-smoke/aimock.k8s.yaml | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-app rollout status deploy/aimock --timeout=120s | |
| - name: Install dawn-app chart | |
| run: | | |
| helm --kube-context "$DAWN_TEST_K8S_CONTEXT" install dawn-app charts/dawn-app \ | |
| -n dawn-app \ | |
| -f test/k8s-smoke/values-dawn-app.yaml --wait | |
| - name: Run full-arc assertions | |
| run: sh test/k8s-smoke/assert-k8s.sh | |
| - name: Diagnostics + cleanup | |
| if: always() | |
| run: | | |
| echo "----- app -----" | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-app get pods,svc -o wide || true | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-app logs deploy/dawn-app --tail=120 || true | |
| echo "----- aimock -----" | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-app logs -l app.kubernetes.io/name=aimock --tail=120 --all-containers || true | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-app describe pods -l app.kubernetes.io/name=aimock || true | |
| echo "----- sandboxes -----" | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-sandboxes get pods,pvc,networkpolicy -o wide || true | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" -n dawn-sandboxes describe pods -l app.kubernetes.io/managed-by=dawn || true | |
| echo "----- teardown -----" | |
| helm --kube-context "$DAWN_TEST_K8S_CONTEXT" uninstall dawn-app -n dawn-app || true | |
| helm --kube-context "$DAWN_TEST_K8S_CONTEXT" uninstall dawn-sandbox-infra -n dawn-app || true | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" delete namespace dawn-app --ignore-not-found --wait=false || true | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" delete namespace dawn-sandboxes --ignore-not-found --wait=false || true | |
| sandbox-docker-e2e: | |
| # Full-arc smoke (docker-out-of-docker): a CONTAINERIZED Dawn app — built the | |
| # user-facing way (`dawn build`'s node target, run as `node | |
| # .dawn/build/server.mjs`) with the host Docker socket bind-mounted — drives | |
| # dockerSandbox to spawn a REAL, isolated SIBLING sandbox container on the | |
| # host daemon, then tears it down. Mirrors sandbox-docker's host-Docker setup; | |
| # adds a Verdaccio-published image build (same mechanism as sandbox-k8s-e2e). | |
| # Determinism comes from a baked aimock (no model key). | |
| needs: metadata_scope | |
| if: ${{ always() && (github.event_name != 'pull_request' || needs.metadata_scope.result != 'success' || needs.metadata_scope.outputs.metadata_only != 'true') }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| # Marks this as the gated full-arc e2e lane (distinct from sandbox-docker). | |
| DAWN_TEST_SMOKE_E2E: "1" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 | |
| with: | |
| version: 10.33.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| # Node 24 — Dawn's floor is the active LTS line (node:sqlite | |
| # unflagged, npm >= 11 bundled). Matches release.yml and engines. | |
| node-version: 24.17.0 | |
| cache: pnpm | |
| - name: Install | |
| run: pnpm install --frozen-lockfile | |
| - name: Build | |
| # Full build so every published-to-Verdaccio @dawn-ai/* package has a | |
| # dist/ (publishWorkspace packs dist as-is). | |
| run: pnpm build | |
| - name: Pull sandbox workload image | |
| # Pull the digest-pinned policy image up front so sibling startup does | |
| # not wait on an external registry. | |
| run: | | |
| SANDBOX_IMAGE="$( | |
| pnpm exec tsx -e 'import { loadCompatibilityPolicy } from "./scripts/kubernetes-compat/policy.ts"; loadCompatibilityPolicy().then((policy) => process.stdout.write(policy.images.sandboxWorkload))' | |
| )" | |
| docker pull "$SANDBOX_IMAGE" | |
| - name: Build app + aimock images (Verdaccio) | |
| # Start the local registry (bound 0.0.0.0 so the in-image npm install can | |
| # reach it via host.docker.internal), publish the workspace, then build | |
| # the app image the user-facing way (build-image.sh docker → node-target | |
| # Dockerfile + static docker CLI layer) and the baked aimock image. The | |
| # registry only needs to live for the app build. | |
| run: | | |
| set -eu | |
| URLFILE="$(mktemp)" | |
| pnpm exec tsx test/k8s-smoke/serve-registry.ts "$URLFILE" & | |
| REG_PID=$! | |
| for _ in $(seq 1 180); do | |
| [ -s "$URLFILE" ] && break | |
| kill -0 "$REG_PID" 2>/dev/null || { echo "serve-registry exited before publishing"; exit 1; } | |
| sleep 1 | |
| done | |
| [ -s "$URLFILE" ] || { echo "registry URL never became ready"; kill "$REG_PID" 2>/dev/null || true; exit 1; } | |
| REG_URL="$(cat "$URLFILE")" | |
| echo "registry ready at $REG_URL" | |
| sh test/k8s-smoke/build-image.sh docker "$REG_URL" | |
| docker build -t dawn-smoke-aimock:latest -f test/k8s-smoke/aimock/Dockerfile test/k8s-smoke | |
| kill "$REG_PID" 2>/dev/null || true | |
| - name: Run full-arc assertions (DooD) | |
| run: sh test/k8s-smoke/assert-docker.sh | |
| - name: Diagnostics + cleanup | |
| if: always() | |
| run: | | |
| echo "----- containers -----" | |
| docker ps -a || true | |
| echo "----- app logs -----" | |
| docker logs dawn-smoke-app --tail=120 || true | |
| echo "----- teardown -----" | |
| docker rm -f dawn-smoke-app dawn-smoke-aimock || true | |
| for c in $(docker ps -aq --filter name=dawn-sbx-); do docker rm -f "$c" || true; done | |
| for v in $(docker volume ls -q --filter name=dawn-sbx-); do docker volume rm "$v" || true; done | |
| docker network rm dawn-smoke-net || true | |
| chart-apply-smoke: | |
| needs: metadata_scope | |
| if: ${{ always() && (github.event_name != 'pull_request' || needs.metadata_scope.result != 'success' || needs.metadata_scope.outputs.metadata_only != 'true') }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| DAWN_TEST_K8S_CONTEXT: kind-dawn-chart-apply | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| with: | |
| version: v4.2.3 | |
| # See the sandbox-k8s lane: primes the tool cache so the action skips its | |
| # own no-`--fail` kind and kubectl downloads. Keep these versions and | |
| # the `version:`/`kubectl_version:` inputs below in lockstep. | |
| - name: Prime kind tool cache | |
| run: scripts/prime-kind-cache.sh v0.32.0 v1.35.6 | |
| - name: Create kind cluster | |
| uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0 | |
| with: | |
| version: v0.32.0 | |
| kubectl_version: v1.35.6 | |
| node_image: kindest/node:v1.35.5@sha256:ce977ae6d65918d0b58a5f8b5e940429c2ce42fa3a5619ec2bbc60b949c0ac95 | |
| cluster_name: dawn-chart-apply | |
| - name: Install dawn-app (placeholder image) and verify it serves | |
| # nginx-unprivileged runs as non-root (UID 101, port 8080), so it satisfies | |
| # the chart's hardened runAsNonRoot default — which is exactly what a real | |
| # langgraph app image must also do. A root image (e.g. traefik/whoami) would | |
| # be rejected by the kubelet, so this doubles as a proof of the non-root default. | |
| run: | | |
| set -eu | |
| PLACEHOLDER_IMAGE="$(jq -er '.images.placeholderApp' .github/kubernetes-compatibility.json)" | |
| REACHABILITY_IMAGE="$(jq -er '.images.reachabilityProbe' .github/kubernetes-compatibility.json)" | |
| PLACEHOLDER_WITH_TAG="${PLACEHOLDER_IMAGE%@sha256:*}" | |
| PLACEHOLDER_REPOSITORY="${PLACEHOLDER_WITH_TAG%:*}" | |
| PLACEHOLDER_DIGEST="sha256:${PLACEHOLDER_IMAGE##*@sha256:}" | |
| printf '%s\n' "$PLACEHOLDER_DIGEST" | grep -Eq '^sha256:[0-9a-f]{64}$' | |
| printf '%s\n' "$REACHABILITY_IMAGE" | grep -Eq '@sha256:[0-9a-f]{64}$' | |
| helm --kube-context "$DAWN_TEST_K8S_CONTEXT" install dawn-app charts/dawn-app \ | |
| --set-string image.repository="$PLACEHOLDER_REPOSITORY" \ | |
| --set-string image.digest="$PLACEHOLDER_DIGEST" \ | |
| --set containerPort=8080 --set healthPath=/ \ | |
| --wait --timeout 3m | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" rollout status deploy/dawn-app --timeout=120s | |
| kubectl --context "$DAWN_TEST_K8S_CONTEXT" run curl --image="$REACHABILITY_IMAGE" --restart=Never --rm -i --quiet -- \ | |
| curl -sf http://dawn-app.default.svc.cluster.local/ >/dev/null && echo "app served OK" |