# The agents as container images, one each (Development Plan ยง3; M1.5 # nisse-dev, M7.6 nisse-review, X4). # # Each is stateless, runs as its own user, and keeps its state in a volume # (/var/lib/); its configuration is mounted read-only # (/etc//.yaml) and its secrets come as environment variables # (docker --env-file). nisse-dev's SSH and deploy keys are mounted read-only # wherever its configuration says; it runs no model-chosen command here # (L13): those go to build VMs over SSH. nisse-review needs only git, for # its read-only clones, kept in its volume (scratch/) between restarts. # # docker build -t nisse-dev . nisse-dev # docker build --target review -t nisse-review . nisse-review # docker build --target test -t nisse-dev:test . plus the tests, for # scripts/e2e.sh --image # docker build --target test --build-arg TEST_BASE= -t . # the tests over another image: nisse-review's (TEST_BASE=review), or # a release as published (M1.5, M7.6 acceptance) # What the test stage stacks on: this build's agent, or a published image. ARG TEST_BASE=runtime # The workspace's source, from which each agent's environment is installed. FROM python:3.12-slim AS source COPY --from=ghcr.io/astral-sh/uv:0.12.10 /uv /usr/local/bin/uv ENV UV_PROJECT_ENVIRONMENT=/opt/nisse UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy WORKDIR /src COPY pyproject.toml uv.lock ./ COPY nisse-core nisse-core COPY nisse-dev nisse-dev COPY nisse-ops nisse-ops COPY nisse-review nisse-review # nisse-dev and what it needs, installed (not editable): the source tree # isn't part of the image. FROM source AS build RUN uv sync --frozen --no-dev --package nisse-dev --no-editable # nisse-review and what it needs, in an environment of its own. FROM source AS build-review RUN uv sync --frozen --no-dev --package nisse-review --no-editable FROM python:3.12-slim AS review ARG VERSION=dev LABEL org.opencontainers.image.title=nisse-review org.opencontainers.image.version=$VERSION RUN apt-get update \ && apt-get install -y --no-install-recommends git \ && rm -rf /var/lib/apt/lists/* \ && useradd --create-home --uid 10002 nisse-review \ && mkdir -p /var/lib/nisse-review /etc/nisse-review \ && chown nisse-review /var/lib/nisse-review COPY --from=build-review /opt/nisse /opt/nisse ENV PATH=/opt/nisse/bin:$PATH \ NISSE_CONFIG=/etc/nisse-review/nisse-review.yaml \ NISSE_ENV=/run/nisse-review/.env VOLUME /var/lib/nisse-review USER nisse-review ENTRYPOINT ["nisse-review"] FROM python:3.12-slim AS runtime ARG VERSION=dev LABEL org.opencontainers.image.title=nisse-dev org.opencontainers.image.version=$VERSION RUN apt-get update \ && apt-get install -y --no-install-recommends openssh-client \ && rm -rf /var/lib/apt/lists/* \ && useradd --create-home --uid 10001 nisse \ && mkdir -p /var/lib/nisse-dev /etc/nisse-dev \ && chown nisse /var/lib/nisse-dev COPY --from=build /opt/nisse /opt/nisse ENV PATH=/opt/nisse/bin:$PATH \ NISSE_CONFIG=/etc/nisse-dev/nisse-dev.yaml \ NISSE_ENV=/run/nisse-dev/.env VOLUME /var/lib/nisse-dev USER nisse ENTRYPOINT ["nisse-dev"] # The tests over an image's own package (this build's, or a published one, # TEST_BASE): only the test tools are added, never the agent reinstalled, so # the end-to-end suite runs against what was built, not the source beside it. # The suite's own code imports every agent's package (nisse-dev's config, # for one), so a package the base lacks is added without its dependencies: # what the image installed stays as it was. FROM ${TEST_BASE} AS test USER root RUN apt-get update \ && apt-get install -y --no-install-recommends git openssh-server \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /run/sshd COPY --from=build /usr/local/bin/uv /usr/local/bin/uv WORKDIR /src COPY pyproject.toml uv.lock ./ COPY nisse-core nisse-core COPY nisse-dev nisse-dev COPY nisse-ops nisse-ops COPY nisse-review nisse-review COPY tests tests COPY scripts scripts COPY conftest.py ./ ENV UV_PROJECT_ENVIRONMENT=/opt/nisse UV_NO_SYNC=1 RUN uv export --frozen --only-group dev --no-hashes --no-emit-project > /tmp/dev.txt \ && uv pip install --quiet --python /opt/nisse/bin/python -r /tmp/dev.txt \ && for package in nisse_dev nisse_review; do \ /opt/nisse/bin/python -c "import $package" 2>/dev/null \ || uv pip install --quiet --no-deps --python /opt/nisse/bin/python \ "./$(echo "$package" | tr _ -)"; \ done ENTRYPOINT [] # The default target: the agent itself. FROM runtime AS agent