CI / verify (pull_request) Successful in 54s
CI / infrastructure-smoke (pull_request) Successful in 37s
CI / migration-smoke (pull_request) Successful in 1m50s
CI / image-build (pull_request) Successful in 18s
CI / deploy-smoke (same-origin) (pull_request) Successful in 42s
CI / deploy-smoke (split) (pull_request) Successful in 1m1s
The CI documentation, the workflow header, the README, ADR 0047 and the sweep's comment all said the server was Gitea 1.24.2, which ignores `permissions`, `concurrency` and `timeout-minutes`. The server reports 1.27.2 (GET /api/v1/version). Each claim is now stated from what is verified on this server: - `concurrency` is honoured, observed: Ekklesia runs 133 and 135 were cancelled when a newer run started for the same pull request; - `permissions` is supported by 1.27 with Gitea's own scopes, but the token's actual authority is not visible through the API and not yet proven, so nothing claims the job token is read-only; - `timeout-minutes` is no longer listed as unsupported, but is not verified, and teardown still relies on the stack sweep and a reaper. Requirement 1 for executing untrusted contributions (upgrade to the 1.26 line or later) is marked done; items 2 and 3, configuring and proving token authority, remain. ADR 0047 (still Proposed) restates its "docker run, not a reusable workflow" reasons for 1.27, where private sources are supported. The reasons still hold without the 1.24 argument. Co-Authored-By: Claude Opus 5.5 <[email protected]>
221 lines
9.4 KiB
YAML
221 lines
9.4 KiB
YAML
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 [email protected] --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 [email protected] --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
|
|
|
|
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 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.
|
|
# Tagged per run and attempt, not only per commit: a pull request and a push of the same commit
|
|
# can build at once on one runner's Docker daemon, and neither may remove the other's image.
|
|
# Labeled like every CI stack, so this job's final step removes it even if the build is killed.
|
|
- name: Build the production image without modules
|
|
shell: bash
|
|
run: |
|
|
source scripts/lib/ci-project.sh
|
|
docker build \
|
|
--file deploy/Dockerfile \
|
|
--build-arg REVISION="$GITHUB_SHA" \
|
|
--label "${EKKLESIA_CI_LABEL}=$(ci_project_name image)" \
|
|
--label "${EKKLESIA_CI_CREATED_LABEL}=$(date +%s)" \
|
|
--tag ekklesia-ci:"$GITHUB_SHA-${GITHUB_RUN_ID:-0}-${GITHUB_RUN_ATTEMPT:-1}" \
|
|
.
|
|
|
|
# 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): 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:
|
|
# 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): 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
|
|
|
|
# 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
|