Files
coreci-chat/.gitea/workflows/ci.yml
T
coreci-chat-po a77b2dc9c2
ci / test-pglite (PGlite, default) (push) Failing after 1m19s
ci / test-postgres (Postgres 16, G-022 RLS) (push) Successful in 1m57s
ci: tolerate the coverage upload leg alone - the runner's artifact endpoint is refused (coreci-chat#1)
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.
2026-10-31 00:27:31 +00:00

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