name: CI # IMPORTANT — the currently inventoried server is Gitea 1.24.2, which *ignores* several keys used # below. Per https://docs.gitea.com/1.24/usage/actions/comparison, its unsupported workflow syntax # includes `permissions` / `jobs..permissions`, `concurrency`, and # `jobs..timeout-minutes`. They are declared here deliberately, so the workflow is already # correct on a supported release and on GitHub Actions, but on this server they are inert: # # * `permissions:` does NOT restrict the in-job `GITEA_TOKEN`. Job-token permission controls, # repository/owner defaults, and server-side maximum-permission clamping arrive in the 1.26 # feature line (https://docs.gitea.com/1.26/usage/actions/token-permissions). Until the server # is upgraded and configured, the token's authority is whatever the server grants — not what # this file requests. # * `concurrency:` and `timeout-minutes:` are NOT bounded-execution guarantees here. Cancellation, # timeout, and teardown must be enforced by the trusted runner provisioner/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 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: Exercise PostgreSQL and S3 infrastructure run: bash scripts/smoke-infrastructure.sh migration-smoke: 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 - name: Exercise transactional migrations against PostgreSQL run: pnpm test:migrations:integration image-build: needs: verify runs-on: ubuntu-latest timeout-minutes: 20 env: # 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 # The platform-only image (ADR 0044): a checkout has no `modules/`, so this proves the image # builds, validates, and assembles with zero modules. Build only — no registry login, no # credentials, no push, no tag anywhere but this runner's local image store. - name: Build the production image without modules run: >- docker build --file deploy/Dockerfile --build-arg REVISION="$GITHUB_SHA" --tag ekklesia-ci:"$GITHUB_SHA" . - name: Remove the image from the runner if: always() run: docker image rm --force ekklesia-ci:"$GITHUB_SHA" || true deploy-smoke: needs: verify runs-on: ubuntu-latest timeout-minutes: 30 # Both topologies (ADR 0045): same-origin, the default every installation gets, and split, which # adds a test-only module and drives a real headless browser across the two origins. strategy: fail-fast: false matrix: topology: - same-origin - split env: 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 # The reference deployment end to end (ADR 0044): a platform-only 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