build: the gate is scripts/check.sh, and CI goes

The Gitea Actions gate repeated, after the merge, what a release already runs
before it, and its runner shared the git host's container: one run there
starved Gitea of memory until it stopped answering. The lanes now live in
scripts/check.sh, run the same by the release dispatcher and by hand, and the
gate-contract test holds its lines (the ruff and pip-audit checks read it
instead of the workflow). The two audits only CI ran join the gate: pip-audit
over the lock (pinned in the test image, blocking at any severity) and npm
audit of the production dependencies. The engine contracts drop the CI
containers; the register records that pushes have no server-side gate.
This commit is contained in:
2026-10-04 06:20:58 +02:00
parent 0528b35f2d
commit cc414de952
14 changed files with 234 additions and 253 deletions
+71 -62
View File
@@ -2222,68 +2222,6 @@
}
},
"lanes": {
".gitea/workflows/check.yml": [
"name: gate",
"on:",
" push:",
" branches: [\"**\"]",
" pull_request:",
"jobs:",
" frontend:",
" runs-on: ubuntu-latest",
" container: node:24-bookworm",
" defaults:",
" run:",
" working-directory: frontend",
" steps:",
" - uses: actions/checkout@v4",
" - run: npm ci",
" - run: npm run typecheck",
" - run: npm run lint",
" - run: npm run format:check",
" - run: npm run knip",
" - run: npm run test",
" - run: npx vite build",
" - run: npm audit --omit=dev --audit-level=high",
" backend:",
" runs-on: ubuntu-latest",
" container: nikolaik/python-nodejs:python3.12-nodejs24",
" services:",
" postgres:",
" image: postgres:16-alpine",
" env:",
" POSTGRES_USER: siftlode",
" POSTGRES_PASSWORD: siftlode",
" POSTGRES_DB: siftlode_test",
" options: >-",
" --health-cmd \"pg_isready -U siftlode -d siftlode_test\"",
" --health-interval 2s",
" --health-timeout 3s",
" --health-retries 30",
" env:",
" DATABASE_URL: postgresql+psycopg://siftlode:siftlode@postgres:5432/siftlode_test",
" SIFTLODE_TEST_REQUIRE_DB: \"1\"",
" steps:",
" - uses: actions/checkout@v4",
" - run: apt-get update && apt-get install -y --no-install-recommends ffmpeg postgresql-client",
" - name: Wait for Postgres",
" run: until pg_isready -h postgres -U siftlode -d siftlode_test; do sleep 1; done",
" - run: pip install --no-cache-dir -r backend/requirements.lock -r backend/requirements-dev.txt",
" - name: ruff",
" run: python -m ruff check --config backend/ruff.toml backend scripts",
" - name: ruff format --check",
" run: python -m ruff format --check --config backend/ruff.toml backend scripts",
" - name: basedpyright",
" run: python -m basedpyright --project pyrightconfig.json",
" working-directory: backend",
" - name: basedpyright baseline is committed",
" run: git diff --exit-code -- backend/.basedpyright/baseline.json",
" - name: pytest",
" run: python -m pytest",
" working-directory: backend",
" - name: pip-audit",
" run: pip install --no-cache-dir pip-audit && pip-audit -r backend/requirements.lock"
],
"backend/Dockerfile.test": [
"FROM python:3.12-slim",
"WORKDIR /app",
@@ -2366,6 +2304,77 @@
" },",
" },",
"});"
],
"scripts/check.sh": [
"set -u",
"cd \"$(dirname \"$0\")/..\" || exit 2",
"mode=\"${1:-all}\"",
"case \"$mode\" in all | lint) ;; *) echo \"usage: scripts/check.sh [lint]\" >&2; exit 2 ;; esac",
"export MSYS_NO_PATHCONV=1 # Git Bash: do not rewrite the in-container paths below",
"TESTCOMPOSE=backend/docker-compose.test.yml",
"failed=()",
"lane() { # lane <name> <command…> — run it, remember a failure, never stop",
" local name=\"$1\"",
" shift",
" echo \">> $name…\"",
" \"$@\" || failed+=(\"$name\")",
"}",
"ruff_pinned() {",
" local pin host",
" pin=\"$(sed -n 's/^ruff==\\([0-9.]*\\).*/\\1/p' backend/requirements-dev.txt)\"",
" host=\"$(python -m ruff --version 2>/dev/null | awk '{print $2}')\"",
" [ -n \"$pin\" ] && [ \"$host\" = \"$pin\" ] && return 0",
" echo \"ruff ${host:-missing} on the host, ${pin:-nothing} pinned — python -m pip install ruff==$pin\" >&2",
" return 1",
"}",
"ruff_check() { ruff_pinned && python -m ruff check --config backend/ruff.toml backend scripts; }",
"ruff_format() { ruff_pinned && python -m ruff format --check --config backend/ruff.toml backend scripts; }",
"basedpyright() {",
" local before",
" before=\"$(git hash-object backend/.basedpyright/baseline.json)\"",
" docker compose -f \"$TESTCOMPOSE\" run --rm --no-deps --build test \\",
" python -m basedpyright --project pyrightconfig.json || return 1",
" if [ \"$(git hash-object backend/.basedpyright/baseline.json)\" != \"$before\" ]; then",
" echo \"this run rewrote backend/.basedpyright/baseline.json (errors were fixed) — commit it\" >&2",
" return 1",
" fi",
" git diff HEAD --quiet -- backend/.basedpyright/baseline.json && return 0",
" echo \"backend/.basedpyright/baseline.json is uncommitted — commit it\" >&2",
" return 1",
"}",
"frontend() { (cd frontend && \"$@\"); }",
"lane \"ruff\" ruff_check",
"lane \"ruff format --check\" ruff_format",
"lane \"basedpyright (new errors only)\" basedpyright",
"lane \"lock check (frontend/node_modules == package-lock.json)\" node scripts/check-node-modules.mjs",
"lane \"tsc (src + configs + e2e)\" frontend npm run --silent typecheck",
"lane \"eslint (warnings fail too)\" frontend npm run --silent lint",
"lane \"prettier --check\" frontend npm run --silent format:check",
"lane \"knip (unused, and unused by what ships)\" frontend npm run --silent knip",
"pytest_lane() { # the full suite against a throwaway Postgres; --pull keeps the base image current",
" docker compose -f \"$TESTCOMPOSE\" build --pull -q test || return 1",
" local rc=0",
" docker compose -f \"$TESTCOMPOSE\" up --build --abort-on-container-exit --exit-code-from test || rc=1",
" docker compose -f \"$TESTCOMPOSE\" down -v >/dev/null 2>&1",
" return $rc",
"}",
"pip_audit() {",
" docker compose -f \"$TESTCOMPOSE\" run --rm --no-deps test \\",
" pip-audit -r requirements.lock --no-deps --disable-pip",
"}",
"if [ \"$mode\" = all ]; then",
" lane \"vitest (+ coverage report)\" frontend npm run --silent test -- --coverage",
" lane \"vite build\" frontend npx vite build --logLevel warn",
" lane \"pytest (pure-logic + DB lane)\" pytest_lane",
" lane \"pip-audit (backend lock)\" pip_audit",
" lane \"npm audit (production dependencies)\" frontend npm audit --omit=dev --audit-level=high",
"fi",
"if [ ${#failed[@]} -eq 0 ]; then",
" echo \">> gate ($mode): green ✓\"",
" exit 0",
"fi",
"echo \">> gate ($mode): RED — ${failed[*]}\" >&2",
"exit 1"
]
}
}