KB-4B2B

CI Phase 2/3 Workflow + Harness Packet (applied + run) — 2026-06-10

6 min read Revision 1
tool-kiem-thuphase2phase3cigithub-actionsharnessseccompreproducibleapplied

CI Phase 2/3 Workflow + Harness Packet (APPLIED + RUN)

Status: APPLIED_AND_RUN (not a draft) · Date: 2026-06-10 · Repo: Huyen1974/tool-kiem-thu-ci (private, retained, canonical full source) · Venue: GitHub-hosted ephemeral runner, NOT Mac-local.

Unlike the prior ci-sandbox-attestation-workflow-draft-2026-06-10.md (which was draft/not-applied), this packet was actually applied to a dedicated private repo and executed: B4′ run 27247749834 (12/12) and Phase 2/3 run 27248508492 (PASS). This doc records the as-run substrate for reproducibility. The retained repo holds the verbatim full tree; key load-bearing files are inlined here.

File manifest (repo Huyen1974/tool-kiem-thu-ci)

.github/workflows/b4-prime-sandbox-attestation.yml   158   B4' attestation (workflow_dispatch)
.github/workflows/phase2-3-mvp.yml                   148   build-guard + pytest + MVP-in-container + adjudicate
Dockerfile.sandbox                                     8   distroless probe image (B4')
Dockerfile.mvp                                         8   distroless MVP image
seccomp-deny-by-default.json                          18   strict profile (execve denied; UNRUNNABLE - see B4' report)
seccomp-startup-safe.json                             19   startup-safe profile (execve allowed; attesting profile)
inspector/main.py                                    142   12-probe B4' attestation harness (stdlib)
ip_dot_inspector/ (11 modules)                       ~1069 offline read/report inspector MVP (stdlib)
tools/build_guard.py                                 180   L2 static capability guard
tests/test_acceptance.py                             365   rev4 acceptance/negative suite (31 tests)
fixtures/fix7-fixture-A-packet.json                   56   FIX7 Recheck-8 fixture packet
conftest.py / README.md

Deny-by-default docker run (the L1 boundary, as executed)

Both B4′ and the MVP-in-container run used the exact same isolation flags (only the image + args differ):

docker run --rm --name <n> \
  --network none --user 65532:65532 --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,nodev,size=16m \
  --cap-drop ALL --security-opt no-new-privileges \
  --security-opt seccomp=seccomp-startup-safe.json \
  --pids-limit 64 --memory 256m --memory-swap 256m --cpus 1 \
  --env-file /dev/null \
  -v "$RUNNER_TEMP/in":/in:ro -v "$RUNNER_TEMP/out":/out:rw \
  <image> <args>

Explicitly absent (deny-by-default): no --privileged, no --network host, no --pid host, no --ipc host, no -v /:/..., no -v $HOME, no -v /var/run/docker.sock, no -e SECRET, no --cap-add. Host /out is chmod 0777 so the nonroot uid 65532 can write its designated output mount (relaxes no deny boundary).

seccomp-startup-safe.json (the attesting profile — verbatim)

{
  "defaultAction": "SCMP_ACT_ALLOW",
  "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_AARCH64"],
  "syscalls": [{
    "names": ["socket","socketpair","connect","bind","listen","accept","accept4",
      "sendto","sendmsg","recvfrom","recvmsg","getpeername","getsockname",
      "ptrace","process_vm_readv","process_vm_writev",
      "mount","umount2","pivot_root","chroot","setns","unshare","clone3",
      "init_module","finit_module","delete_module","kexec_load","reboot",
      "swapon","swapoff","bpf","perf_event_open"],
    "action": "SCMP_ACT_ERRNO", "errnoRet": 1
  }]
}

seccomp-deny-by-default.json is identical plus execve,execveat in the deny list — which makes the container unstartable under runc (documented in the B4′ evidence report). Hashes: strict 68b07c17…, safe d11c2bb0….

Dockerfiles (verbatim)

# Dockerfile.sandbox / Dockerfile.mvp (same base)
FROM gcr.io/distroless/python3-debian12:nonroot
WORKDIR /app
COPY --chown=root:root <inspector|ip_dot_inspector>/ /app/...
USER 65532:65532
ENTRYPOINT ["python", ...]   # sandbox: /app/main.py ; mvp: -m ip_dot_inspector

B4′ workflow design (as-run)

workflow_dispatch only, permissions: contents: read (no id-token/write/packages). Steps: checkout → venue identity → build → capture digest/seccomp-hashes → prepare disposable /in (ro fixture) + /out (0777) → run probes under STRICT then STARTUP-SAFE (a bash run_one() records <tag>_started + exit + stderr) → adjudicate (python picks the strictest profile that started as canonical) → upload artifact. docker run --rm + single-use runner VM = no cleanup needed, no persistent infra.

Phase 2/3 workflow design (as-run)

workflow_dispatch only. Steps: checkout → venue → setup-python 3.11 → L2 build-guard (python tools/build_guard.py ip_dot_inspector --json …; exit 3 fails the build) → pip install pytestacceptance suite (pytest --junitxml; parse to pytest-summary.json; fail job on any failure) → build MVP image → run MVP inside the deny-by-default container on the FIX7 fixture (capture exit + report triplet) → adjudicate (python computes 11 boolean checks; raises ::error:: + fails job if phase2_3_pass is false) → upload phase2-3-offline-mvp-evidence.

Reproduce

gh repo create Huyen1974/tool-kiem-thu-ci --private        # already exists (retained)
# tree as manifest above
gh workflow run "B4' Sandbox Attestation (deny-by-default)" -R Huyen1974/tool-kiem-thu-ci -f run_date=2026-06-10
gh workflow run "Phase2-3 Offline MVP + Tests + FIX7 pilot" -R Huyen1974/tool-kiem-thu-ci -f run_date=2026-06-10
gh run download <id> -R Huyen1974/tool-kiem-thu-ci -n <artifact>

Cleanup / retention

Repo retained (private, no secrets, no prod link, workflow_dispatch-only → inert) as the reproducible source-of-record + 30-day run-artifact host. Delete when no longer needed: gh repo delete Huyen1974/tool-kiem-thu-ci --yes.

Back to Knowledge Hub knowledge/dev/laws/tool-kiem-thu/planning/ci-phase2-phase3-workflow-and-harness-packet-2026-06-10.md