This file provides context for AI agents working on this repository. Every project has its own <project>/AGENTS.md with specific details.
A monorepo of Docker container projects for personal infrastructure. Each subdirectory is a self-contained project with its own Dockerfile and typically a ./run script.
| Project | Purpose | Status | Notes |
|---|---|---|---|
goss |
Goss binary built from source | Active | Scratch image; patches CVEs in Go deps; used by other projects |
samba-timemachine |
macOS Time Machine backup server via Samba | Active | Most mature; has goss tests, AGENTS.md; depends on goss |
gam |
Google Workspace CLI (GAM) container | Active | Pinned versions; has goss tests |
checkov |
Bridgecrew Checkov security scanner | Active | Pinned versions; has goss tests |
toolbox |
Generic Debian toolbox container | Maintained | Debian trixie; build-arg driven tools |
yajsv |
JSON schema validator (Go) | Active | Multi-stage scratch build (~5MB); has tests |
offlineimap |
Email sync with supercronic | Active | Debian trixie; has goss tests |
postfix |
SMTP relay | Active | Debian trixie; has goss tests |
tcpdump |
Network debugging | Active | Debian trixie; has goss + integration tests |
ssh-audit |
SSH security auditing | Active | Full test suite with hardened/weak sshd; has AGENTS.md, README |
spf-flattener |
SPF record flattening tool | Active | Alpine image; Let's Encrypt tool; requires DNS for testing |
media |
Media server stack | Reference | Compose-only; third-party images; has ./run |
No outstanding issues.
See .cursorrules for full details. Key points:
./runscript: Standard interface (build,clean,release)- Tags:
<project>-v<MAJOR>.<MINOR>.<PATCH> - Base images: Pin versions via
ARG(e.g.,ARG DEBIAN_VERSION="trixie-20260406-slim") - Builds: Purge build deps in same
RUNlayer, use--no-install-recommends - Multi-arch: Release builds target
linux/amd64,linux/arm64
Use Test-Driven Development (TDD) with the red-green-refactor loop. See the TDD skill for detailed guidance.
- Test behavior, not implementation — Tests verify what users care about (can I connect? can I backup?) not internal function calls
- Use public interfaces — Test through CLI/API, not internal methods
- One test at a time — RED→GREEN for each behavior, never write all tests first (horizontal slicing anti-pattern)
- Never refactor while RED — Get to GREEN first, then refactor
RED: Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes
REFACTOR: Clean up (tests still pass)
REPEAT: Next behavior
- Test describes behavior, not implementation
- Test uses public interface only
- Test would survive internal refactor
- Code is minimal for this test
Eight projects have test suites: samba-timemachine, ssh-audit, yajsv, checkov, offlineimap, postfix, tcpdump, and gam.
samba-timemachine tests three phases:
- Build-time tests: Validate image structure
- Healthcheck tests: Validate running container
- Live integration tests: Validate user-facing behavior
ssh-audit tests both positive and negative cases:
- Build-time tests: Validate binary install and version
- Integration tests: Audit a hardened sshd (must pass with exit 0) and a weak sshd (must fail with exit >= 2)
yajsv tests the container image directly (no goss needed for scratch images):
- Version test: Default CMD returns correct version
- Positive tests: Valid JSON files pass schema validation
- Negative tests: Invalid files (missing fields, wrong types, extra properties) are rejected with correct error messages
checkov mounts goss into the Python container:
- Direct artifact tests: Version and help output
- Goss tests: Entrypoint permissions, version match, help output
gam includes network connectivity tests:
- Build-time tests: Version, help, pip package verification
- Entrypoint tests: Verify exec path works (e.g.,
python --version) - Network tests:
gam checkconnectionvalidates connectivity to 40+ Google APIs (~25s)
The goss project builds goss from source with patched Go dependencies to fix CVEs. All projects use this pre-built goss image.
Pattern 1: Embedded (services with healthcheck)
Copy goss into the image for build-time validation and runtime healthchecks:
FROM timjdfletcher/goss:latest AS goss
FROM debian:trixie-slim
COPY --from=goss /goss /goss/gossUsed by: samba-timemachine
Pattern 2: External (CLI tools)
Extract goss at test time and mount it. The _ensure_goss_image() function auto-builds the goss image if missing:
_ensure_goss_image() {
if ! docker image inspect "${GOSS_IMAGE}:${IMAGE_TAG}" >/dev/null 2>&1; then
log "Goss image not found, building..."
(cd "${SCRIPT_DIR}/../goss" && ./run build)
fi
}
_ensure_goss() {
_ensure_goss_image
local goss_dir="${PWD}/.goss-bin"
if [ ! -x "${goss_dir}/goss" ]; then
mkdir -p "${goss_dir}"
docker rm goss-extract 2>/dev/null || true
docker create --name goss-extract "${GOSS_IMAGE}:${IMAGE_TAG}" >/dev/null
docker cp goss-extract:/goss "${goss_dir}/goss"
docker rm goss-extract >/dev/null
fi
}
# Mount when testing:
docker run --rm -v "${PWD}/.goss-bin:/goss-bin:ro" ... /goss-bin/goss validateUsed by: gam, checkov, ssh-audit, tcpdump, postfix, offlineimap
Scratch images (yajsv): Don't use goss. Test the container directly by running it with different inputs and checking outputs/exit codes.
Use the checkov container to scan Dockerfiles:
docker run --rm -v "$(pwd):/tf" timjdfletcher/checkov:tmp \
--directory /tf --framework dockerfile --compact --quietSome checkov findings are acceptable for this repo:
| Check | Finding | Why It's OK |
|---|---|---|
| CKV_DOCKER_3 | No USER instruction | CLI tools often need root (tcpdump, postfix) or handle users at runtime (gam, samba-timemachine) |
| CKV_DOCKER_2 | No HEALTHCHECK | Most containers are CLI tools, not long-running services. Only samba-timemachine needs HEALTHCHECK |
- No secrets committed (no
.env, credentials, keys, PEM files) - Use
COPYnotADD(except for URLs, which we avoid) - Pin all versions via
ARG - Clean up apt lists:
rm -rf /var/lib/apt/lists/* - Use
pip install --no-cache-dir - Avoid running as root when downloading from the internet
- Check upstream for new versions (see project AGENTS.md for URLs)
- Update
ARGin Dockerfile - Run
./run testif available, otherwise./run build - Tag and release:
git tag <project>-v<VERSION> && ./run release
The macOS native container CLI (Homebrew) works for building, running, and testing images. Tested on macOS 26.3.
| Feature | Status | Notes |
|---|---|---|
| Build | ✓ | Pass --build-arg for ARG before FROM |
| Multi-arch | ✓ | --platform linux/arm64 --platform linux/amd64 |
| Run/exec/volumes/ports | ✓ | Same flags as Docker |
| Goss testing | ✓ | Mount goss-bin volume, use --entrypoint /goss-bin/goss |
| container-compose | ✗ | v0.9.0 has limited compose file support |
All 8 projects with tests were validated using native containers:
| Project | Tests | Notes |
|---|---|---|
| samba-timemachine | 70 pass | Healthcheck + live tests |
| yajsv | 7 pass | Direct container tests (no goss needed) |
| gam | 12 pass | Includes network connectivity tests |
| checkov | 7 pass | |
| ssh-audit | 4 pass | Build-time only (integration needs compose) |
| tcpdump | 5 pass | |
| postfix | 8 pass | |
| offlineimap | 12 pass |
Key differences from Docker:
--entrypoint ""doesn't work; use--entrypoint /path/to/binaryinstead- Shared volumes work the same way
- No
docker cpequivalent; for scratch images, test the container directly
See samba-timemachine/AGENTS.md for detailed findings.
- Always
cdinto the project subdirectory before running./runcommands - The most complex/interesting project is
samba-timemachine— use it as a reference - When in doubt about patterns, check existing implementations in mature projects