API image execution boundary
Status (2026-09-04): frozen by tests/test_api_image_boundary.py; the slim non-root API image ships in 2.2.0, the narrow Docker-staging service is a 2.3.0 design item.
The 2.2.0 API-image split must preserve the behavior the control-plane process actually owns. A source audit found a wider boundary than the original release plan assumed.
Because the final stage starts again from the Playwright base, nothing from the scanner runtime's
ENV crosses into the API image. The release identity (SCANNER_VERSION,
SHAKERSCAN_BUILD_VERSION, SHAKERSCAN_SOURCE_REVISION) is therefore passed as build arguments by
every build site and verified inside the Dockerfile against the release manifest copied from the
runtime stage, so the API can never carry a different identity than the workers.
The API process currently executes:
- Playwright/Chromium through the Python library for interactive sessions and AI Gate widget probes;
- Docker Engine API calls over
/var/run/docker.sockfor worker inventory and lifecycle; - the pinned Docker CLI for Model Intake guest-image staging;
- a fixed
curlargv for ASM soft-404 and reachability probes; and - opt-in, bounded version commands for Command Arsenal tools and local planner agents.
Worker-only process execution remains in api/worker.py; the Gungnir executable belongs to the
Gungnir worker entrypoint; Firecracker host commands belong to the opt-in Model Intake runner
entrypoint. None of those is API-process authority merely because the source is copied into a
shared image layer.
tests/test_api_image_boundary.py freezes the modules that may create subprocesses and rejects a
new direct Go-scanner path in the API process. Before the API image can drop the scanner toolchain,
ASM reachability must move to an in-process target-bound HTTP adapter and version probing must
become worker-reported metadata (or be explicitly retired). Model Intake staging and worker
inventory still require the Docker boundary until the planned narrow internal service replaces it.