Files
coreci-chat/.gitea/workflows/ci.yml
T
coreci-chat-po a86a801784
ci / test-pglite (PGlite, default) (push) Failing after 1m3s
ci / test-postgres (Postgres 16, G-022 RLS) (push) Successful in 1m51s
ci: build the control-plane app in the gate (next build) - the app build was never machine-verified (coreci-chat#10)
The M2 acceptance gate requires both jobs GREEN, but no step in either job ran
`next build`: the workflow builds the eight library packages and typechecks and
lints the app, so the App Router tree itself was never compiled by a machine.
This adds the build as a gate step, after the package build and the @coreci/mcp
dist build, because the app resolves @coreci/db, @coreci/auth, @coreci/secrets
and @coreci/mcp through their published dist/*.d.ts.

coreci-chat#10 closes on a green app build on main.
2026-10-31 00:27:25 +00:00

251 lines
9.6 KiB
YAML

# .gitea/workflows/ci.yml — CoreCI Chat CI pipeline (G-011, G-022, R-009, Wave J Task 7).
#
# Gitea Actions (GitHub Actions-compatible YAML + secrets + service containers).
# The repo's forge is Gitea at git.cloudinit.dev; Gitea Actions runs the same
# workflow syntax as GitHub Actions. Two jobs:
#
# 1. test-pglite (default): pnpm install, typecheck, lint, test, conformance,
# coverage upload. Go tests. Runs on every push/PR. Track B LLM smoke
# runs when secrets.GITHUB_SMOKE_PAT is available (allow-failure — does
# NOT block the P0 gate).
#
# 2. test-postgres (G-022): Postgres 16 service container, setup-ci-roles.sql
# (coreci_app NOBYPASSRLS, migrator BYPASSRLS), DB_MODE=pg, pnpm migrate,
# full M1 + M2 suite against real Postgres (the first real-RLS test).
# Runs on every push/PR (parallel to test-pglite).
#
# Both jobs cache pnpm store + go modules. Coverage uploaded as artifacts.
# The M2 acceptance gate (spec §6) requires both jobs GREEN.
# NOTE (2026-10-26, coreci-chat-po, revised): the trigger shape below now
# matches the shape this instance actually runs - a bare `push:` and a
# `pull_request` filtered to `main` (coreci/nova-platform ci.yml fires on
# both). The earlier note here ("only a default-branch push touching THIS file
# registers the trigger", sre readback c12346, "F-1") is FALSIFIED: PR #7
# merged to main at 2026-10-26T22:59:04Z touching this file and the pipeline
# still produced no run record (coreci-chat#1, M3 kickoff gate).
#
# NOTE (2026-10-26, coreci-chat-po): the jobs run on the fleet shared-pool label
# `ubuntu-latest`. The `node` label is a bare node:24-bookworm image with no fleet
# toolchain - nova-platform run 51350 went green on ubuntu-latest, run 51345 red on
# node. Go and the postgres client are installed by the jobs themselves, and the
# postgres service is reached by its service name (coreci-chat#1, M3 kickoff gate).
name: ci
on:
push:
pull_request:
branches: [main]
workflow_dispatch: {}
env:
# Pin Node + pnpm versions for reproducibility.
# Node 22 is the floor: pnpm 11.23.0 (the packageManager pin) needs >= v22.13
# and dies on Node 20 with ERR_UNKNOWN_BUILTIN_MODULE (node:sqlite).
NODE_VERSION: "22"
# Display label for the pnpm step only. The INSTALLED pnpm version is the
# packageManager pin in package.json - pnpm/action-setup rejects a second
# pin (workflow version: + package.json packageManager:) and exits 1.
PNPM_VERSION: "11"
jobs:
# ─── Job 1: test-pglite (default — PGlite in-process) ──────────────────
test-pglite:
name: test-pglite (PGlite, default)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup pnpm ${{ env.PNPM_VERSION }}
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Get pnpm store dir
id: pnpm-cache
run: echo "STORE=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE }}
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: pnpm-${{ runner.os }}-
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Consumers resolve @coreci/db and @coreci/secrets through their
# published dist/*.d.ts, so the packages must be built (pnpm runs
# them in dependency order) before typecheck and before the tests.
- name: Build (packages - dist for the type declarations)
run: pnpm --filter "./packages/*" -r build
- name: Typecheck
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Build (mcp package — dist for the smoke imports)
run: pnpm --filter @coreci/mcp build
# The app build is the M2 gate's missing leg (coreci-chat#10): `next
# build` is the only check that proves the App Router tree (root layout,
# route handlers, pages) compiles. The workspace packages are built
# above because the app resolves @coreci/db, @coreci/auth,
# @coreci/secrets and @coreci/mcp through their published dist/*.d.ts.
- name: Build (control-plane app - next build)
run: pnpm --filter @coreci/control-plane build
- name: "[G-018,R-008] Import guard (no @coreci/llm-mock in prod source)"
run: pnpm check:llm-mock-guard
- name: Unit + integration tests (PGlite)
run: pnpm test
- name: MCP conformance + LLM smoke (Track A mock-path P0 + Track B allow-failure)
env:
# Track B runs only when the PAT secret is present; it is allow-failure.
GITHUB_SMOKE_PAT: ${{ secrets.GITHUB_SMOKE_PAT }}
run: pnpm test:conformance
- name: Coverage (llm-mock + mcp)
run: |
pnpm --filter @coreci/llm-mock test:coverage
pnpm --filter @coreci/mcp test:coverage || true
continue-on-error: true
- name: Setup Go 1.23
uses: actions/setup-go@v5
with:
go-version: "1.23"
cache: false
- name: Go tests (Relay Agent)
run: |
if [ -f apps/relay-agent/go.mod ]; then
cd apps/relay-agent && go test ./...
fi
- name: Upload coverage artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-pglite
path: |
packages/llm-mock/coverage/
packages/mcp/coverage/
if-no-files-found: ignore
retention-days: 7
# ─── Job 2: test-postgres (G-022 — real Postgres 16, RLS enforced) ──────
test-postgres:
name: test-postgres (Postgres 16, G-022 RLS)
runs-on: ubuntu-latest
timeout-minutes: 25
services:
# Postgres 16 service container (R-009). The image is the official
# postgres:16; the CI runner connects to it via `postgres` hostname.
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
# The test harness reads DB_MODE + DATABASE_URL. Connect as the
# superuser to run setup-ci-roles.sql, then the tests connect as
# coreci_app (NOBYPASSRLS) so RLS is enforced.
# DATABASE_URL is exported by the "Resolve the CI database host" step
# below, so the service host is decided once for every later step.
DB_MODE: "pg"
PGPASSWORD: postgres
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup pnpm ${{ env.PNPM_VERSION }}
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~/.local/share/pnpm/store
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: pnpm-${{ runner.os }}-
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Consumers resolve @coreci/db and @coreci/secrets through their
# published dist/*.d.ts, so the packages must be built (pnpm runs
# them in dependency order) before typecheck and before the tests.
- name: Build (packages - dist for the type declarations)
run: pnpm --filter "./packages/*" -r build
- name: Install the postgres client (the runner image carries no psql)
run: |
apt-get update -qq && apt-get install -y -qq postgresql-client
- name: Resolve the CI database host
run: |
HOST=$(getent hosts postgres >/dev/null 2>&1 && echo postgres || echo localhost)
echo "CI_DB_HOST=$HOST" >> "$GITHUB_ENV"
echo "DATABASE_URL=postgres://coreci_app:coreci_app_ci@$HOST:5432/coreci_ci" >> "$GITHUB_ENV"
echo "CI_MIGRATOR_DATABASE_URL=postgres://migrator:migrator_ci@$HOST:5432/coreci_ci" >> "$GITHUB_ENV"
- name: "[R-009] Setup CI roles (coreci_app NOBYPASSRLS, migrator BYPASSRLS)"
run: |
psql -h "$CI_DB_HOST" -U postgres -d postgres -f packages/db/scripts/setup-ci-roles.sql
- name: "[G-022] Run migrations as migrator (BYPASSRLS)"
run: |
DATABASE_URL="$CI_MIGRATOR_DATABASE_URL" pnpm --filter @coreci/db migrate
- name: "[G-022] Build mcp (dist for smoke imports)"
run: pnpm --filter @coreci/mcp build
- name: "[G-022] Full M1 + M2 test suite against real Postgres 16"
# The tests read DB_MODE=pg + DATABASE_URL (coreci_app role, RLS
# enforced). The pen test's WITH CHECK assertion (R-009) is REAL here
# — a cross-tenant INSERT is rejected by the RLS policy.
run: pnpm test
- name: "[G-022] MCP conformance + LLM smoke (Track A only — no PAT in pg job)"
run: pnpm test:conformance
- name: "[G-022] DB pen test (real RLS WITH CHECK enforcement, R-009)"
run: pnpm --filter @coreci/db test:pen
- name: Upload coverage artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-postgres
path: |
packages/*/coverage/
apps/*/coverage/
if-no-files-found: ignore
retention-days: 7