Run In Containers¶
English · Русский
Container images are an optional deployment path for isolated CLI and MCP workers. PyPI remains the normal installation path for local Python use.
Release Status¶
Stable 1.6.0 images are published and verified; see the
immutable digests and signatures.
The RC5 container evidence remains bound to RC5.
Select an exact version tag such as
ghcr.io/wa-pis/agent-paranoid-android-cli:1.6.0, then resolve and verify its
immutable digest before use. The stable tag also updates the mutable 1.6, 1
and latest aliases; none provides immutable version identity.
Published Images¶
| Image | Entrypoint | Installed surface |
|---|---|---|
ghcr.io/wa-pis/agent-paranoid-android-cli |
test-data-agent |
Core CSV and JSON workflows |
ghcr.io/wa-pis/agent-paranoid-android-generator-mcp |
test-data-agent-mcp-generator |
Core plus MCP |
ghcr.io/wa-pis/agent-paranoid-android-trino-mcp |
test-data-agent-mcp-trino |
Core, MCP, Trino, and SQLGlot |
Release tags publish linux/amd64 and linux/arm64 manifests. PyArrow is not
installed in these images. Use the PyPI parquet extra when Parquet output is
required.
Pull requests build and run every target on both architectures. ARM64 checks
use QEMU only as CI execution support; the resulting image still reports
arm64 and must pass the same non-root, read-only, network-isolated health
contract as the native AMD64 validation. Both architectures also run actual
installed CLI generation, validation and seeded replay in JSON, CSV and SQL;
generator MCP profiling, inference, generation, validation and export over
stdio; and Trino MCP discovery plus an excluded-catalog refusal before network
access. Evidence records the source commit and image digest. The minimal images
also prove a safe missing-Parquet-extra refusal. Live database acquisition is a
separate disposable-database campaign, not a health-check claim.
Build Locally¶
Build only the target you need:
docker build --target cli -t agent-paranoid-android:cli .
docker build --target generator-mcp -t agent-paranoid-android:generator-mcp .
docker build --target trino-mcp -t agent-paranoid-android:trino-mcp .
The Dockerfile uses digest-pinned Python and uv images, a frozen lockfile, and
separate dependency sets. Final images run as UID/GID 65532 by default.
The shared runtime layer installs fixed Bookworm PCRE2 and Perl packages and
checks their versions during the build. Perl remains a Debian essential package;
image scans continue to block fixable High and Critical findings.
Prepare Compose¶
Create writable workspace and audit folders plus a private audit key file:
umask 077
mkdir -p workspace audit/generator audit/trino secrets
openssl rand -base64 32 > secrets/generator_audit_hmac_key
openssl rand -base64 32 > secrets/trino_audit_hmac_key
chmod 600 secrets/generator_audit_hmac_key secrets/trino_audit_hmac_key
export CONTAINER_UID="$(id -u)"
export CONTAINER_GID="$(id -g)"
CONTAINER_UID and CONTAINER_GID must remain non-zero. They let the
non-root process write to bind-mounted host folders on Linux. Never commit the
secrets, audit, or workspace folders.
Build the Compose targets from the current checkout:
docker compose build cli generator-mcp trino-mcp
docker compose run --rm cli doctor --skip-smoke
The Compose contract applies a read-only root filesystem, drops all
capabilities, enables no-new-privileges, limits CPU, memory, processes, and
temporary storage, and publishes no ports.
Generator MCP¶
The generator receives only /workspace and /audit; it has no network:
docker compose run --rm -T generator-mcp
Set TEST_DATA_AGENT_MCP_MAX_INVOCATION_SECONDS in the shell or Compose .env
file before starting generator MCP to configure its invocation deadline. The
default is 120 seconds; finite positive values are required. Independent generation,
profiling, transformation and container memory limits still apply.
An MCP client can launch that command directly. Use an absolute Compose path:
{
"mcpServers": {
"test-data-generator": {
"command": "docker",
"args": [
"compose",
"-f",
"/absolute/path/agent-paranoid-android/compose.yaml",
"run",
"--rm",
"-T",
"generator-mcp"
]
}
}
}
The client receives MCP messages over stdio. There is intentionally no exposed HTTP port.
Trino MCP¶
Set an HTTPS endpoint and narrow allowlists before starting the Trino worker:
export TRINO_HOST=trino.example.internal
export TRINO_PORT=443
export TRINO_USER=test_data_agent
export TRINO_ALLOWED_CATALOGS=iceberg
export TRINO_ALLOWED_SCHEMAS=dev,staging
docker compose run --rm -T trino-mcp
Missing host or allowlists fail before the server starts. The Trino service has network access but receives no generator workspace mount. The Compose example does not enable unrestricted access, plain HTTP, or the optional raw-SQL tool.
Audit Secret¶
Compose mounts separate generator and Trino audit keys below /run/secrets.
Keys are not stored in image metadata or process environment. The application
rejects a secret file that is empty, oversized, writable by another user,
linked, or configured together with TEST_DATA_AGENT_AUDIT_HMAC_KEY.
The services also use separate host directories and logs:
audit/generator/generator.jsonl and audit/trino/trino.jsonl. A compromise of
one worker therefore does not grant the key or writable log mount of the other.
Stop the corresponding writer before rotating either file. See
MCP Audit Logging.
Verify A Published Image¶
Use the immutable digest shown by GHCR rather than relying on a mutable tag:
IMAGE=ghcr.io/wa-pis/agent-paranoid-android-generator-mcp
DIGEST=sha256:replace-with-published-digest
cosign verify \
--certificate-identity-regexp \
'^https://github.com/wa-pis/agent-paranoid-android/.github/workflows/containers.yml@refs/tags/v[0-9].*$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"${IMAGE}@${DIGEST}"
gh attestation verify "oci://${IMAGE}@${DIGEST}" \
--repo wa-pis/agent-paranoid-android
docker buildx imagetools inspect "${IMAGE}@${DIGEST}" \
--format '{{ json .SBOM }}'
The release workflow signs the multi-platform manifest digest with a short-lived GitHub OIDC identity and publishes BuildKit SBOM and provenance attestations. No Cosign private key is stored in the repository.
Pull-request CI also scans every native container target for fixable High and Critical operating-system and Python-package vulnerabilities. A finding at either severity blocks publication through the container validation gate. Unfixed upstream findings remain visible in the scan output and must be reviewed separately during release-candidate security review.
Health Semantics¶
The image health command performs only local checks: non-root execution, expected dependencies, workspace access, Trino safety configuration, and audit configuration. It never connects to Trino or reads a dataset. Because MCP uses stdio, container liveness is also represented by the MCP process itself.