Files
geointel/docs/CI_SUPPLY_CHAIN.md
T
Codex 6a22fcd1f8
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s
Remediate RC6 container scan findings
2026-07-18 04:28:46 +02:00

4.6 KiB

CI and supply-chain release gates

GeoIntel uses the same release gates in Gitea Actions and GitHub Actions:

  • .gitea/workflows/release-gates.yml
  • .github/workflows/release-gates.yml

Gitea is the operational source-control platform. The GitHub workflow is kept equivalent so a mirror or external review does not receive a weaker gate.

Runner requirements

The ubuntu-latest runner must provide:

  • outbound HTTPS access to PyPI, npm, Docker Hub and vulnerability databases;
  • Python 3.11 and Node 20 through the official setup actions;
  • Bash and Docker with Compose v2;
  • permission to build images and mount /var/run/docker.sock;
  • sufficient disk for the all-in-one GIS image and scanner databases.

The container job builds the GIS release variant only. PyTorch and Ultralytics remain in the optional ai extra and in the explicit AI image variant; CI does not silently make them base dependencies.

Quality gate

The quality job installs:

python -m pip install --require-hashes -r backend/requirements-ci.lock
python -m pip install --no-deps -e backend
cd frontend && npm ci

It then validates the lock policy and runs the complete readiness script. The readiness script covers backend compile/tests, contract audits, Alembic single-head, frontend typecheck/build and release-script syntax. CI also renders offline migration SQL and resolved Compose configuration as retained evidence.

Reproducible Python lock

backend/requirements-runtime.lock and backend/requirements-ci.lock are generated in a digest-pinned Linux Python 3.11 container. The runtime lock contains base and GIS packages used by the release image. The CI lock adds developer/test dependencies. Both use package hashes and deliberately exclude the optional AI dependency group.

Regenerate after changing relevant pyproject.toml dependencies:

bash scripts/generate_python_lock.sh
python scripts/verify_python_lock.py

The all-in-one frontend build uses npm ci; the non-AI runtime installs the hashed runtime lock. The optional AI image additionally uses explicit PyTorch, torchvision and Ultralytics build-argument versions.

Do not hand-edit dependency versions or hashes in either generated lock. verify_python_lock.py rejects a stale input fingerprint, another Python generation version, unhashed packages, missing direct dependencies and AI packages leaking into the standard CI environment.

Vulnerability policy

The dependency job:

  • fails on any non-excepted vulnerability reported by pip-audit for the complete exact lock without platform-specific re-resolution;
  • fails when npm audit --audit-level=high finds a high or critical frontend dependency vulnerability;
  • publishes both unfiltered and policy-filtered Python JSON reports plus the npm JSON report, including on failure.

The only current Python/container exceptions are the Starlette 2026 advisories recorded in security/pip-audit-exceptions.json. FastAPI 0.139.2 still constrains Starlette below 0.53 while patched releases begin at 1.x. GeoIntel applies request-target, form-content, route-class and Linux-runtime compensating controls. The exception file has a mandatory review date; readiness and CI fail automatically after it expires. New advisories are never auto-ignored. The all-in-one image replaces the Go-based base-image gosu helper with a small setpriv exec wrapper and upgrades packaged setuptools/wheel metadata; these scanner findings are fixed rather than excepted.

The container job builds a non-AI all-in-one image and uses digest-pinned scanner images:

  • Syft 1.44.0 generates an SPDX JSON SBOM;
  • Trivy 0.70.0 generates a complete JSON vulnerability report;
  • fixed high or critical image vulnerabilities fail the gate;
  • unfixed findings remain in the full report and require explicit release review, but do not make a rebuild impossible when no patched package exists.

Run these controls on a Docker-enabled workstation:

docker build \
  -f deploy/unraid/Dockerfile.all-in-one \
  --build-arg GEOINTEL_INSTALL_AI=false \
  --build-arg GEOINTEL_BUILD_SHA=local \
  --build-arg GEOINTEL_BUILD_TIME=local \
  -t geointel-ci:local .
bash scripts/generate_container_sbom.sh geointel-ci:local
bash scripts/scan_container_image.sh geointel-ci:local

Outputs are written below ignored artifacts/; scanner cache is written below ignored .cache/trivy/.

Published evidence

Every workflow run retains:

  • offline Alembic upgrade SQL;
  • resolved Docker Compose configuration;
  • pip-audit and npm-audit JSON;
  • image inspection metadata;
  • SPDX JSON SBOM;
  • complete Trivy JSON report.

No secret or plaintext database credential belongs in these artefacts.