name: hub check

# Builds, type-checks, and tests the Hub TS package under hub/.
# The Hub is the Feishu-group collaboration + agent runtime half
# (spec/System implementation). 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
        ports:
          - 5432:5432
        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: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "24"
          cache: npm
          cache-dependency-path: hub/package-lock.json

      - name: Install dependencies
        run: npm ci

      - 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;
          function tryConnect() {
            const socket = net.createConnection({ host: "127.0.0.1", port: 5432 });
            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 127.0.0.1:5432");
                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

      - name: Prove real Claude SDK Bash sandbox boundary
        run: |
          sudo install -d -o "$(id -u)" -g "$(id -g)" -m 0700 /w/t
          CPH_SANDBOX_TEST_ROOT=/w/t \
            /usr/bin/setpriv --no-new-privs \
            npx 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 set up as a service container below.
      - 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@127.0.0.1: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 }}
