name: isolated-ci on: push: pull_request: jobs: verify: # Runner labels/capabilities must be confirmed by the operator before this # workflow is considered release evidence. No deployment or secret access is # performed by this job. runs-on: ubuntu-latest container: oven/bun:1.3.14 steps: - name: Checkout uses: actions/checkout@v4 - name: Install frozen dependencies run: bun install --frozen-lockfile --ignore-scripts - name: Unit and integration tests run: bun test - name: Typecheck run: bun run check - name: Build fixture application run: APP_MODE=demo APP_RELEASE_ID=fixture bun run build - name: Release safety checks run: APP_MODE=demo APP_RELEASE_ID=fixture bun run release:check - name: Isolated fixture smoke run: APP_MODE=demo APP_RELEASE_ID=fixture bun run test:fixture - name: Disabled capability HTTP smoke run: APP_MODE=demo APP_RELEASE_ID=fixture bun run test:release-gates - name: Strict staging release safety check run: >- RELEASE_ENV=staging APP_MODE=live APP_RELEASE_ID=ci-${{ gitea.sha }} CONVEX_IMAGE=ghcr.io/get-convex/convex-backend@sha256:3aa2ccd6697a75de53948b1ee531d7c9688fe09ef360748d75df46dfc888f69a CONVEX_DASHBOARD_IMAGE=ghcr.io/get-convex/convex-dashboard@sha256:63e94c62940a09acd36464e02e1b0a7589f7ef48227003de78510f9523bb4e6b bun run release:check container: # Docker builds run only for trusted pushes. Do not run this job for PR # code on a shared/privileged runner; use a dedicated rootless runner once # one is registered and verified in Gitea. if: ${{ gitea.event_name == 'push' }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Validate Compose expansion run: docker compose config --quiet - name: Build immutable web artifact run: docker build --build-arg APP_RELEASE_ID=fixture-ci --tag eve-intelligence:fixture . - name: Run isolated container smoke shell: bash run: | set -euo pipefail volume="eden-ci-reference-${GITHUB_RUN_ID:-trusted-push}" container="eden-ci-web-${GITHUB_RUN_ID:-trusted-push}" cleanup() { docker rm --force "$container" >/dev/null 2>&1 || true; docker volume rm "$volume" >/dev/null 2>&1 || true; } trap cleanup EXIT docker volume create "$volume" >/dev/null docker run --rm --network none --user root -v "$volume:/app/data/reference" eve-intelligence:fixture \ bun workers/reference.ts --fixture --directory /app/data/reference docker run --detach --name "$container" --network none \ -e APP_MODE=demo -e APP_ORIGIN=http://127.0.0.1:3000 -e ORIGIN=http://127.0.0.1:3000 \ -e HOST=127.0.0.1 -e PORT=3000 -e REFERENCE_DIR=/app/data/reference -e APP_RELEASE_ID=fixture-ci \ -v "$volume:/app/data/reference:ro" eve-intelligence:fixture >/dev/null for attempt in $(seq 1 60); do if docker exec "$container" bun -e "const r = await fetch('http://127.0.0.1:3000'); if (r.status !== 200 || r.headers.get('x-application-release') !== 'fixture-ci') process.exit(1);"; then break; fi if [ "$attempt" = 60 ]; then echo 'container smoke did not become ready' >&2; exit 1; fi sleep 0.5 done docker exec "$container" bun -e "const r = await fetch('http://127.0.0.1:3000/assets'); if (r.status !== 200) process.exit(1);"