Operator Blocker Packet — Sandbox Attestation (B4′) — run on VPS / approved CI runner
Operator Blocker Packet — Sandbox Attestation (B4′)
Macro:
PROGRAM_MACRO_PROVISION_AND_ATTEST_DENY_BY_DEFAULT_SANDBOX_FOR_PHASE2_OFFLINE_MVP_2026_06_09Date: 2026-06-09 · Audience: operator · Status:B4_PRIME_BLOCKED_OPERATOR_ACTION_REQUIREDPairs with: profiledesigns/deny-by-default-sandbox-profile-phase2-offline-mvp-2026-06-09.md· reportreports/sandbox-host-attestation-for-phase2-offline-mvp-2026-06-09.mdNo destructive command. No assumed owner approval. This packet requests provisioning + attestation; it provisions nothing. Claude performed no install, container creation, sandbox run, or production mutation.
0. The one blocker
B4′ — a deny-by-default sandbox must be provisioned and attested before the Phase-2 offline MVP build may run. Claude has authored the complete reproducible profile but cannot run it (the governed VPS Docker socket is read-only; no run/exec tool; Mac-local is not an accepted venue). Only the operator can run it on an approved venue and return evidence.
1. Approved venue (pick one) — Mac-local is NOT accepted
- V1 — VPS host (Option B, recommended): a throwaway, isolated container on the already-deployed Docker runtime. Do NOT reuse a prod container; create its own
--rmcontainer; do not touch prod networks/volumes. - V2 — Approved CI runner (Option D): a deny-by-default ephemeral CI job (e.g. a hardened runner) that builds the image and runs the probes.
A developer-laptop / Mac-local run is explicitly rejected as B4′ evidence (owner direction 2026-06-09): it attests only a local/ephemeral venue and would risk an Article-14 venue-confusion. Use V1 or V2.
2. Exact steps
- Place the three files from the profile on the venue:
Dockerfile.sandbox,seccomp-deny-by-default.json(use §4a targeted-deny for the first attestation), and a ≤30-line probeinspector/main.pythat runs the §6 probes and writes JSONL to/out/attest.jsonl. (The probe payload is the operator's to place; the real inspector replaces it in Phase 2.) - Build:
docker build -f Dockerfile.sandbox -t tki-inspector:attest . - Prepare throwaway dirs:
INPUT_DIR(read-only packet, may be empty for boundary attestation),OUTPUT_DIR(empty),SECCOMP(path to the json). - Run the exact command from profile §5 (
--network none --read-only --cap-drop ALL --security-opt no-new-privileges --security-opt seccomp=… --env-file /dev/null -v $INPUT_DIR:/in:ro -v $OUTPUT_DIR:/out:rw …, with no privileged/host-net/host-pid/host-ipc/home/docker-sock/secret flags). - Execute each probe in profile §6 and capture results.
3. Exact probes → exact expected output (proof-of-block)
| Probe | Operation | Expected (PASS only if matched) | L1 test |
|---|---|---|---|
| PR-NET-1 | socket().connect(("1.1.1.1",53)) |
raises OSError; errno ∈ {EPERM(1), ENETUNREACH(101), EAFNOSUPPORT(97)} |
#27 |
| PR-NET-2 | read /proc/net/dev |
interfaces = lo only (empty net ns) |
#27 sib |
| PR-SOCK-1 | socket.socket(AF_INET, SOCK_STREAM) |
raises PermissionError errno EPERM(1) (seccomp) |
#25 |
| PR-ENV-1 | sorted(os.environ.keys()) |
no key matching `(?i)(token | secret |
| PR-FS-RO-IN | open("/in/__probe","w") |
raises OSError errno EROFS(30) |
#33 |
| PR-FS-ESC-1 | open("/etc/__probe","w") |
raises OSError errno EROFS(30) (read-only rootfs) |
#29 |
| PR-FS-ESC-2 | open("/root/__probe","w") and open("/app/__probe","w") |
raises OSError errno EROFS(30)/EACCES(13) |
#29/#33 |
| PR-FS-OUT-OK | open("/out/report.md","w").write("ok") |
succeeds (positive control: the one writable path) | #33 ctrl |
| PR-EXEC-1 | subprocess.run(["/bin/ls"]) / os.execv("/bin/ls",["ls"]) |
raises PermissionError EPERM(1) (seccomp) and/or FileNotFoundError (no shell in distroless) |
#34 |
| PR-MOUNT-1 | read /proc/self/mountinfo |
exactly: rootfs ro, /in ro, /out rw, /tmp tmpfs noexec; nothing else |
#29/#33 |
| PR-SOCK-DOCKER | os.path.exists("/var/run/docker.sock") |
False |
#36 |
| PR-PTRACE-1 (opt) | ptrace(PTRACE_TRACEME) via ctypes |
EPERM(1) | #37 |
#35 (dynamic import outside the L2 allowlist) is a build-time L2 check, not an OS probe; it is attested when the Phase-2 harness is built. Noted so it is not silently dropped.
4. Evidence to return (so Claude can verify read-only, run nothing)
Deposit a bundle where Claude can read it — either a KB doc under knowledge/dev/laws/tool-kiem-thu/reports/sandbox-attestation-evidence-<venue>-<date>.json or the governed VPS write area /opt/incomex/docs/mcp-writes/sandbox-attestation-<date>.json. Include:
{
"venue": "VPS|CI",
"image_digest": "sha256:…",
"seccomp_sha256": "sha256:…",
"runtime": "docker 2x.y / podman a.b",
"probes": [
{"probe_id":"PR-NET-1","operation":"…","expected":"…","actual_stderr_or_value":"…","errno_or_exit":"…","verdict":"PASS|FAIL","artifact_path":"/out/attest.jsonl#…"}
],
"raw": {"mountinfo":"…","env_keyset":["…"],"proc_net_dev":"…"}
}
5. How B4′ closes
Once the bundle is returned: a follow-up agent reads it read-only, confirms every probe's actual matches the §3 expected, binds each to rev4 matrix #24–#37, and only then asserts B4′ acceptance. Claude will not run the sandbox. Until the bundle exists and is verified, B4′ = BLOCKED and the gated build prompt must not run.
6. Risk if waived
Waiving B4′ leaves the MVP's L1 primary boundary unproven; its own P1 self-check is designed to fail closed (BLOCKED/exit 3), so a waiver yields a refusing MVP, not an accepted one. Waiving B4′ is not recommended. B0‴ (Codex re-seal) is separately waived for this prototype-prep scope only; that waiver does not cover B4′.
7. If the venue cannot run it
If neither V1 (VPS throwaway container) nor V2 (approved CI runner) can be provisioned/attested, the build stays BLOCKED (rev4 §21 hard fallback B) and this becomes a genuine owner/operator resource constraint to escalate. Current evidence (runtime already deployed, no install needed) indicates this is not the expected path.
Action-ready, command-level. No destructive command included; the operator chooses and executes provisioning on an approved venue. Claude performed no provisioning, install, container creation, sandbox run, or production mutation in authoring this packet.