name: CI # The server runs Gitea 1.27.2 (docs/development/security.md, "What this server honours"): # # * `concurrency:` is honoured: a newer push to a pull request cancels the run it supersedes, so a # cancelled run's own cleanup is never guaranteed (see the CI stack sweep in each stack job). # * `permissions:` is supported by 1.27 with Gitea's own scopes, but what the job token can do on # this server is not yet proven, so nothing here relies on it being read-only. # * `timeout-minutes:` is no longer listed as unsupported, but is not verified here either; # teardown relies on the stack sweep and the runner's own reaper. # # `persist-credentials: false` below is unaffected by any of this and is enforced by the action # itself. See docs/development/security.md. on: pull_request: push: branches: - main permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: verify: runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false - name: Set up Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version-file: .node-version - name: Activate pinned pnpm run: | corepack enable corepack prepare pnpm@11.12.0 --activate - name: Install dependencies run: pnpm install --frozen-lockfile - name: Verify repository run: pnpm ci:verify infrastructure-smoke: needs: verify runs-on: ubuntu-latest timeout-minutes: 10 env: # Names this job's stacks, so its final step removes exactly these (scripts/lib/ci-project.sh). EKKLESIA_CI_JOB_KEY: infrastructure-smoke steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false # A job the runner killed (cancelled, or past the runner's own time limit) never ran its # cleanup. Anything a CI job left on this shared daemon more than three hours ago goes first. - name: Sweep stale CI stacks from the runner run: bash scripts/ci-sweep.sh --stale - name: Prove the sweep removes exactly what it should, against real Docker resources run: bash scripts/test-ci-sweep.sh - name: Exercise PostgreSQL and S3 infrastructure run: bash scripts/smoke-infrastructure.sh # Whatever happened above, this job's own stacks do not outlive it. - name: Remove this job's CI stacks if: always() run: bash scripts/ci-sweep.sh --job migration-smoke: needs: verify runs-on: ubuntu-latest timeout-minutes: 15 env: # Names this job's stacks, so its final step removes exactly these (scripts/lib/ci-project.sh). EKKLESIA_CI_JOB_KEY: migration-smoke steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false # A job the runner killed (cancelled, or past the runner's own time limit) never ran its # cleanup. Anything a CI job left on this shared daemon more than three hours ago goes first. - name: Sweep stale CI stacks from the runner run: bash scripts/ci-sweep.sh --stale - name: Set up Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version-file: .node-version - name: Activate pinned pnpm run: | corepack enable corepack prepare pnpm@11.12.0 --activate - name: Install dependencies run: pnpm install --frozen-lockfile - name: Exercise transactional migrations against PostgreSQL run: pnpm test:migrations:integration # Whatever happened above, this job's own stacks do not outlive it. - name: Remove this job's CI stacks if: always() run: bash scripts/ci-sweep.sh --job standalone-module: needs: verify runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false - name: Set up Node.js uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version-file: .node-version - name: Activate pinned pnpm run: | corepack enable corepack prepare pnpm@11.12.0 --activate - name: Install dependencies run: pnpm install --frozen-lockfile # ADR 0053: pack and inspect the public packages, then install them into a module outside this # repository and prove it builds, packages, and verifies. Nothing is published. - name: Build a standalone module from the packed public packages run: pnpm test:standalone-module image-build: needs: verify runs-on: ubuntu-latest timeout-minutes: 20 env: # Names this job's stacks, so its final step removes exactly these (scripts/lib/ci-project.sh). EKKLESIA_CI_JOB_KEY: image-build # Cache mounts in deploy/Dockerfile need BuildKit; this selects it even where the Docker CLI # has no buildx plugin. DOCKER_BUILDKIT: "1" steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false # A job the runner killed (cancelled, or past the runner's own time limit) never ran its # cleanup. Anything a CI job left on this shared daemon more than three hours ago goes first. - name: Sweep stale CI stacks from the runner run: bash scripts/ci-sweep.sh --stale # The one generic platform image (ADR 0044, ADR 0048), proved rather than assumed: it contains no # module, no module template, and no module manifest; its module storage mount point is empty; # EKKLESIA_MODULES_DIR names it; and a checkout with a populated modules/ directory builds an # identical runtime file system. Build only — no registry login, no credentials, no push, no tag # anywhere but this runner's local image store. Tagged per run and attempt, and labeled like # every CI stack, so this job's final step removes the images even if a build is killed. - name: Build the generic platform image and prove it holds no modules run: bash scripts/check-image.sh # Whatever happened above, this job's own stacks do not outlive it. - name: Remove this job's CI stacks if: always() run: bash scripts/ci-sweep.sh --job deploy-smoke: needs: verify runs-on: ubuntu-latest timeout-minutes: 30 # Both topologies (ADR 0045), each on the one generic image: same-origin, the default every # installation gets, and split, which installs a test-only module into module storage, removes # it, and restores it (ADR 0048), and drives a real headless browser across the two origins. strategy: fail-fast: false matrix: topology: - same-origin - split env: # Names this job's stacks, so its final step removes exactly these (scripts/lib/ci-project.sh). EKKLESIA_CI_JOB_KEY: deploy-smoke-${{ matrix.topology }} DOCKER_BUILDKIT: "1" EKKLESIA_SMOKE_TOPOLOGY: ${{ matrix.topology }} steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # `actions/checkout` defaults to leaving the job token in `.git/config`, where any later # step — including one a pull request added to this file — could read or reuse it. Nothing # in this workflow pushes, so the credential is never needed after checkout. persist-credentials: false # A job the runner killed (cancelled, or past the runner's own time limit) never ran its # cleanup. Anything a CI job left on this shared daemon more than three hours ago goes first. - name: Sweep stale CI stacks from the runner run: bash scripts/ci-sweep.sh --stale # The reference deployment end to end (ADR 0044): the generic platform image, base + proxy with # Caddy's internal CA (test-only), an explicit migration apply against this job's own fresh # PostgreSQL, then the API, Dashboard, storage delivery, client-address chain, and verify-full # database TLS through the proxy. Every secret is generated for this run and discarded with # it; nothing is pushed, published, or logged in to. - name: Smoke-test the reference deployment (${{ matrix.topology }}) run: bash scripts/smoke-deploy.sh # Whatever happened above, this job's own stacks do not outlive it. - name: Remove this job's CI stacks if: always() run: bash scripts/ci-sweep.sh --job