Merge pull request 'chore: docker-based test environment' (#14) from chore/docker-test-env into main

Reviewed-on: #14
Reviewed-by: archeious <archeious@unbiasedgeek.com>
This commit is contained in:
archeious 2026-04-08 21:08:27 +00:00
commit 16d88e951b
5 changed files with 116 additions and 0 deletions

15
.dockerignore Normal file
View file

@ -0,0 +1,15 @@
.git
.gitignore
.venv
docs/wiki
**/__pycache__
**/*.pyc
**/*.pyo
*.egg-info
.pytest_cache
.mypy_cache
.ruff_cache
.coverage
htmlcov
Dockerfile
.dockerignore

24
Dockerfile Normal file
View file

@ -0,0 +1,24 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /app
# Install build deps separately so the layer caches when source changes.
COPY pyproject.toml README.md ./
RUN pip install --upgrade pip
# Copy the project and install editable with dev extras.
COPY cli ./cli
COPY researchers ./researchers
COPY orchestrator ./orchestrator
COPY tests ./tests
RUN pip install -e ".[dev]"
# Trace files land here; mount a volume to persist across runs.
RUN mkdir -p /root/.marchwarden/traces
CMD ["pytest", "-q"]

View file

@ -24,6 +24,20 @@ marchwarden ask "What are ideal crops for a garden in Utah?"
marchwarden replay <trace_id>
```
## Docker test environment
A reproducible container is available for running the test suite and the
CLI without depending on the host's Python install:
```bash
scripts/docker-test.sh build # build the image
scripts/docker-test.sh test # run pytest
scripts/docker-test.sh ask "question" # run `marchwarden ask` end-to-end
# (mounts ~/secrets ro and ~/.marchwarden rw)
scripts/docker-test.sh replay <id> # replay a trace from ~/.marchwarden/traces
scripts/docker-test.sh shell # interactive bash in the container
```
## Documentation
- **[Architecture](https://forgejo.labbity.unbiasedgeek.com/archeious/marchwarden/wiki/Architecture)** — system design, researcher contract, MCP flow

View file

@ -26,6 +26,7 @@ dependencies = [
dev = [
"pytest>=7.0",
"pytest-cov>=4.0",
"pytest-asyncio>=0.21",
"black>=23.0",
"ruff>=0.1.0",
"mypy>=1.0",

62
scripts/docker-test.sh Executable file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Helper for the dockerized test/run environment.
#
# Usage:
# scripts/docker-test.sh build Build the image
# scripts/docker-test.sh test Run pytest in the container
# scripts/docker-test.sh ask "..." Run `marchwarden ask` end-to-end
# (mounts ~/secrets ro and ~/.marchwarden rw)
# scripts/docker-test.sh shell Drop into a bash shell in the container
set -euo pipefail
IMAGE="marchwarden-test"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cmd="${1:-test}"
shift || true
case "$cmd" in
build)
docker build -t "$IMAGE" "$ROOT"
;;
test)
docker run --rm -v "$ROOT:/app" "$IMAGE" pytest -q "$@"
;;
ask)
if [ ! -f "$HOME/secrets" ]; then
echo "error: ~/secrets not found on host" >&2
exit 1
fi
mkdir -p "$HOME/.marchwarden/traces"
docker run --rm -it \
-v "$ROOT:/app" \
-v "$HOME/secrets:/root/secrets:ro" \
-v "$HOME/.marchwarden:/root/.marchwarden" \
"$IMAGE" marchwarden ask "$@"
;;
replay)
mkdir -p "$HOME/.marchwarden/traces"
docker run --rm \
-v "$ROOT:/app" \
-v "$HOME/.marchwarden:/root/.marchwarden" \
"$IMAGE" marchwarden replay "$@"
;;
shell)
docker run --rm -it \
-v "$ROOT:/app" \
-v "$HOME/secrets:/root/secrets:ro" \
-v "$HOME/.marchwarden:/root/.marchwarden" \
"$IMAGE" bash
;;
*)
echo "unknown command: $cmd" >&2
echo "usage: $0 {build|test|ask|replay|shell}" >&2
exit 1
;;
esac