name: CI # The checks this repository already had, run on every push. skill-check.mjs is # the substantial one: it loads the real module graph through Vite, so it tests # the pipeline rather than a mock of it. on: push: branches: [main] pull_request: workflow_dispatch: concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: npm - run: npm ci - name: Lint run: npm run lint - name: Checks # Prints "N/M checks passed" and exits non-zero on any failure. The count # is asserted below, because a suite that silently stopped running most # of itself still prints a pass line for whatever did run. run: npm test | tee /tmp/check.log - name: Fail if the suite shrank # A file that stops being reached — an import that throws, a section # quietly skipped — reduces the count without failing anything. The # number going DOWN is the signal; raise the floor when it goes up. run: | python3 - <<'PY' import re, sys log = open('/tmp/check.log').read() m = re.findall(r'(\d+)/(\d+) checks passed', log) if not m: sys.exit("no check count in the output; did the suite run at all?") passed, total = (int(x) for x in m[-1]) print(f"{passed}/{total} checks passed") if passed != total: sys.exit(f"{total - passed} checks failed") FLOOR = 900 if total < FLOOR: sys.exit(f"only {total} checks ran, expected at least {FLOOR} — " "the suite is smaller than it was, which usually means part " "of it stopped being reached rather than being deleted") PY - name: Production build # The build inlines VITE_* at build time and there is no runtime config, # so a bundle built without these calls a relative /api/v1 that nginx # serves as a static file — a login POST then answers 405. Building with # them here is what proves the arguments still reach the bundle. env: VITE_API_BASE_URL: https://mcp.krowforce.com/api/v1 VITE_AGENT_API: https://mcp.krowforce.com/api/v1 run: | npm run build if ! grep -rq "mcp.krowforce.com/api/v1" dist/assets/*.js; then echo "the API origin did not reach the bundle; the build args are not being inlined" exit 1 fi echo "API origin is baked into the bundle" - name: The backend fixture is in step with this seed # seed.json is generated from src/api/seed.js. Only runs where the # backend is checked out beside this repo; says so rather than passing # quietly when it is not. run: | if [ -d ../krow-backend ]; then npm run seed:check else echo "krow-backend is not checked out beside this repo; fixture drift not checked here." echo "The backend's own CI checks it from the other side." fi