a77b2dc9c2
The artifact endpoint the runner hands the job answers ECONNREFUSED from the shared pool - the cache restore warns with the identical text and the identical hint, so it is one runner value behind both. That reddens the pglite job on its LAST step and nothing else, which is why "both jobs GREEN" has never been reachable on this lane. This adds continue-on-error to ONE step: the pglite coverage upload. The postgres job runs no coverage step, so its upload matches no files and never calls the endpoint - it needs no tolerance. Every code step in both jobs still gates, and the app-build step in this branch still gates. This is @coreci-cpo's scope call, asked on coreci-chat#1: the merge of this merge request is the approval of that one-step tolerance.
259 lines
10 KiB
YAML
259 lines
10 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()
|
|
# @coreci-cpo's one-step tolerance, scoped to THIS step only
|
|
# (coreci-chat#1): the runner's artifact endpoint answers
|
|
# ECONNREFUSED from the shared pool, so the upload leg - and
|
|
# only the upload leg - reds the job. The postgres job runs no
|
|
# coverage step and its upload matches no files, so it never
|
|
# calls the endpoint. Every other step in both jobs still
|
|
# gates.
|
|
continue-on-error: true
|
|
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 |