Files
plex-playlist/docs/DEPLOYABLE_RUNTIME_CONTRACT.md
Xlorep DarkHelm c7540e97ad
All checks were successful
CICD Start / Sanity and Base Decision (push) Successful in 17s
feat(ci): enforce runtime-validation image separation (#69)
## Summary

Implements issue #59 by enforcing a hard boundary between CI validation tooling and deployable runtime images.

This PR:

- Adds automated deployable-runtime boundary checks in CI.
- Verifies deployable backend/frontend artifacts are free of CI/development tooling.
- Documents runtime-vs-validation ownership and enforcement behavior.

## What Changed

### CI workflow enforcement

- Updated `.gitea/workflows/docker-build-main.yaml` to:
  - Checkout additional verification inputs (`Dockerfile.backend`, `Dockerfile.frontend`, scripts, backend/frontend directories).
  - Run `scripts/check-dockerfile-boundaries.sh`.
  - Build deployable runtime images (`Dockerfile.backend`, `Dockerfile.frontend --target production`).
  - Run `scripts/verify-deployable-image-purity.sh` against both images before publishing CICD image.

- Updated `.gitea/workflows/cicd-checks.yaml` to add:
  - `dockerfile-boundary-check` job.
  - Boundary validation execution inside the CICD validation image.

### New enforcement scripts

- Added `scripts/check-dockerfile-boundaries.sh`:
  - Ensures deployable Dockerfiles do **not** reference CICD image paths (`cicd-base`, `CICD_BASE_IMAGE`, `Dockerfile.cicd*`, etc.).
  - Ensures deployable Dockerfiles do **not** include disallowed CI-only tooling tokens.
  - Enforces runtime base expectations:
    - Backend: `python:3.14-slim`
    - Frontend production target: `nginx:alpine`

- Added `scripts/verify-deployable-image-purity.sh`:
  - Baseline binary checks for disallowed tooling.
  - Backend-specific deep checks:
    - Python module import probes for disallowed CI/dev modules.
    - `pip show` package metadata checks for disallowed CI/dev packages.
  - Frontend-specific deep checks:
    - OS package metadata checks (`apk`/`dpkg` when available) for disallowed runtime leaks.
    - Directory-based checks for development package trees (`node_modules`, `.venv`, `site-packages`, `dist-packages` in sensitive paths).

## Documentation updates

- Updated `docs/DEVELOPMENT.md`:
  - Clarifies runtime-vs-validation enforcement and where checks run.
  - Notes purity checks include binaries and metadata artifacts.

- Updated `docs/CICD_MULTI_STAGE_BUILD.md`:
  - Adds explicit “Runtime Boundary Enforcement” section.
  - Documents metadata-level purity probes.

- Updated `docs/DEPLOYABLE_RUNTIME_CONTRACT.md`:
  - Replaces future-only language with current enforcement hooks.
  - Documents binary + metadata-level purity enforcement.

## Acceptance Criteria Mapping

1. **Deployable backend/frontend image paths do not require CI-only tool installation**
   - Enforced by:
     - `scripts/check-dockerfile-boundaries.sh`
     - `scripts/verify-deployable-image-purity.sh`
     - `docker-build-main.yaml` pre-publish gates

2. **Checks and tests execute in dedicated validation environment(s)**
   - Reinforced by:
     - `cicd-checks.yaml` boundary-check job running in CICD validation image
     - Existing check/test workflow usage of CICD image

3. **Workflow docs identify runtime vs validation concerns**
   - Addressed via updates to:
     - `docs/DEVELOPMENT.md`
     - `docs/CICD_MULTI_STAGE_BUILD.md`
     - `docs/DEPLOYABLE_RUNTIME_CONTRACT.md`

## Scope / Non-Goals

- Included:
  - Structural separation enforcement
  - Workflow-level guardrails
  - Documentation clarity and traceability

- Not included:
  - Full staging deployment wiring
  - Security policy redesign

## Notes for Reviewers

- Main enforcement path is in `docker-build-main.yaml` before CICD image publish.
- New scripts are intentionally fail-fast and policy-oriented.
- Existing deployable Dockerfiles currently satisfy the new gates.

Co-authored-by: copilotcoder <copilotcoder@darkhelm.org>
Reviewed-on: #69
2026-06-22 12:45:20 -04:00

6.0 KiB

Deployable Runtime Image Contract

Purpose

Define the minimum deployable runtime contract for backend and frontend images. This document is the canonical source for what must be present, what must not be present, and what behavior deployment environments can rely on.

This contract supports issue PP-58 and establishes a baseline for future automation work under epic #66.

Scope

Included:

  • Backend deployable runtime image requirements.
  • Frontend deployable runtime image requirements.
  • Runtime entrypoint, ports, health behavior, startup behavior, and environment contracts.
  • Explicitly disallowed non-runtime tooling classes in deployable images.

Excluded:

  • CI workflow rewiring.
  • Test execution redesign.
  • New runtime hardening implementations not required to define contract.

Backend Runtime Contract

Runtime Artifact Definition

  • Container build source: Dockerfile.backend.
  • Runtime base image: python:3.14-slim.
  • Runtime process: uvicorn main:app --host 0.0.0.0 --port 8000.
  • Exposed runtime port: 8000.

Required Runtime Dependencies

The runtime artifact must include versions compatible with:

  • fastapi==0.120.2
  • psycopg==3.2.12
  • sqlalchemy==2.0.44
  • uvicorn==0.38.0

The lockfile in backend/uv.lock is the dependency source of truth.

Required Runtime Environment Contract

  • DATABASE_URL is required.
    • Accepted form: postgresql://... or SQLAlchemy async form.
    • Runtime normalization to async psycopg dialect is performed in backend/src/backend/database.py.
  • BACKEND_REQUIRED_PYTHON is optional and defaults to 3.14.

Backend Health and Startup Behavior

  • Startup must fail fast if runtime policy checks fail.
    • Source: backend/src/backend/main.py lifecycle (lifespan) validation.
  • Health endpoint contract:
    • GET /health returns 200 with {"status":"healthy","database":"connected"} when database probe succeeds.
    • GET /health returns 503 with {"status":"unhealthy","database":"disconnected"} when probe fails.
  • Compatibility diagnostics endpoint:
    • GET /compatibility reports policy and package compatibility status.

Backend Runtime Checklist

  • Runtime image built from Dockerfile.backend.
  • Runtime process is uvicorn serving main:app on 0.0.0.0:8000.
  • DATABASE_URL is set in deployment runtime.
  • GET /health behavior matches contract.
  • Startup fails on runtime policy mismatch.
  • Deployable artifact excludes CI-only and test-only tooling classes.

Frontend Runtime Contract

Frontend Runtime Artifact Definition

  • Container build source: Dockerfile.frontend (target production).
  • Runtime base image: nginx:alpine.
  • Runtime process: nginx -g "daemon off;".
  • Exposed runtime port: 80.
  • Runtime artifact payload: static assets from /app/dist copied to /usr/share/nginx/html.

Frontend Runtime Entry and Routing Contract

  • Nginx configuration source: frontend/nginx.conf.
  • SPA routing behavior must use fallback to index.html for unknown routes.
  • API requests under /api/ are proxied to backend service endpoint http://backend:8000/ in compose deployments.

Frontend Health and Startup Behavior

  • Startup expectation: nginx process starts and serves static assets on port 80.
  • Runtime health expectation for deployment checks:
    • GET / should return 200 and serve frontend entry document.
  • API proxy readiness is dependent on backend runtime availability.

Frontend Runtime Environment Contract

  • No required runtime environment variables are defined for nginx static serving.
  • Build-time frontend mode is production-oriented and not part of runtime env contract.

Frontend Runtime Checklist

  • Runtime image built from Dockerfile.frontend production target.
  • Runtime process is nginx serving on port 80.
  • SPA route fallback behavior is present.
  • /api/ proxy behavior aligns with backend service wiring.
  • Deployable artifact excludes CI-only and test-only tooling classes.

Disallowed Tooling Classes in Deployable Runtime Images

Deployable runtime artifacts must not include tooling classes that are only needed for CI, validation, or local development workflows.

Disallowed classes:

  • Linters and formatters (example: ruff, eslint, prettier).
  • Type checking and static analysis tooling (example: pyright, vue-tsc).
  • Test frameworks and test drivers (example: pytest, vitest, playwright).
  • Browser test binaries and CI runner helper tools.
  • Build-only package managers and build toolchains not needed at runtime.

Note:

  • Multi-stage builds may use these tools in build stages.
  • These tools must not be required by or present in final deployable runtime image layers.

Acceptance Criteria Traceability (PP-58)

  1. Backend runtime requirements are documented and approved.
    • Covered by: "Backend Runtime Contract" and backend checklist.
  2. Frontend runtime requirements are documented and approved.
    • Covered by: "Frontend Runtime Contract" and frontend checklist.
  3. Runtime contracts include health endpoint expectations and startup behavior.
    • Covered by: backend health/startup section and frontend health/startup section.
  4. Non-runtime tool classes are explicitly excluded from deployable image definition.
    • Covered by: "Disallowed Tooling Classes in Deployable Runtime Images".

Enforcement Hooks

Current enforcement implemented in CI:

  • Dockerfile target boundary checks:
    • Script: scripts/check-dockerfile-boundaries.sh
    • Workflow: .gitea/workflows/docker-build-main.yaml
  • Deployable runtime image purity checks:
    • Script: scripts/verify-deployable-image-purity.sh
    • Workflow: .gitea/workflows/docker-build-main.yaml
    • Checks include binary presence and profile-specific package metadata probes to detect CI/development tooling leakage.

Future follow-up automation under epic #66 may expand this with:

  • Contract tests that assert documented health/startup behavior.
  • Additional policy checks for drift detection and broader runtime compliance.