Files
ModelForge/docs/architecture/adr/0046-v1-security-release-gate.md

2.0 KiB

ADR-0046: v1 security release gate

Status

Accepted in M16 on 2026-08-27.

Decision

Treat the security review as a source of build-enforced properties rather than a point-in-time report. Every conclusion the M16 review reached by hand is encoded as a test: no shell execution, no arbitrary execution primitive, subprocess use allowlisted, no command route, AES-256-GCM from a reviewed library with a fresh nonce per chunk and fail-closed decryption, no privileged mode or Docker socket, no floating dependency specifier, datastores bound to loopback, capabilities dropped, and a console image that serves a build rather than a development server.

Publish nothing on a network interface that is not authenticated for it. PostgreSQL, Redis and the operator console default to loopback; the API is published deliberately because every admin route is operator-authenticated.

Inventory what shipped, not what was intended: read the Python SBOM from the built images, bind each image to its source commit, and classify every advisory with evidence rather than counting them.

Consequences

The most serious finding of M16 was configuration, not code: the control-plane database was published on every interface behind a development password, exposing provenance, credential hashes and the audit trail to the LAN. A test now fails if that binding returns.

Encoding review conclusions as tests means M17 cannot quietly reintroduce them while packaging, and a future reviewer inherits the reasoning rather than having to rediscover it.

The cost is friction: adding a subprocess call, a new route segment, or a dependency without a version now requires either a deliberate allowlist change or a failing build. That friction is the point.

Some findings are correctly accepted rather than fixed. pip carried archive-extraction advisories and never runs at runtime, but leaving a known-vulnerable installer in a release image makes every future scan noisier, so the build upgrades it — a cheap fix is preferred to a standing exception even where the risk is not reachable.