CI / verify (pull_request) Successful in 1m2s
CI / infrastructure-smoke (pull_request) Successful in 35s
CI / migration-smoke (pull_request) Successful in 1m52s
CI / package-release (pull_request) Failing after 16s
CI / image-build (pull_request) Successful in 29s
CI / deploy-smoke (same-origin) (pull_request) Successful in 44s
CI / deploy-smoke (split) (pull_request) Successful in 1m29s
Produces the exact public package tarballs of a platform release, validates them, and proves a standalone module consumes those artifacts end to end. Nothing is published and no credential is configured. - scripts/package-release.ts (pnpm packages:release) is the canonical release builder: from a clean commit it rebuilds the nine public packages from clean output, packs each, inspects every tarball, checks the release set and coordinated versions, and only then writes ekklesia-packages-<version>/ with the tarballs, SHA256SUMS, and a provider-neutral manifest (ekklesia-package-train.json: version, revision, and each package's file, size, SHA-256, npm integrity). - Packing uses a pack-only pnpm beforePacking hook (passed with --config.pnpmfile, never the workspace's install settings). pnpm inserts rewritten workspace: dependencies in async completion order, so two checkouts of one commit packed module-pack's package.json with keys in a different order; the hook restores the source key order (and the inspection enforces it). It also drops devDependencies, which named private packages outside the train. - scripts/test-package-release.sh (pnpm test:package-release, the CI package-release gate) builds the train twice, the second time from a separate worktree, requires byte-identical release directories, then runs the standalone consumer proof on the release: manifest checked, offline install from the tarballs only, lockfile integrity equal to the manifest's, frozen-lockfile reinstall, no Drizzle, one React, contracts only transitive, every @ekklesia package and module-pack at the release version, skipLibCheck: false, UI build, pack, and Core verification. - docs/development/releases.md documents the release order, the train, the artifacts, and the reproducibility findings; registry publication remains unimplemented. - ADR 0053 is Accepted: everything it decides that does not need a registry is now proven, and registry provisioning is on its own Deferred list. Co-Authored-By: Claude Opus 5.5 <[email protected]>
247 lines
11 KiB
YAML
247 lines
11 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
|
|
|
|
package-release:
|
|
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 [email protected] --activate
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
# ADR 0053's package release gate: build the public package train from this commit, build it
|
|
# again from a second checkout and require byte-identical artifacts, then install exactly those
|
|
# tarballs (offline, no registry) into a module outside this repository and prove it builds,
|
|
# packages, and verifies. Nothing is published and no credential exists here. A future publish
|
|
# job must depend on this job and publish only the artifacts it proved.
|
|
- name: Build, reproduce, and consume the public package train
|
|
run: pnpm test:package-release
|
|
|
|
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
|