name: CI on: pull_request: push: branches: [main] jobs: frozen-install: name: Frozen lockfile install runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Verify workspace groups run: pnpm -r list --depth -1 # E00-S02-T08: the static assertions of tests/secrets-not-embedded.test.mjs # gate every PR (the docker-gated layer-scan probe inside the same file runs # where a Docker daemon is available and skips cleanly otherwise). secrets-not-embedded: name: Secrets not embedded (E00-S02-T08) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Run secrets-not-embedded test suite run: node --test tests/secrets-not-embedded.test.mjs # E00-S03-T02: the static assertions of tests/database-postgres-imports.test.mjs # gate every PR — the scan proves pg/Kysely imports live only in # packages/database-postgres and the mutation probes prove the scan catches # a driver import injected into any other package. database-postgres-imports: name: Database-postgres import isolation (E00-S03-T02) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Run database-postgres import isolation suite run: node --test tests/database-postgres-imports.test.mjs # E00-S03-T03: the static assertions of tests/database-postgres-ledger.test.mjs # gate every PR — the suite locks in the migration ledger (schema_migrations # table DDL, idempotent parameterized record, driver-boundary re-export) # with mutation probes, and the docker-gated real-stack probe (migrate an # empty database and confirm the ledger exists) runs where a Docker daemon # is available and skips cleanly otherwise. The job installs the frozen # workspace because the real-stack probe executes the committed ledger # module from the host (it imports `pg` through the package's own links). database-postgres-ledger: name: Migration ledger (E00-S03-T03) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Run migration ledger test suite run: node --test tests/database-postgres-ledger.test.mjs # E00-S03-T04: the static assertions of tests/database-postgres-lock.test.mjs # gate every PR — the suite locks in the migration advisory lock (session- # scoped pg_advisory_lock/pg_try_advisory_lock over a stable keyed hash on a # dedicated connection, re-entrant-safe in-flight acquire so concurrent # acquire() calls share one connection, driver-boundary re-export) with # mutation probes, and the docker-gated real-stack concurrent probe (a # second runner waits or fails while the first holds the lock; concurrent # acquire() checks out exactly one connection; the lock releases when the # holding session ends) runs where a Docker daemon is available and skips # cleanly otherwise. The job installs the frozen workspace because the # real-stack probe executes the committed lock module from the host (it # imports `pg` through the package's own links). database-postgres-lock: name: Migration advisory lock (E00-S03-T04) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Run migration advisory lock test suite run: node --test tests/database-postgres-lock.test.mjs # E00-S03-T05: the static assertions of tests/database-postgres-diagnostic.test.mjs # gate every PR — the suite locks in the migration failure diagnostic (a # structured MigrationFailedError whose diagnostic identifies the failing # migration, the failure phase, the underlying cause, and the applied/pending # ledger state, serializable via toJSON) with mutation probes, and a # deterministic stub-pool behavioral probe (intentionally failing migration # fixture -> structured diagnostic naming the failing migration) runs on # Node 24; the docker-gated real-stack probe (the issue's test plan: "run an # intentionally failing migration fixture and confirm the diagnostic") runs # where a Docker daemon is available and skips cleanly otherwise. The job # installs the frozen workspace because the probes execute the committed # runner module from the host (it imports `pg` through the package's own # links). database-postgres-diagnostic: name: Migration failure diagnostic (E00-S03-T05) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Run migration failure diagnostic test suite run: node --test tests/database-postgres-diagnostic.test.mjs # E00-S03-T06: the static assertions of tests/app-readiness.test.mjs gate # every PR — the suite locks in the readiness gate (the app answers # GET /health with 503 {"status":"not ready"} until the startup migration # run completes, then 200 {"status":"ok"}) with mutation probes, the # deterministic probes (boot the committed server: no DATABASE_URL -> # ready immediately; unreachable DATABASE_URL -> stays not-ready) run on # Node 24, and the docker-gated real-stack probe (the issue's test plan: # "start with pending migrations and confirm readiness waits" — the app's # migration run is blocked behind a held ACCESS EXCLUSIVE lock on the # migration ledger, /health stays not-ready, then flips ready once the lock # releases) runs where a Docker daemon is available and skips cleanly # otherwise. The job installs the frozen workspace and builds the config # and database-postgres packages because the probes boot the committed # server from the host (it imports @personal-blog/config and # @personal-blog/database-postgres through the packages' own links; the # required EPPP_SESSION_SECRET is provided by the probe's boot env). app-readiness: name: App readiness after migrations (E00-S03-T06) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Build the config and database-postgres packages (the probes boot the committed server which imports them) run: pnpm --filter @personal-blog/config build && pnpm --filter @personal-blog/database-postgres build - name: Run app readiness test suite run: node --test tests/app-readiness.test.mjs # E00-S04-T02: the static assertions of tests/config-startup-error.test.mjs # gate every PR — the suite locks in the field-specific startup error (a # missing required setting fails startup with an error naming the missing # field: packages/config's MissingRequiredSettingError/assertValidConfig, # wired into the committed server before it binds) with mutation probes, and # the deterministic probes execute the issue's test plan ("start with a # missing required field and confirm the error names it"): booting the # committed server without EPPP_SESSION_SECRET exits non-zero naming # sessionSecret, while a valid secret boots to GET /health 200. The job # installs the frozen workspace and builds the config and database-postgres # packages because the probes boot the committed server which imports them. config-startup-error: name: Field-specific startup errors (E00-S04-T02) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Build the config and database-postgres packages (the probes boot the committed server which imports them) run: pnpm --filter @personal-blog/config build && pnpm --filter @personal-blog/database-postgres build - name: Run config startup error test suite run: node --test tests/config-startup-error.test.mjs # E00-S04-T03: the static assertions of tests/config-log-redaction.test.mjs # gate every PR — the suite locks in automatic secret redaction from logs # (packages/config's redactConfig/redactText + the server's redacting # logger: every log line is scrubbed of the config's secret values) with # mutation probes, and the deterministic probes execute the issue's test # plan ("log configuration and confirm secret values are redacted"): # booting the committed server logs its resolved configuration with the # secret values replaced by [REDACTED], and no secret value appears in the # log output. The job installs the frozen workspace and builds the config # and database-postgres packages because the probes boot the committed # server which imports them. config-log-redaction: name: Secret redaction from logs (E00-S04-T03) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Build the config and database-postgres packages (the probes boot the committed server which imports them) run: pnpm --filter @personal-blog/config build && pnpm --filter @personal-blog/database-postgres build - name: Run config log redaction test suite run: node --test tests/config-log-redaction.test.mjs # E00-S04-T01: the static assertions of tests/config-schema.test.mjs gate # every PR — the suite locks in the TypeBox/Ajv configuration schema # (packages/config, golden-tuple pins @sinclair/typebox@0.34.52 + # ajv@8.20.0) with mutation probes, and the deterministic probe executes # the issue's test plan ("validate a full config against the TypeBox/Ajv # schema") against the committed schema through Ajv. The job installs the # frozen workspace and builds the config package because the probe also # exercises the compiled package boundary (@personal-blog/config) exactly # as the later configuration adapter will consume it. config-schema: name: TypeBox/Ajv config schema (E00-S04-T01) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Enable pnpm (corepack, pinned to 11.23.0 via packageManager) run: corepack enable - name: Install dependencies (frozen lockfile) run: pnpm install --frozen-lockfile - name: Build the config package (the probe exercises the compiled package boundary) run: pnpm --filter @personal-blog/config build - name: Run config schema test suite run: node --test tests/config-schema.test.mjs # E00-S03-T01: the static assertions of tests/compose-config.test.mjs (db # image pinned to postgres:18.6-bookworm, health gate, volume persistence, # build platforms) gate every PR (the docker-gated real-stack probes inside # the same file run where a Docker daemon is available and skip cleanly # otherwise). compose-config: name: Compose config (E00-S03-T01) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Node.js 24 uses: actions/setup-node@v4 with: node-version: '24' - name: Run compose-config test suite run: node --test tests/compose-config.test.mjs