CI #1183
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: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "17 3 * * 2" | |
| push: | |
| branches: ["master"] | |
| pull_request: | |
| branches: ["master"] | |
| permissions: read-all | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| backend-sqlite: | |
| name: Backend (SQLite) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build frontend (security-regression assertions need dist, issue #290) | |
| run: cd frontend && bun run build | |
| - name: Build terraform-config-inspect (registry install e2e needs the same binary prod bakes in, issue #720) | |
| run: CGO_ENABLED=0 GOBIN=$GITHUB_WORKSPACE/backend/bin go install github.com/hashicorp/terraform-config-inspect@v0.0.0-20260709150029-2fb54c236733 | |
| - name: Allow binding loopback 443 for the genuine provider-mirror install (best effort; the suite skips that leg otherwise) | |
| run: sudo sysctl -w net.ipv4.ip_unprivileged_port_start=443 || true | |
| - name: Run backend tests (SQLite) | |
| env: | |
| # Raises the tofu release-lookup ceiling from 60/hr (per shared | |
| # runner IP) to 5000/hr when both matrix jobs run e2e downloads. | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Keep pull requests fast and deterministic; the scheduled run | |
| # expands the independent lifecycle model's seed corpus. | |
| TERRENCE_PROPERTY_CASES: ${{ github.event_name == 'schedule' && '2000' || '256' }} | |
| # The backend package script serializes Bun workers because the test | |
| # suite shares its Elysia app and SQLite connection across files. | |
| run: cd backend && bun run test | |
| - name: Prove critical guard tests detect mutations | |
| run: bun backend/scripts/check-guard-mutations.ts | |
| backend-postgres: | |
| name: Backend (Postgres) | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:18-alpine@sha256:d3e1620b530c944afa6e887d22eb899824da68e19c52024bf98f5220c88a65b2 | |
| env: | |
| POSTGRES_USER: terrence | |
| POSTGRES_PASSWORD: terrence | |
| POSTGRES_DB: terrence_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build frontend (security-regression assertions need dist, issue #290) | |
| run: cd frontend && bun run build | |
| - name: Build terraform-config-inspect (registry install e2e needs the same binary prod bakes in, issue #720) | |
| run: CGO_ENABLED=0 GOBIN=$GITHUB_WORKSPACE/backend/bin go install github.com/hashicorp/terraform-config-inspect@v0.0.0-20260709150029-2fb54c236733 | |
| - name: Allow binding loopback 443 for the genuine provider-mirror install (best effort; the suite skips that leg otherwise) | |
| run: sudo sysctl -w net.ipv4.ip_unprivileged_port_start=443 || true | |
| - name: Run backend tests (Postgres) | |
| env: | |
| DATABASE_URL: postgres://terrence:terrence@localhost:5432/terrence_test | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # The backend package script serializes Bun workers because the test | |
| # suite shares its Elysia app and SQLite connection across files. | |
| run: cd backend && bun run test | |
| - name: Run SQLite to PostgreSQL migration and export contracts | |
| env: | |
| PG_TEST_ADMIN_URL: postgres://terrence:terrence@localhost:5432/terrence_test | |
| # Keep DATABASE_URL absent: the application must start on SQLite so | |
| # the actual migration path runs, not the already-PostgreSQL guard. | |
| run: cd backend && bun test tests/api/db-migration.test.ts tests/api/db-export.test.ts --max-concurrency=1 --no-orphans | |
| ha-mixed-version: | |
| name: HA mixed-version smoke | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:18-alpine@sha256:d3e1620b530c944afa6e887d22eb899824da68e19c52024bf98f5220c88a65b2 | |
| env: | |
| POSTGRES_USER: terrence | |
| POSTGRES_PASSWORD: terrence | |
| POSTGRES_DB: terrence_mixed | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Run protocol-1/protocol-2 HA compatibility smoke | |
| env: | |
| DATABASE_URL: postgres://terrence:terrence@localhost:5432/terrence_mixed | |
| run: bash scripts/ha-mixed-version-smoke.sh | |
| frontend: | |
| name: Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Run frontend tests | |
| env: | |
| NO_COLOR: "1" | |
| run: cd frontend && bun run test | |
| - name: Frontend build | |
| run: cd frontend && bun run build | |
| checks: | |
| name: Checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Verify Bun runtime version | |
| run: bun run check:bun-version | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Check formatting | |
| run: bun run format:check | |
| - name: Check lockfile deduplication | |
| run: bun run deps:dedupe:check | |
| - name: Dependency vulnerability audit (issue #285) | |
| run: bun run deps:audit | |
| - name: Check dependency release-age policy | |
| run: | | |
| bun - <<'NODE' | |
| const fs = require("fs"); | |
| const renovate = JSON.parse(fs.readFileSync("renovate.json", "utf8")); | |
| const lines = fs.readFileSync("bunfig.toml", "utf8").split(/\r?\n/); | |
| const installStart = lines.findIndex((line) => line.trim() === "[install]"); | |
| const installEnd = lines.findIndex((line, index) => index > installStart && /^\s*\[/.test(line)); | |
| const installLines = lines.slice(installStart + 1, installEnd === -1 ? lines.length : installEnd); | |
| const ageAssignments = installLines.filter((line) => /^\s*minimumReleaseAge\s*=/.test(line)); | |
| const activeAge = ageAssignments[0]?.match(/^\s*minimumReleaseAge\s*=\s*(\d+)\s*(?:#.*)?$/)?.[1]; | |
| if (renovate.minimumReleaseAge !== "3 days" || renovate.lockFileMaintenance?.enabled !== false || ageAssignments.length !== 1 || activeAge !== "259200") process.exit(1); | |
| console.log("Dependency release-age policy is enforced; Renovate lock maintenance is disabled because Bun enforces the same guard."); | |
| NODE | |
| - name: Verify controlled supply-chain policy (issue #787) | |
| run: bun run check:supply-chain | |
| - name: Verify rolling-upgrade schema compatibility | |
| run: bun run check:schema-compat | |
| - name: Generate dependency manifest, SBOM, and change summary | |
| env: | |
| BASE_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }} | |
| run: | | |
| set -euo pipefail | |
| args=() | |
| if [[ -n "${BASE_REF:-}" ]] && git cat-file -e "${BASE_REF}^{commit}" 2>/dev/null; then | |
| args+=(--base-ref "$BASE_REF") | |
| fi | |
| bun scripts/supply-chain-manifest.ts \ | |
| --output dependency-manifest.json \ | |
| --sbom-output dependency-sbom.spdx.json \ | |
| --summary-output dependency-change-summary.md \ | |
| "${args[@]}" | |
| - name: Upload dependency supply-chain evidence | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: dependency-supply-chain | |
| path: | | |
| dependency-manifest.json | |
| dependency-sbom.spdx.json | |
| dependency-change-summary.md | |
| supply-chain/dependency-exceptions.json | |
| retention-days: 90 | |
| - name: Check canonical brand assets | |
| run: bun run --cwd frontend scripts/brand-assets.tsx --check | |
| - name: Typecheck | |
| run: bun run typecheck | |
| - name: Lint (baseline report) | |
| run: bun run lint | |
| continue-on-error: true | |
| - name: Lint debt budget | |
| run: bun run lint:budget | |
| - name: Knip | |
| run: bun run knip | |
| - name: Security endpoint coverage (todo 143) | |
| run: bun test backend/tests/unit/endpoint-policy-compliance.test.ts | |
| - name: Secret fingerprint check (todo 116) | |
| run: bun test backend/tests/worker/env-isolation.test.ts | |
| - name: Verify operational runbook in disposable storage (issue #757) | |
| run: bun backend/scripts/verify-operations-docs.ts | |
| - name: Run documented upgrade fixture (issue #754) | |
| run: bun test backend/tests/db/upgrade-invariants.test.ts --max-concurrency=1 --no-orphans | |
| # Coverage gate (issue #380): runs the backend suite under coverage and | |
| # uploads the report. NOT yet enforcing (--fail) while legacy exposure | |
| # exists; ratchet the threshold in backend/scripts/coverage-report.ts as | |
| # exposure is closed out. | |
| coverage: | |
| name: Backend coverage report | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build frontend (security-regression assertions need dist, issue #290) | |
| run: cd frontend && bun run build | |
| - name: Backend coverage report | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: cd backend && bun run coverage --json > /tmp/coverage.json | |
| - name: Upload coverage report | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: backend-coverage | |
| path: /tmp/coverage.json | |
| retention-days: 30 | |
| # Supply-chain / artifact verification (todos 828, 889, 800). | |
| build-verification: | |
| name: Build verification | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Frontend build (reproducible) | |
| run: cd frontend && bun run build | |
| - name: Docker full build and runtime smoke check (todo 828) | |
| run: | | |
| docker build -f Dockerfile -t terrence:ci . > /tmp/docker-build.log 2>&1 || (cat /tmp/docker-build.log; exit 1) | |
| docker run --rm terrence:ci /usr/bin/bun --version | |
| # Verify non-root guarantee (issue #379) | |
| user=$(docker inspect terrence:ci --format '{{.Config.User}}' 2>/dev/null || true); echo "image USER=$user"; case "$user" in nonroot*|65532*) ;; *) echo "FAIL: image USER must be nonroot/65532" >&2; exit 1;; esac | |
| # Deep-verify with the tracked script: image USER, live process | |
| # uid/gid, storage ownership and writability. The probe container is | |
| # always removed afterwards, even when verification fails. | |
| docker run -d --name terrence-ci-verify terrence:ci > /dev/null | |
| cleanup_verify() { docker rm -f terrence-ci-verify > /dev/null 2>&1 || true; } | |
| trap cleanup_verify EXIT | |
| for attempt in $(seq 1 30); do | |
| health=$(docker inspect terrence-ci-verify --format '{{.State.Health.Status}}' 2>/dev/null || true) | |
| if [ "$health" = "healthy" ]; then break; fi | |
| if [ "$attempt" -lt 30 ]; then sleep 5; fi | |
| done | |
| # Re-inspect after the polling loop: only a confirmed healthy | |
| # container may be passed to the runtime-user verification script. | |
| health=$(docker inspect terrence-ci-verify --format '{{.State.Health.Status}}' 2>/dev/null || true) | |
| if [ "$health" != "healthy" ]; then | |
| echo "FAIL: verification container is not healthy (status=${health:-unknown})" >&2 | |
| exit 1 | |
| fi | |
| bash backend/scripts/verify-container-user.sh terrence-ci-verify | |
| trap - EXIT | |
| cleanup_verify | |
| echo "Docker image build and runtime smoke check OK" | |
| - name: Bundle size budget (todo 800) | |
| run: bun run check:bundle-size | |
| browser-tests: | |
| name: Browser & E2E Tests (Bun.WebView) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build static frontend | |
| run: cd frontend && bun run build | |
| - name: Run browser E2E & accessibility suite (Bun.WebView) | |
| run: bun run test:profile -- browser | |
| provider-compatibility: | |
| name: Provider and CLI (${{ matrix.engine }}, ${{ matrix.tier }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| engine: [terraform, tofu] | |
| tier: ${{ github.event_name == 'schedule' && fromJSON('["canary"]') || fromJSON('["floor", "current"]') }} | |
| env: | |
| TERRENCE_E2E_CLI: ${{ matrix.engine }} | |
| TERRENCE_E2E_TIER: ${{ matrix.tier }} | |
| TERRENCE_E2E_SEED: eng21-${{ matrix.engine }}-${{ matrix.tier }} | |
| TERRENCE_E2E_RESULTS_DIR: ${{ github.workspace }}/provider-lifecycle-results | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Set up Terraform for provider schema verification | |
| uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1 | |
| with: | |
| terraform_version: v1.16.3 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Verify the tracked hashicorp/tfe provider catalog | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| provider_version="$(bun -e 'const fs=require("fs"); const s=JSON.parse(fs.readFileSync("backend/src/data/provider_surface.json", "utf8")); const m=/v([0-9]+[.][0-9]+[.][0-9]+)/.exec(s.provider); if (!m) process.exit(1); process.stdout.write(m[1]);')" | |
| TFE_PROVIDER_VERSION="$provider_version" TERRAFORM_BIN=terraform bun backend/scripts/refresh-provider-surface.ts | |
| git diff --exit-code -- backend/src/data/provider_surface.json backend/tests/e2e/provider_surface.json | |
| - name: Build frontend for API contract fixtures | |
| run: cd frontend && bun run build | |
| - name: Run focused CLI and API compatibility contracts | |
| run: | | |
| set -euo pipefail | |
| cd backend | |
| bun test --bail=5 --max-concurrency=1 --no-orphans \ | |
| tests/api/e2e_full_flow.test.ts \ | |
| tests/api/oauth-login-flow.test.ts | |
| cd ../frontend | |
| bun test --bail=5 --max-concurrency=1 --no-orphans \ | |
| tests/terraform-cli-route-compat.test.tsx | |
| - name: Cache verified CLI binaries and provider packages | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 | |
| with: | |
| path: | | |
| backend/storage/binaries | |
| backend/storage/e2e-plugin-cache | |
| key: ${{ runner.os }}-${{ runner.arch }}-cli-${{ matrix.engine }}-${{ matrix.tier }}-${{ hashFiles('backend/tests/e2e/cli_matrix.json', 'backend/tests/e2e/provider_surface.json') }} | |
| - name: Run pinned provider and remote CLI journeys | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: bun run test:profile -- sqlite-cli | |
| - name: Build the production Landlock helper | |
| if: matrix.engine == 'terraform' && matrix.tier == 'current' | |
| run: backend/bin/build-landlock-runner.sh | |
| - name: Run provider E2E with required production sandboxing | |
| if: matrix.engine == 'terraform' && matrix.tier == 'current' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TERRENCE_E2E_CLI: terraform | |
| TERRENCE_E2E_SECURITY_PROFILE: required | |
| run: bun run test:profile -- sandbox | |
| - name: Upload successful provider lifecycle evidence | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: provider-lifecycle-results-${{ matrix.engine }}-${{ matrix.tier }} | |
| path: provider-lifecycle-results/* | |
| if-no-files-found: ignore | |
| retention-days: 30 | |
| provider-canary-review: | |
| name: Open provider canary review item | |
| needs: provider-compatibility | |
| if: always() && github.event_name == 'schedule' && needs.provider-compatibility.result == 'failure' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| # Deliberately no checkout: this write-capable job must not execute repository code. | |
| - name: Open a review item for a failed canary | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| title="[CLI canary] provider compatibility failure" | |
| existing="$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --search "$title in:title" --json number --jq '.[0].number // empty')" | |
| if [ -z "$existing" ]; then | |
| cat > /tmp/canary-issue.md <<EOF | |
| The scheduled provider/CLI canary matrix failed. Review the [CI run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) and its redacted CLI diagnostic artifacts to identify the failing engine. | |
| The supported floor and current pins have not changed. Promote a new version only after the complete compatibility matrix passes. | |
| EOF | |
| gh issue create --repo "$GITHUB_REPOSITORY" --title "$title" --body-file /tmp/canary-issue.md | |
| fi | |
| cli-compatibility-report: | |
| name: Publish tested CLI matrix artifact | |
| needs: provider-compatibility | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| - name: Download successful matrix evidence | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: provider-lifecycle-results-* | |
| merge-multiple: true | |
| path: provider-lifecycle-results | |
| - name: Generate the tested compatibility page | |
| run: bun backend/scripts/report-cli-compatibility.ts provider-lifecycle-results backend/docs/cli-compatibility-results.md | |
| - name: Upload the tested compatibility page and evidence | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: cli-compatibility-report | |
| path: | | |
| backend/docs/cli-compatibility-results.md | |
| provider-lifecycle-results/*-lifecycle.json | |
| retention-days: 90 | |
| publish-nightly: | |
| name: Publish nightly image | |
| needs: | |
| - backend-sqlite | |
| - backend-postgres | |
| - frontend | |
| - checks | |
| - coverage | |
| - build-verification | |
| - browser-tests | |
| - provider-compatibility | |
| - cli-compatibility-report | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| actions: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 2 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.4.2 | |
| no-cache: true | |
| - name: Determine build version | |
| id: version | |
| run: | | |
| pkg_version=$(bun -e "console.log(String(require('./package.json').version ?? '0.0.0'))" 2>/dev/null || echo "0.0.0") | |
| echo "version=${pkg_version}" >> "$GITHUB_OUTPUT" | |
| echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ghcr.io/${{ github.repository }} | |
| tags: | | |
| type=raw,value=nightly | |
| type=sha,format=short | |
| - name: Download tested CLI/provider evidence | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: cli-compatibility-report | |
| path: release-evidence | |
| - name: Build and push Docker image | |
| id: build | |
| uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| push: true | |
| build-args: | | |
| BUILD_VERSION=${{ steps.version.outputs.version }} | |
| BUILD_SHA=${{ steps.version.outputs.sha_short }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: mode=max | |
| sbom: true | |
| outputs: type=image,name=ghcr.io/${{ github.repository }},push=true | |
| - name: Write redacted build manifest | |
| run: | | |
| set -euo pipefail | |
| args=() | |
| if git rev-parse HEAD^ >/dev/null 2>&1; then args+=(--base-ref HEAD^); fi | |
| bun scripts/supply-chain-manifest.ts \ | |
| --output dependency-manifest.json \ | |
| --sbom-output dependency-sbom.spdx.json \ | |
| --summary-output dependency-change-summary.md \ | |
| "${args[@]}" | |
| bun run check:supply-chain | |
| bun backend/scripts/build-manifest.ts \ | |
| --output build-manifest.json \ | |
| --version "${{ steps.version.outputs.version }}" \ | |
| --commit "$(git rev-parse HEAD)" \ | |
| --image "ghcr.io/${{ github.repository }}:nightly" \ | |
| --digest "${{ steps.build.outputs.digest }}" \ | |
| --dependency-manifest dependency-manifest.json \ | |
| --dependency-sbom dependency-sbom.spdx.json \ | |
| --dependency-summary dependency-change-summary.md \ | |
| --dependency-exceptions supply-chain/dependency-exceptions.json \ | |
| --evidence-dir release-evidence | |
| - name: Upload redacted build manifest | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: build-manifest-nightly | |
| path: | | |
| build-manifest.json | |
| dependency-manifest.json | |
| dependency-sbom.spdx.json | |
| dependency-change-summary.md | |
| supply-chain/dependency-exceptions.json | |
| retention-days: 365 |