# BlastContain Drill — hardened container image
#
# Production build (assumes blastcontain-core is published to PyPI):
#   podman build -t blastcontain-drill:0.1.0 .
#
# Dev build (sibling blastcontain-core/ source, before PyPI publish):
#   podman build -t blastcontain-drill:0.1.0 -f drill/Containerfile ..
#   (run from blastcontain-oss/ — context is the parent dir containing both
#    core/ and drill/. The Containerfile installs core from local source when
#    present, otherwise resolves it from PyPI.)
#
# Run — black-box mode against a running agent (no egress beyond the target):
#   podman run --rm \
#     -v /path/to/reports:/reports:rw \
#     blastcontain-drill:0.1.0 \
#     --agent-id my-agent --agent-url http://agent:8080 \
#     --report /reports/drill.md --output /reports/drill.json
#
# Run — inprocess cage against a model on the host (LM Studio on :1234):
#   podman run --rm --add-host=host.containers.internal:host-gateway \
#     -v "$PWD/reports:/reports:rw" \
#     blastcontain-drill:0.1.0 \
#     --agent-id my-agent --cage inprocess \
#     --target-base-url http://host.containers.internal:1234/v1 \
#     --target-model "qwen/qwen3-30b-a3b-2507" \
#     --report /reports/drill.md --output /reports/drill.json
#
# (Drill drives a model, so unlike Verify it is not run with --network none.)

# ── Stage 1: build ─────────────────────────────────────────────────────────────
FROM python:3.12-slim AS builder

WORKDIR /build

# Copy drill source (always required). constraints.txt pins every third-party
# dependency (core's cryptography/pyyaml + drill's click/httpx + transitives) to
# the exact tested-good versions, so the published image is reproducible and can't
# silently pull a newer, unaudited release. Regen recipe is in the file header.
COPY drill/pyproject.toml drill/README.md drill/constraints.txt ./
COPY drill/blastcontain_drill/ ./blastcontain_drill/

# Optional: local core source. For dev builds the context is the parent dir
# (blastcontain-oss/) so core/ is present; for prod builds it is absent and
# pip resolves blastcontain-core from PyPI.
COPY core* /build/core_optional/

RUN if [ -d /build/core_optional ] && [ -f /build/core_optional/pyproject.toml ]; then \
        echo "Building blastcontain-core wheel from local source"; \
        pip install --no-cache-dir build && \
        python -m build --wheel /build/core_optional --outdir /build/wheels; \
    fi && \
    FIND_LINKS_ARG="" && \
    if [ -d /build/wheels ]; then FIND_LINKS_ARG="--find-links /build/wheels"; fi && \
    pip install --no-cache-dir --ignore-installed --prefix=/install $FIND_LINKS_ARG --constraint constraints.txt "."

# ── Stage 2: runtime ───────────────────────────────────────────────────────────
FROM python:3.12-slim AS runtime

# Non-root user with no home directory and no login shell.
RUN useradd --system --no-create-home --shell /sbin/nologin --uid 10001 drill

COPY --from=builder /install /usr/local

# Drop any setuid binaries — drill never needs them.
RUN find / -perm /4000 -type f 2>/dev/null | xargs chmod u-s 2>/dev/null || true

USER drill

LABEL org.opencontainers.image.title="blastcontain-drill" \
      org.opencontainers.image.description="Adversarial red-team scanner for AI agents" \
      org.opencontainers.image.version="0.1.0" \
      org.opencontainers.image.licenses="Apache-2.0" \
      org.opencontainers.image.source="https://github.com/gdeudney/blastcontain-oss"

ENTRYPOINT ["blastcontain-drill"]
CMD ["--help"]
