An easy-to-host PDS on the ATProtocol, MacOS. Grandma-approved.

docs: add test plan for MM-66 Docker image

+108
+108
docs/test-plans/2026-03-08-MM-66.md
··· 1 + # MM-66 Human Test Plan 2 + 3 + **Feature:** Docker image derived from Nix build 4 + **Implementation plan:** `docs/implementation-plans/2026-03-08-MM-66/` 5 + **Generated:** 2026-03-08 6 + 7 + ## Prerequisites 8 + 9 + - A Linux system (x86_64-linux or aarch64-linux) with: 10 + - Nix installed (with flakes enabled) 11 + - Docker daemon running 12 + - The repository checked out at commit `7bb5376fbec84feab775f57cb4c4d2fb02307686` or later 13 + - Run the automated checks first: `bash tests/verify-mm66.sh` — all checks must pass before proceeding 14 + 15 + ## Phase 1: Flake Output Verification (AC1.1, AC1.2) 16 + 17 + | Step | Action | Expected | 18 + |------|--------|----------| 19 + | 1.1 | Run `nix flake show --accept-flake-config 2>/dev/null \| grep docker-image` | Output includes a line showing `docker-image` under the `x86_64-linux` packages section (e.g., `docker-image: package 'docker-image.tar.gz'` nested under `packages` > `x86_64-linux`) | 20 + | 1.2 | Inspect the same output for `aarch64-linux` | Output includes a line showing `docker-image` under the `aarch64-linux` packages section | 21 + | 1.3 | Confirm no `docker-image` appears under `aarch64-darwin` or `x86_64-darwin` sections | No `docker-image` lines appear in Darwin system sections (cross-validates AC1.3 on Linux) | 22 + 23 + ## Phase 2: Image Build (AC2.1, AC2.2) 24 + 25 + | Step | Action | Expected | 26 + |------|--------|----------| 27 + | 2.1 | Run `nix build .#docker-image --accept-flake-config` on x86_64-linux | Command exits with status 0. A `result` symlink appears in the project root pointing to a path like `/nix/store/...-docker-image.tar.gz` | 28 + | 2.2 | Run `ls -lh result` | The file is a gzipped tarball (`.tar.gz`). Note the file size for later comparison with AC4.1 | 29 + | 2.3 | (If aarch64-linux or binfmt available) Run `nix build .#packages.aarch64-linux.docker-image --accept-flake-config` | Command exits with status 0. A `result` symlink appears for the aarch64 image. If no aarch64 system or binfmt is available, skip and note as untested | 30 + 31 + ## Phase 3: Image Load and Inspect (AC2.3, AC2.4) 32 + 33 + | Step | Action | Expected | 34 + |------|--------|----------| 35 + | 3.1 | Run `docker load < result` | Output contains `Loaded image: relay:latest` | 36 + | 3.2 | Run `docker images relay` | Output shows at least one row with REPOSITORY `relay` and TAG `latest` | 37 + 38 + ## Phase 4: Image Contents Validation (AC3.1, AC3.2, AC3.3) 39 + 40 + | Step | Action | Expected | 41 + |------|--------|----------| 42 + | 4.1 | Run `docker run --rm relay:latest` | Container exits. There must be NO errors like `no such file or directory` or `error while loading shared libraries: libsqlite3.so`. A non-zero exit code is acceptable because the relay binary is a stub with no configuration to connect to | 43 + | 4.2 | Run `docker inspect relay:latest \| grep -E 'SSL_CERT_FILE'` | Output shows an environment variable line containing `SSL_CERT_FILE=/nix/store/...-nss-cacert-.../etc/ssl/certs/ca-bundle.crt` (the exact Nix store hash will vary) | 44 + | 4.3 | Run `docker inspect relay:latest \| grep -E 'TZDIR'` | Output shows an environment variable line containing `TZDIR=/nix/store/...-tzdata-.../share/zoneinfo` (the exact Nix store hash will vary) | 45 + 46 + ## Phase 5: Image Size (AC4.1) 47 + 48 + | Step | Action | Expected | 49 + |------|--------|----------| 50 + | 5.1 | Run `docker images relay --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"` | The SIZE column shows a value under 50 MB. The image should be relatively small since it is a minimal Nix closure containing only the relay binary, sqlite, cacert, and tzdata | 51 + 52 + ## Phase 6: Scope Boundary (AC5.1) 53 + 54 + | Step | Action | Expected | 55 + |------|--------|----------| 56 + | 6.1 | Run `docker run --rm relay:latest` (same as step 4.1) | The container exits immediately. It does NOT attempt to start an HTTP server, listen on any port, or block waiting for connections. This confirms the relay is a packaging-only stub | 57 + | 6.2 | Run `docker run --rm -d relay:latest && sleep 2 && docker ps \| grep relay` | No running container appears in `docker ps` output — the relay exited immediately, confirming no long-running server process | 58 + 59 + ## End-to-End: Full Build-to-Run Pipeline 60 + 61 + **Purpose:** Validate the complete workflow a developer or CI system would follow to build and verify the Docker image from a clean state. 62 + 63 + 1. Start from a clean state: `docker rmi relay:latest 2>/dev/null; rm -f result` 64 + 2. Run automated checks: `bash tests/verify-mm66.sh` — verify exit code 0 65 + 3. Build the image: `nix build .#docker-image --accept-flake-config` 66 + 4. Verify the result symlink exists: `ls -lh result` 67 + 5. Load into Docker: `docker load < result` 68 + 6. Verify loaded: `docker images relay` — shows `relay:latest` 69 + 7. Run the container: `docker run --rm relay:latest` — exits without linker errors 70 + 8. Inspect environment: `docker inspect relay:latest | jq '.[0].Config.Env'` — shows both `SSL_CERT_FILE` and `TZDIR` 71 + 9. Check size: `docker images relay --format '{{.Size}}'` — under 50 MB 72 + 10. Clean up: `docker rmi relay:latest; rm -f result` 73 + 74 + **Expected:** All steps succeed. The pipeline demonstrates that the Nix flake produces a valid, loadable, runnable Docker image with correct environment configuration and acceptable size. 75 + 76 + ## Human Verification Required 77 + 78 + | Criterion | Why Manual | Steps | 79 + |-----------|-----------|-------| 80 + | AC1.1 | Requires Linux Nix evaluation to confirm x86_64-linux output is present | Phase 1, Step 1.1 | 81 + | AC1.2 | Requires Linux Nix evaluation to confirm aarch64-linux output is present | Phase 1, Step 1.2 | 82 + | AC2.1 | `nix build` of docker-image only works on Linux; macOS has no `docker-image` output | Phase 2, Step 2.1 | 83 + | AC2.2 | Requires aarch64-linux system or binfmt QEMU support for cross-arch build | Phase 2, Step 2.3 | 84 + | AC2.3 | Requires Docker daemon to load the image tarball | Phase 3, Step 3.1 | 85 + | AC2.4 | Requires Docker daemon to list loaded images | Phase 3, Step 3.2 | 86 + | AC3.1 | Requires Docker daemon to run the container and verify no linker errors | Phase 4, Step 4.1 | 87 + | AC3.2 | Requires Docker daemon to inspect image config for SSL_CERT_FILE | Phase 4, Step 4.2 | 88 + | AC3.3 | Requires Docker daemon to inspect image config for TZDIR | Phase 4, Step 4.3 | 89 + | AC4.1 | Requires Docker daemon to check loaded image size | Phase 5, Step 5.1 | 90 + | AC5.1 | Requires Docker daemon to confirm relay is a stub (exits immediately, no server) | Phase 6, Steps 6.1-6.2 | 91 + 92 + ## Traceability 93 + 94 + | Acceptance Criterion | Automated Test | Manual Step | 95 + |----------------------|----------------|-------------| 96 + | AC1.1 | — | Phase 1, Step 1.1 | 97 + | AC1.2 | — | Phase 1, Step 1.2 | 98 + | AC1.3 | `tests/verify-mm66.sh` lines 16-51 | Phase 1, Step 1.3 (cross-validation) | 99 + | AC2.1 | — | Phase 2, Step 2.1 | 100 + | AC2.2 | — | Phase 2, Step 2.3 | 101 + | AC2.3 | — | Phase 3, Step 3.1 | 102 + | AC2.4 | — | Phase 3, Step 3.2 | 103 + | AC3.1 | — | Phase 4, Step 4.1 | 104 + | AC3.2 | — | Phase 4, Step 4.2 | 105 + | AC3.3 | — | Phase 4, Step 4.3 | 106 + | AC3.4 | `tests/verify-mm66.sh` lines 56-65 | — | 107 + | AC4.1 | — | Phase 5, Step 5.1 | 108 + | AC5.1 | — | Phase 6, Steps 6.1-6.2 |