# Worker image for mcpwatchman scanners (scaffold). See ADR-002 for the tool stack.
#
# The production image also installs osv-scanner (a Go binary) and pins the base
# by SHA digest; this scaffold installs the Python worker deps only.
FROM python:3.12-slim AS base

# Scans run as a non-root user (uid 1000) per the sandboxing posture.
RUN useradd --create-home --uid 1000 scanner

# git is REQUIRED, not optional: `scanner/source.py` clones GitHub and GitLab
# sources, and `python:3.12-slim` does not ship it — without this every git-
# sourced scan died on a missing binary. ca-certificates so the clone can verify
# TLS. Removed from the apt lists in the same layer to keep the image small.
RUN apt-get update \
 && apt-get install -y --no-install-recommends git ca-certificates \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /app
# Hash-locked, so the image runs the semgrep and dependencies CI tested, not
# whatever resolves on the day it is built; the project itself installs with
# --no-deps and builds with the locked hatchling rather than a fresh one.
# One invocation, so a pin the two files disagree on fails the build instead of
# the second file silently replacing the first's.
COPY requirements ./requirements
RUN pip install --no-cache-dir --require-hashes \
      -r requirements/workers.txt -r requirements/build.txt
COPY pyproject.toml README.md ./
COPY src ./src
# REQUIRED, and its absence is a BUILD failure rather than a runtime one.
# `pyproject.toml` force-includes `rules/` into the wheel so an installed
# scanner can find its ruleset; hatchling RAISES `Forced include not found`
# when the source is missing from the build context, so omitting this line
# does not degrade the image — it stops the image existing. Measured by
# reproducing this exact context.
COPY rules ./rules
RUN pip install --no-cache-dir --no-deps --no-build-isolation .

USER scanner
