Skip to content

Fix re-login hang on auth page after logout #30945

Fix re-login hang on auth page after logout

Fix re-login hang on auth page after logout #30945

Workflow file for this run

name: CI
on:
push:
branches:
- main
- ci-bisect
- ci-bisect-**
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
checks: write
contents: read
id-token: write
# Lets the warm-test-images step pull the private GHCR mirror packages.
packages: read
pull-requests: write
jobs:
change-check:
name: Check which packages changed
runs-on: ubuntu-latest
outputs:
boxel: ${{ steps.filter.outputs.boxel }}
ai-bot: ${{ steps.filter.outputs.ai-bot }}
bot-runner: ${{ steps.filter.outputs.bot-runner }}
eslint-plugin-boxel: ${{ steps.filter.outputs.eslint-plugin-boxel }}
eslint-plugin-cardstack-host: ${{ steps.filter.outputs.eslint-plugin-cardstack-host }}
postgres-migrations: ${{ steps.filter.outputs.postgres-migrations }}
boxel-icons: ${{ steps.filter.outputs.boxel-icons }}
boxel-ui: ${{ steps.filter.outputs.boxel-ui }}
matrix: ${{ steps.filter.outputs.matrix }}
realm-server: ${{ steps.filter.outputs.realm-server }}
vscode-boxel-tools: ${{ steps.filter.outputs.vscode-boxel-tools }}
boxel-cli: ${{ steps.filter.outputs.boxel-cli }}
bench-amd: ${{ steps.filter.outputs.bench-amd }}
bench-realm: ${{ steps.filter.outputs.bench-realm }}
# Force all tests to run when on ci-bisect* branches
run_all: ${{ steps.force-run-all.outputs.run_all }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
with:
filters: |
shared: &shared
- '.github/workflows/ci.yaml'
- 'packages/runtime-common/**'
- 'package.json'
- 'pnpm-lock.yaml'
# CI boot path. Each gated suite runs `./.github/actions/init`
# (which calls `jdx/mise-action`, sourcing `.mise.toml` for tool
# versions) and then `mise run test-services:*` (which sources
# every script under mise-tasks/, with dev-log-tee.sh as a
# runtime dep). A breaking change to any of these can take down
# all the suites without matching a per-package filter — the
# exact failure mode that hid PR #4671.
- '.mise.toml'
- '.github/actions/**'
- 'mise-tasks/**'
- 'packages/observability/scripts/**'
boxel:
- *shared
- '.github/workflows/build-host.yml'
- '.github/workflows/deploy-host.yml'
- '.github/workflows/manual-deploy.yml'
- 'packages/ai-bot/**'
- 'packages/bot-runner/**'
- 'packages/base/**'
- 'packages/boxel-icons/**'
- 'packages/boxel-ui/**'
- 'packages/host/**'
- 'packages/realm-server/**'
- 'packages/test-realm-cards/**'
ai-bot:
- *shared
- '.github/workflows/pr-ai-bot.yml'
- 'packages/ai-bot/**'
- 'packages/billing/**'
- 'packages/postgres/**'
bot-runner:
- *shared
- 'packages/bot-runner/**'
- 'packages/postgres/**'
eslint-plugin-boxel:
- *shared
- 'packages/eslint-plugin-boxel/**'
eslint-plugin-cardstack-host:
- *shared
- 'packages/eslint-plugin-cardstack-host/**'
postgres-migrations:
- 'packages/postgres/migrations/**'
- 'packages/postgres/scripts/determine-changed-migrations.sh'
boxel-icons:
- *shared
- 'packages/boxel-icons/**'
boxel-ui:
- *shared
- 'packages/boxel-icons/**'
- 'packages/boxel-ui/**'
matrix:
- *shared
- 'packages/base/**'
- 'packages/boxel-icons/**'
- 'packages/boxel-ui/**'
- 'packages/host/**'
- 'packages/matrix/**'
- 'packages/realm-server/**'
- 'packages/test-realm-cards/**'
realm-server:
- *shared
- 'packages/billing/**'
- 'packages/boxel-icons/**'
- 'packages/boxel-ui/**'
- 'packages/host/**'
- 'packages/eslint-plugin-boxel/**'
- 'packages/postgres/**'
- 'packages/realm-server/**'
- 'packages/test-realm-cards/**'
vscode-boxel-tools:
- *shared
- 'packages/vscode-boxel-tools/**'
boxel-cli:
- *shared
- 'packages/boxel-cli/**'
bench-amd:
# The AMD transpiler is a runtime-common module with no
# cross-workspace deps that affect its wall-time, so the
# bench only needs to fire for runtime-common edits and
# the committed bench fixtures.
- 'packages/runtime-common/**'
- 'bench-fixtures/runtime-common/amd-transpile/**'
bench-realm:
# HTTP GET + search regression bench. Self-contained — the
# bench's source-realm snapshot lives under
# packages/realm-server/scripts/bench-realm/fixtures/, so
# software-factory changes can't move the bench medians.
# The packages that *can* affect the medians are the ones
# the bench's wire path actually exercises:
# runtime-common (definition lookup, query engine, file
# serializer), realm-server itself, postgres (schema
# migrations + the pg adapter the bench writes through),
# host (FastBoot prerender), the base realm, and the
# harness that spins up the ephemeral stack.
- *shared
- 'packages/base/**'
- 'packages/host/**'
- 'packages/postgres/**'
- 'packages/realm-server/**'
- 'packages/realm-test-harness/**'
- name: Force run all jobs on ci-bisect branches
id: force-run-all
shell: bash
run: |
echo "run_all=${{ startsWith(github.ref, 'refs/heads/ci-bisect') || startsWith(github.ref, 'refs/heads/ci-bisect-') || startsWith(github.head_ref || '', 'ci-bisect') }}" >> "$GITHUB_OUTPUT"
test-web-assets:
name: Build test web assets
needs: change-check
if: needs.change-check.outputs.boxel == 'true' || needs.change-check.outputs.boxel-ui == 'true' || needs.change-check.outputs.matrix == 'true' || needs.change-check.outputs.realm-server == 'true' || needs.change-check.outputs.vscode-boxel-tools == 'true' || needs.change-check.outputs.boxel-cli == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
uses: ./.github/workflows/test-web-assets.yaml
with:
caller: ci
concurrency:
group: ci-test-web-assets-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
ai-bot-test:
name: AI bot Tests
needs: change-check
if: needs.change-check.outputs.ai-bot == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: postgres
concurrency:
group: ai-bot-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: AI Bot test suite
run: pnpm test
working-directory: packages/ai-bot
bot-runner-test:
name: Bot Runner Tests
needs: change-check
if: needs.change-check.outputs.bot-runner == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: bot-runner-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Bot Runner test suite
run: pnpm test
working-directory: packages/bot-runner
eslint-plugin-boxel-test:
name: ESLint Plugin Boxel Tests
needs: change-check
if: needs.change-check.outputs.eslint-plugin-boxel == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: eslint-plugin-boxel-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: ESLint Plugin Boxel test suite
run: pnpm test
working-directory: packages/eslint-plugin-boxel
- name: Check generated files are up to date
working-directory: packages/eslint-plugin-boxel
run: |
pnpm run update
git diff --exit-code || (echo "::error::Generated files are out of date. Run 'pnpm run update' in packages/eslint-plugin-boxel and commit the result." && exit 1)
eslint-plugin-cardstack-host-test:
name: ESLint Plugin Cardstack Host Tests
needs: change-check
if: needs.change-check.outputs.eslint-plugin-cardstack-host == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: eslint-plugin-cardstack-host-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: ESLint Plugin Cardstack Host test suite
run: pnpm test
working-directory: packages/eslint-plugin-cardstack-host
- name: Check generated files are up to date
working-directory: packages/eslint-plugin-cardstack-host
run: |
pnpm run update
git diff --exit-code || (echo "::error::Generated files are out of date. Run 'pnpm run update' in packages/eslint-plugin-cardstack-host and commit the result." && exit 1)
postgres-migration-test:
name: Postgres Migration Test
needs: change-check
if: needs.change-check.outputs.postgres-migrations == 'true' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: postgres-migration-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: ./.github/actions/init
# Warm the test images from the GHCR mirror so the steps
# below start from a local image instead of an unauthenticated Docker Hub
# pull (the cause of the recurring registry-1.docker.io timeouts).
# Best-effort: a miss falls back to a hardened-retry Docker Hub pull.
- name: Warm test Docker images from the GHCR mirror
continue-on-error: true
uses: ./.github/actions/warm-test-images
- name: Start Postgres
run: pnpm start:pg
working-directory: packages/postgres
- name: Determine changed migrations
id: migrations
env:
PULL_REQUEST_BASE_SHA: ${{ github.event.pull_request.base.sha || '' }}
GITHUB_EVENT_BEFORE: ${{ github.event.before || '' }}
shell: bash
run: packages/postgres/scripts/determine-changed-migrations.sh
- name: Apply migrations
if: steps.migrations.outputs.count && steps.migrations.outputs.count != '0'
working-directory: packages/postgres
env:
PGHOST: localhost
PGPORT: 5435
run: pnpm migrate up
- name: Run down migrations
if: steps.migrations.outputs.count && steps.migrations.outputs.count != '0'
working-directory: packages/postgres
env:
MIGRATION_DOWN_COUNT: ${{ steps.migrations.outputs.down_count }}
run: pnpm migrate down "$MIGRATION_DOWN_COUNT"
- name: Reapply migrations
if: steps.migrations.outputs.count && steps.migrations.outputs.count != '0'
working-directory: packages/postgres
run: pnpm migrate up
boxel-ui-test:
name: Boxel UI Tests
needs: [change-check]
if: needs.change-check.outputs.boxel-ui == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: boxel-ui-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Restore boxel-icons build cache
id: icons-cache
uses: ./.github/actions/restore-icons-cache
- name: Build boxel-icons and boxel-ui
run: mise run build:ui
env:
SKIP_ICONS_BUILD: ${{ steps.icons-cache.outputs.cache-hit }}
- name: Run test suite
run: pnpm test
working-directory: packages/boxel-ui/test-app
boxel-ui-raw-icon-changes-only:
name: Boxel UI ensure raw icon changes only
needs: change-check
if: needs.change-check.outputs.boxel-ui == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: boxel-ui-raw-icon-changes-only-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Rebuild boxel-ui icons
run: pnpm rebuild:icons
working-directory: packages/boxel-ui/addon
- name: Fail if generated icons have been changed without underlying raw icon changing
run: git diff --exit-code
boxel-icons-raw-icon-changes-only:
name: Boxel Icons ensure raw icon changes only
needs: change-check
if: needs.change-check.outputs.boxel-icons == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: boxel-icons-raw-icon-changes-only-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Rebuild boxel-icons icons
run: pnpm rebuild:all
working-directory: packages/boxel-icons
- name: Fail if generated icons have been changed without underlying raw icon changing
run: git diff --exit-code
matrix-client-test:
name: Matrix Client Tests
needs: [change-check, test-web-assets]
if: needs.change-check.outputs.matrix == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3]
shardTotal: [3]
concurrency:
group: matrix-client-test-${{ matrix.shardIndex }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Install Playwright Browsers
run: pnpm exec playwright install
working-directory: packages/matrix
# Warm the test images from the GHCR mirror so the services
# below (and the Playwright synapse/smtp fixtures) start from a local
# image instead of an unauthenticated Docker Hub pull (the cause of the
# recurring registry-1.docker.io timeouts). Best-effort: a miss falls
# back to a hardened-retry Docker Hub pull.
- name: Warm test Docker images from the GHCR mirror
continue-on-error: true
uses: ./.github/actions/warm-test-images
- name: Run OIDC mapping provider unit tests
# Fast (~no boot) and stack-independent — it only needs the warmed
# Synapse image — so run it once on shard 1 rather than every shard.
if: matrix.shardIndex == 1
run: pnpm test:oidc-mapping-provider
working-directory: packages/matrix
- name: Start test services (icons + host dist + base realm)
run: |
MATRIX_REGISTRATION_SHARED_SECRET='xxxx' mise run test-services:matrix | tee -a /tmp/server.log &
timeout 300 bash -c 'until curl -ksf https://localhost:4200 > /dev/null && curl -sf http://localhost:4206 > /dev/null; do sleep 2; done'
- name: Run Playwright tests
run: pnpm test:group ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
working-directory: packages/matrix
- name: Print realm server logs
if: ${{ !cancelled() }}
run: cat /tmp/server.log
- name: Extract worker and prerender logs
if: ${{ !cancelled() }}
run: |
grep -E '^\[start:worker-base|^\[start:worker-development|^\[start:worker-test' /tmp/server.log > /tmp/worker-manager.log || true
grep -E '^\[start:prerender-dev' /tmp/server.log > /tmp/prerender-server.log || true
grep -E '^\[start:prerender-manager-dev' /tmp/server.log > /tmp/prerender-manager.log || true
grep -E '^\[start:icons' /tmp/server.log > /tmp/icon-server.log || true
grep -E '^\[start:host-dist' /tmp/server.log > /tmp/host-dist.log || true
- name: Upload realm server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-realm-server-log-${{ matrix.shardIndex }}
path: /tmp/server.log
retention-days: 30
- name: Upload worker manager log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-worker-manager-log-${{ matrix.shardIndex }}
path: /tmp/worker-manager.log
retention-days: 30
- name: Upload prerender server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-prerender-server-log-${{ matrix.shardIndex }}
path: /tmp/prerender-server.log
retention-days: 30
- name: Upload prerender manager log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-prerender-manager-log-${{ matrix.shardIndex }}
path: /tmp/prerender-manager.log
retention-days: 30
- name: Upload icon server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-icon-server-log-${{ matrix.shardIndex }}
path: /tmp/icon-server.log
retention-days: 30
- name: Upload host-dist log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: matrix-test-host-dist-log-${{ matrix.shardIndex }}
path: /tmp/host-dist.log
retention-days: 30
- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: blob-report-${{ matrix.shardIndex }}
path: packages/matrix/blob-report
retention-days: 1
- name: Upload Playwright traces
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-traces-${{ matrix.shardIndex }}
path: packages/matrix/test-results/**/trace.zip
retention-days: 30
if-no-files-found: ignore
matrix-client-merge-reports-and-publish:
name: Merge Matrix reports and publish
needs:
- change-check
- matrix-client-test
# !cancelled() makes it run even if a matrix-client-test shard fails, but still respects cancellation
if: ${{ !cancelled() && (needs.change-check.outputs.matrix == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true') }}
runs-on: ubuntu-latest
concurrency:
group: matrix-client-merge-reports-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
id-token: write
contents: write
checks: write
statuses: write
outputs:
timestamp: ${{ steps.timestampid.outputs.timestamp }}
steps:
- name: Create a timestamp as a directory to store reports in
id: timestampid
run: echo "timestamp=$(date --utc +%Y%m%d_%H%M%SZ)" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge blobs into one single report
run: pnpm exec playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 14
- name: Set up env
env:
INPUT_ENVIRONMENT: ${{ inputs.environment }}
run: |
echo "AWS_REGION=us-east-1" >> $GITHUB_ENV
echo "AWS_ROLE_ARN=arn:aws:iam::680542703984:role/boxel-matrix-playwright-reports" >> $GITHUB_ENV
echo "AWS_S3_BUCKET=cardstack-boxel-matrix-playwright-reports-staging" >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Publish consolidated report to S3
run: aws s3 sync ./playwright-report s3://cardstack-boxel-matrix-playwright-reports-staging/${{ github.head_ref || github.ref_name }}/${{ steps.timestampid.outputs.timestamp }}
- name: Store Playwright report URL
shell: bash
run: echo "PLAYWRIGHT_REPORT_URL=https://boxel-matrix-playwright-reports.stack.cards/${{ github.head_ref || github.ref_name }}/${{ steps.timestampid.outputs.timestamp }}/index.html" >> $GITHUB_ENV
- name: Add status with link to Playwright report
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
MATRIX_TEST_RESULT: ${{ needs.matrix-client-test.result }}
run: |
state="success"
description=""
if [ "$MATRIX_TEST_RESULT" = "failure" ]; then
state="failure"
description="Matrix Playwright shard failures"
fi
curl \
-X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$REPOSITORY/statuses/$HEAD_SHA \
-d '{"context":"Matrix Playwright tests report","description":"'"$description"'","target_url":"'"$PLAYWRIGHT_REPORT_URL"'","state":"'"$state"'"}'
realm-server-test:
name: Realm Server Tests
needs: [change-check, test-web-assets]
if: needs.change-check.outputs.realm-server == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: realm-server-test-${{ matrix.shardIndex }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4, 5, 6]
shardTotal: [6]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Compute shard test modules
id: shard_modules
run: echo "modules=$(node scripts/shard-test-modules.cjs ${{ matrix.shardIndex }} ${{ matrix.shardTotal }})" >> "$GITHUB_OUTPUT"
working-directory: packages/realm-server
# Warm the test images from the GHCR mirror so the services
# below start from a local image instead of an unauthenticated Docker Hub
# pull (the cause of the recurring registry-1.docker.io timeouts).
# Best-effort: a miss falls back to a hardened-retry Docker Hub pull.
- name: Warm test Docker images from the GHCR mirror
continue-on-error: true
uses: ./.github/actions/warm-test-images
- name: Start test services (icons + host dist + realm servers)
run: mise run test-services:realm-server | tee -a /tmp/server.log &
- name: create realm users
run: pnpm register-realm-users
working-directory: packages/matrix
- name: realm server test suite
run: pnpm test:wait-for-servers
working-directory: packages/realm-server
env:
TEST_MODULES: ${{ steps.shard_modules.outputs.modules }}
JUNIT_OUTPUT_FILE: ${{ github.workspace }}/junit/realm-server-${{ matrix.shardIndex }}.xml
- name: Upload junit report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-report-${{ matrix.shardIndex }}
path: junit/realm-server-${{ matrix.shardIndex }}.xml
retention-days: 30
- name: Print realm server logs
if: ${{ !cancelled() }}
run: cat /tmp/server.log
- name: Prepare artifact name
id: artifact_name
if: ${{ !cancelled() }}
run: |
export SAFE_ARTIFACT_NAME=shard-${{ matrix.shardIndex }}
echo "artifact_name=$SAFE_ARTIFACT_NAME" >> "$GITHUB_OUTPUT"
- name: Extract worker and prerender logs
if: ${{ !cancelled() }}
run: |
grep -E '^\[start:worker-development|^\[start:worker-test' /tmp/server.log > /tmp/worker-manager.log || true
grep -E '^\[start:prerender-dev' /tmp/server.log > /tmp/prerender-server.log || true
grep -E '^\[start:prerender-manager-dev' /tmp/server.log > /tmp/prerender-manager.log || true
grep -E '^\[start:development' /tmp/server.log > /tmp/start-development.log || true
grep -E '^\[start:test-realms|^\[start:worker-test' /tmp/server.log > /tmp/test-realms.log || true
grep -E '^\[start:icons' /tmp/server.log > /tmp/icon-server.log || true
grep -E '^\[start:host-dist' /tmp/server.log > /tmp/host-dist.log || true
- name: Upload realm server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-realm-server-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/server.log
retention-days: 30
- name: Upload worker manager log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-worker-manager-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/worker-manager.log
retention-days: 30
- name: Upload prerender server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-prerender-server-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/prerender-server.log
retention-days: 30
- name: Upload prerender manager log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-prerender-manager-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/prerender-manager.log
retention-days: 30
- name: Upload start:development log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-start-development-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/start-development.log
retention-days: 30
- name: Upload test-realms log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-test-realms-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/test-realms.log
retention-days: 30
- name: Upload icon server log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-icon-server-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/icon-server.log
retention-days: 30
- name: Upload host-dist log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-host-dist-log-${{steps.artifact_name.outputs.artifact_name}}
path: /tmp/host-dist.log
retention-days: 30
realm-server-merge-reports:
name: Merge Realm Server reports and publish
if: ${{ !cancelled() && (needs.change-check.outputs.realm-server == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true') }}
concurrency:
group: realm-server-merge-reports-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
needs: [change-check, realm-server-test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download JUnit reports
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: all-realm-server-reports
pattern: realm-server-test-report-*
merge-multiple: true
- name: Merge reports
run: npx junit-report-merger realm-server.xml "./all-realm-server-reports/*.xml"
- name: Upload merged report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: realm-server-test-report-merged
path: realm-server.xml
retention-days: 30
- name: Publish test results
id: publish-tests
uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # 2.18.0
if: ${{ !cancelled() }}
with:
junit_files: realm-server.xml
check_name: Realm Server Test Results
comment_mode: "off"
json_file: test-results.json
- name: Build realm-tests slot
if: ${{ !cancelled() && hashFiles('test-results.json') != '' }}
run: |
set -euo pipefail
mkdir -p slot
{
echo "### Realm Server Test Results"
echo
jq -r '.summary' test-results.json
failures=$(jq -r '((.stats.tests_fail // 0) + (.stats.tests_error // 0))' test-results.json)
check_url=$(jq -r '.check_url // empty' test-results.json)
if [ -n "$check_url" ] && [ "$failures" -gt 0 ]; then
echo
echo "For more details on these errors, see [this check]($check_url)."
fi
} > slot/slot.md
- name: Upload realm-tests slot
if: ${{ !cancelled() && hashFiles('slot/slot.md') != '' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pr-comment-slot-realm-tests
path: slot/
retention-days: 7
amd-transpile-bench:
name: AMD Transpile Bench
needs: change-check
# Parallel-independent bench of the loader's ES → AMD transpiler.
# Compares production-candidate medians against
# `packages/runtime-common/scripts/bench-amd/baseline.json`. When
# baseline.json is absent the script runs in report-only mode and
# exits 0 — used to anchor the initial baseline from real CI numbers
# before enforcement is turned on. See CS-10983.
if: needs.change-check.outputs.bench-amd == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: amd-transpile-bench-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
# Doubled vs. the local default (50/5) to dampen GH-runner noise.
ITER: 100
WARMUP: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Run bench gate
run: pnpm bench:amd:check
working-directory: packages/runtime-common
- name: Trip-test (proves gate's failure path)
# Synthetic stingy baseline → confirms exit 1, FAIL-message
# format intact, every fixture appears in breach list. Runs
# only after the real gate passes so a green pipeline means
# "real gate accepts current code AND failure path still works."
run: pnpm bench:amd:check:trip-test
working-directory: packages/runtime-common
realm-bench:
name: Realm Performance Benchmark
needs: change-check
# HTTP GET and `_search` regression bench against a fixture realm
# snapshot. Spins up an ephemeral realm-server stack (postgres +
# prerender + worker + realm-server) via realm-test-harness and
# times representative requests. Compares medians against
# `packages/realm-server/scripts/bench-realm/baseline.json`. When
# baseline.json is absent the script runs in report-only mode and
# exits 0 — used to anchor the initial baseline from real CI numbers
# before enforcement is turned on.
#
# Runs in parallel with everything else (only depends on
# change-check, like `amd-transpile-bench`). The job builds host/dist
# itself rather than consuming the shared `test-web-assets` artifact
# so a slow web-assets build doesn't gate the bench.
if: needs.change-check.outputs.bench-realm == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: realm-bench-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
# CI default — local default is 50/5. The bench harness amortises
# one stack startup across all scenarios, so doubling iterations
# only adds ~tens of seconds for tighter medians.
ITER: 100
WARMUP: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
# The harness mounts host/dist on the realm-server. Build it here
# rather than consuming the test-web-assets artifact so the bench
# stays parallel-independent. Host's build pulls in @cardstack/
# boxel-ui and @cardstack/boxel-icons via their package exports, so
# those need built dists before host's vite build can resolve them.
- name: Build Boxel Icons
run: pnpm run build
working-directory: packages/boxel-icons
- name: Build Boxel UI
run: pnpm run build
working-directory: packages/boxel-ui/addon
- name: Build host dist
run: pnpm build
working-directory: packages/host
- name: Run bench gate
run: pnpm bench:realm:check
working-directory: packages/realm-server
post-pr-status:
name: Update PR status comment
needs:
- realm-server-merge-reports
if: ${{ !cancelled() && needs.realm-server-merge-reports.result == 'success' }}
uses: ./.github/workflows/pr-status-comment.yml
permissions:
contents: read
issues: write
pull-requests: write
actions: read
with:
head-sha: ${{ github.event.pull_request.head.sha || github.sha }}
pr-number: ${{ github.event.pull_request.number }}
slots: realm-tests
secrets: inherit
vscode-boxel-tools-package:
name: Boxel Tools VS Code Extension package
needs: [change-check, test-web-assets]
if: needs.change-check.outputs.vscode-boxel-tools == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: vscode-boxel-tools-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Prepublish
run: pnpm vscode:prepublish
working-directory: packages/vscode-boxel-tools
- name: Package
run: pnpm vscode:package
working-directory: packages/vscode-boxel-tools
- name: Upload
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: vscode-boxel-tools
path: packages/vscode-boxel-tools/boxel-tools*vsix
boxel-cli-build:
name: Boxel CLI Build
needs: [change-check, test-web-assets]
if: needs.change-check.outputs.boxel-cli == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: boxel-cli-build-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
# `pnpm build` in boxel-cli runs `build:test-harness`, which reads
# from `packages/host/dist/`. Restore that from the shared
# test-web-assets artifact so we don't have to rebuild the host
# here (CS-11164).
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Build boxel-cli
run: pnpm build
working-directory: packages/boxel-cli
boxel-cli-test:
name: Boxel CLI Tests
needs: [change-check, test-web-assets]
# Also run on realm-server changes: boxel-cli's integration tests cover
# the publish/unpublish/readiness-check HTTP contract the realm-server
# exposes, so a realm-server-only PR that drifts that contract (as in
# CS-11161) needs to fail here pre-merge rather than on main post-merge.
if: needs.change-check.outputs.boxel-cli == 'true' || needs.change-check.outputs.realm-server == 'true' || github.ref == 'refs/heads/main' || needs.change-check.outputs.run_all == 'true'
runs-on: ubuntu-latest
concurrency:
group: boxel-cli-test-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Build
run: pnpm build
working-directory: packages/boxel-cli
- name: Run unit tests
run: pnpm test:unit
working-directory: packages/boxel-cli
# Warm the test images from the GHCR mirror so the steps
# below start from a local image instead of an unauthenticated Docker Hub
# pull (the cause of the recurring registry-1.docker.io timeouts).
# Best-effort: a miss falls back to a hardened-retry Docker Hub pull.
- name: Warm test Docker images from the GHCR mirror
continue-on-error: true
uses: ./.github/actions/warm-test-images
- name: Start Matrix
run: pnpm start:matrix
working-directory: packages/realm-server
- name: Create realm users
run: pnpm register-realm-users
working-directory: packages/matrix
- name: Start dev stack (icons + host-dist + base realm + prerenderer)
run: |
mise run test-services:matrix | tee -a /tmp/server.log &
# `-k` skips cert verification (the local realm-server speaks
# HTTPS with the mkcert leaf cert). `-w '%{http_code}'` + grep
# ensures we treat 3xx as still-not-ready instead of letting
# `-f` return 0 on the dispatcher's redirect response, which
# would race the tests ahead of the base realm finishing its
# initial index.
timeout 600 bash -c 'until curl -sk -o /dev/null -w "%{http_code}" https://localhost:4200/ | grep -qx 200 && curl -sk -o /dev/null -w "%{http_code}" -H "Accept: application/vnd.api+json" https://localhost:4201/base/_readiness-check | grep -qx 200; do sleep 2; done'
- name: Run integration tests
run: pnpm test:integration
working-directory: packages/boxel-cli
- name: Print server logs
if: ${{ !cancelled() }}
run: cat /tmp/server.log
deploy:
name: Deploy boxel to staging
if: needs.change-check.outputs.boxel == 'true' && github.ref == 'refs/heads/main'
needs:
- change-check
- ai-bot-test
- bot-runner-test
- boxel-ui-test
- realm-server-test
uses: ./.github/workflows/manual-deploy.yml
permissions:
contents: read
deployments: write
id-token: write
secrets: inherit
with:
environment: "staging"
cache-index:
name: Cache realm index
needs: [change-check, test-web-assets]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
concurrency:
group: cache-index-${{ github.run_id }}
cancel-in-progress: false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/init
- name: Download test web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.test-web-assets.outputs.artifact_name }}
path: .test-web-assets-artifact
- name: Restore test web assets into workspace
shell: bash
run: |
shopt -s dotglob
cp -a .test-web-assets-artifact/. ./
- name: Index all realms and dump tables
# pipefail so a nonzero exit from the index/dump task fails the step
# instead of being masked by tee's exit code.
run: |
set -o pipefail
mise run ci:cache-index 2>&1 | tee /tmp/cache-index.log
timeout-minutes: 45
- name: Upload service logs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: cache-index-log
path: /tmp/cache-index.log
retention-days: 7
# Separate step so an incomplete cache (a table dropped out of the dump)
# surfaces as its own short, clearly-labeled failure with an error
# annotation, rather than an exit code buried in the dump log above.
- name: Verify index cache is complete
run: scripts/verify-index-cache.sh /tmp/boxel-index-cache.sql.gz
- name: Upload index cache
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: boxel-index-cache
path: /tmp/boxel-index-cache.sql.gz
retention-days: 30