986ac19863
Two-track LLM smoke (G-018): Track A (mock-path) P0 gate passes deterministically; Track B (real-path) optional/allow-failure. llm-mock hardened (G-019 regex set). Settings→Adapters UI + Test-Call UI with SSE consumer, staleness, closed-tool-set gap docs (G-014). CI pipeline (.gitea/workflows/ci.yml, G-011) with Postgres 16 service container + setup-ci-roles.sql (G-022). Import guard (R-008). Tests: 618 green + 38 conformance + 5 pen test. Coverage: 97% llm-mock, 92.3% mcp. M1 non-regression: all M1 tests pass. ---ci--- phase: 5 milestone: v0.2 status: complete wave: J phase_role: execution ---/ci---
198 lines
6.6 KiB
YAML
198 lines
6.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.
|
|
|
|
name: ci
|
|
|
|
on:
|
|
push:
|
|
branches: ["**"]
|
|
pull_request:
|
|
branches: ["**"]
|
|
|
|
env:
|
|
# Pin Node + pnpm versions for reproducibility.
|
|
NODE_VERSION: "20"
|
|
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:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
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
|
|
|
|
- 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
|
|
|
|
- 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: 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.
|
|
DB_MODE: "pg"
|
|
DATABASE_URL: "postgres://coreci_app:coreci_app_ci@localhost:5432/coreci_ci"
|
|
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:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
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
|
|
|
|
- name: [R-009] Setup CI roles (coreci_app NOBYPASSRLS, migrator BYPASSRLS)
|
|
run: |
|
|
psql -h localhost -U postgres -d postgres -f packages/db/scripts/setup-ci-roles.sql
|
|
|
|
- name: [G-022] Run migrations as migrator (BYPASSRLS)
|
|
env:
|
|
DATABASE_URL: "postgres://migrator:migrator_ci@localhost:5432/coreci_ci"
|
|
run: 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 |