Files
curriculum-project-hub/.gitea/workflows/hub-check.yml
T

159 lines
5.7 KiB
YAML

name: hub check
# Builds, type-checks, and tests the Hub TS package under hub/.
# The Hub is the Feishu-group collaboration + agent runtime half.
# This is an INTERNAL gate on the Hub's own
# health, like checker-check is for the Rust half.
on:
push:
pull_request:
workflow_dispatch:
jobs:
hub-check:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: paradigm
POSTGRES_PASSWORD: paradigm
POSTGRES_DB: cph_hub_test
# Avoid host-port binds: concurrent hub-check jobs on the shared
# runner raced on published 5432/15432 ("port is already allocated").
# Reach the service by Docker DNS name from the job container instead.
options: >-
--health-cmd "pg_isready -U paradigm -d cph_hub_test"
--health-interval 5s
--health-timeout 5s
--health-retries 20
defaults:
run:
working-directory: hub
steps:
- uses: actions/checkout@v5
- name: Install Rust toolchain (for cph binary)
uses: dtolnay/rust-toolchain@1.92.0
- name: Cache cargo registry + build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-hub-check-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-hub-check-${{ runner.os }}-
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
cache-dependency-path: |
hub/package-lock.json
hub/admin-web/package-lock.json
- name: Install dependencies
run: |
npm ci
npm ci --prefix admin-web
- name: Audit production Node dependencies
run: npm run audit:production
- name: Install Linux sandbox dependency
run: sudo apt-get update && sudo apt-get install --yes bubblewrap socat
- name: Wait for Postgres
run: |
node <<'NODE'
const net = require("node:net");
const deadline = Date.now() + 60000;
const host = process.env.HUB_CHECK_PG_HOST || "postgres";
const port = Number(process.env.HUB_CHECK_PG_PORT || "5432");
function tryConnect() {
const socket = net.createConnection({ host, port });
socket.once("connect", () => {
socket.end();
process.exit(0);
});
socket.once("error", () => {
socket.destroy();
if (Date.now() > deadline) {
console.error(`Postgres did not become reachable at ${host}:${port}`);
process.exit(1);
}
setTimeout(tryConnect, 1000);
});
}
tryConnect();
NODE
# Prisma client must be generated before tsc can check imports from
# @prisma/client. Stub DATABASE_URL so prisma generate works.
- name: Generate Prisma client
run: DATABASE_URL="postgresql://stub:stub@127.0.0.1:5432/stub" npx prisma generate --schema prisma/schema.prisma
- name: Type-check
run: npx tsc -p tsconfig.json --noEmit
- name: Build
run: npm run build
- name: Validate Prisma schema
run: DATABASE_URL="postgresql://stub:stub@127.0.0.1:5432/stub" npx prisma validate --schema prisma/schema.prisma
- name: Install cph binary
run: |
cd ..
cargo install --path crates/cph-cli --locked
# Make cph available to the unprivileged sandbox user below.
sudo install -m 0755 "$HOME/.cargo/bin/cph" /usr/local/bin/cph
- name: Prove real Claude SDK Bash sandbox boundary
run: |
set -euo pipefail
# The proof requires uid>0, CapEff=0, and NoNewPrivs=1. Gitea act often
# runs as root; switch to cphci then clear caps under no_new_privs.
if ! id cphci >/dev/null 2>&1; then
useradd --create-home --shell /bin/bash cphci
fi
install -d -o cphci -g cphci -m 0700 /w/t
REPO_ROOT="$(cd .. && pwd)"
NODE_BIN_DIR="$(dirname "$(command -v node)")"
NPX_BIN="$(command -v npx)"
chown -R cphci:cphci "$REPO_ROOT/hub"
runuser -u cphci -- env \
HOME="/home/cphci" \
PATH="$NODE_BIN_DIR:/usr/local/bin:/usr/bin:/bin" \
CPH_SANDBOX_TEST_ROOT=/w/t \
/usr/bin/setpriv \
--inh-caps=-all --bounding-set=-all --no-new-privs \
bash -lc "cd '$REPO_ROOT/hub' && '$NPX_BIN' vitest run test/integration/agent-sandbox-linux.test.ts"
- name: Run unit tests
run: npx vitest run test/unit
# Integration tests need PostgreSQL + cph. cph is installed above.
# PostgreSQL is the job service container reachable as `postgres`.
- name: Run integration tests (mock provider, real prisma + cph)
run: |
npx prisma migrate deploy --schema prisma/schema.prisma
npx vitest run test/integration \
--exclude test/integration/real-model.test.ts \
--exclude test/integration/agent-sandbox-linux.test.ts
env:
DATABASE_URL: postgresql://paradigm:paradigm@postgres:5432/cph_hub_test
# Real-model tests are opt-in: set RUN_REAL_MODEL_TESTS=true and provide
# OPENROUTER_API_KEY when a branch should hit live OpenRouter.
- name: Run real-model integration tests (optional, needs secret)
run: npx vitest run test/integration/real-model.test.ts
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
RUN_REAL_MODEL_TESTS: ${{ vars.RUN_REAL_MODEL_TESTS }}