Repository navigation
fix(nesting): fetch the smoke image at build time, materialise it at deploy (the sandbox boundary) - #15
Conversation
…deploy (the sandbox boundary)
The build-time `podman pull` cannot work under a sandboxed BuildKit worker:
the sandbox denies `unshare(CLONE_NEWUSER)` to build processes, so podman
dies at startup with `Error determining cgroups mode`, and skopeo's
containers-storage path dies with `Error during unshare(CLONE_NEWUSER)`.
The candy now splits the work:
- build time (root): `skopeo copy docker://quay.io/libpod/alpine:latest
dir:/usr/share/charly/nesting-smoke` — a pure image fetch needs no user
namespace, so it runs on the sandboxed worker;
- a new `nesting-smoke-layout` check asserts the baked OCI layout;
- deploy time (`${USER}`, `context: [runtime]`): `skopeo copy
dir:/usr/share/charly/nesting-smoke
containers-storage:quay.io/libpod/alpine:latest` — the container's own
user namespace is available there.
The runtime copy has no network dependency (the bytes are baked), so a host
whose outer container cannot resolve `quay.io` still gets a warm nested
store, and `nested-podman-run` (`podman run --pull=never`) passes.
Agent: dsh-crabbox-079
Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Review — PASSHead SHA: Security screen: PASS — no secrets/egress, no guardrail weakening, public image fetch only. Non-blocking notes: the skill/body name the two run steps Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Summary
Head
e49d7e736cc23b136ab8d0995e950a06bb42899e.The build-time pre-pull cannot populate the nested store on a sandboxed BuildKit worker: the sandbox denies
unshare(CLONE_NEWUSER), sopodman pulldies at startup withError determining cgroups modeandskopeo copy … containers-storage:dies withError during unshare(CLONE_NEWUSER): Operation not permitted. Any box building this candy fails that step (charly#991 — thedistro-cachyosbox/crabbox-e2ebuild died there twice).The candy now splits the work:
mkdir -p /usr/share/charly/nesting-smoke && skopeo copy docker://quay.io/libpod/alpine:latest dir:/usr/share/charly/nesting-smoke— a pure image fetch needs no user namespace, so it runs on the sandboxed workernesting-smoke-layoutfile: /usr/share/charly/nesting-smoke/manifest.jsonexists${USER},context: [runtime])nesting-smoke-materialiseskopeo copy dir:/usr/share/charly/nesting-smoke containers-storage:quay.io/libpod/alpine:latest— the container's own user namespace is available thereThe runtime copy has no network dependency (the bytes are baked), so a host whose outer container cannot resolve
quay.iostill gets a warm nested store, andnested-podman-run(podman run --pull=never) passes.The skill (
.agents/skills/container-nesting/SKILL.md) gains a "Build-time store population (the sandbox boundary)" section with this RCA and the fetch/materialise table; its/tmpsection now records that the old pre-pull was the trigger and is retired.How tested
The changed build step ran live in the box that was blocked:
distro-cachyos'sbox/crabbox-e2e, built with this branch's candy throughCHARLY_REPO_OVERRIDE=github.com/opencharly/layer-container-nesting=<this worktree>:The runtime materialise ran live in the bed's kept container (a
disposable: truetarget, run viacharly shell), after removing the bed's own copy so the step's effect is visible:The plan's own gate (
charly check box crabbox-e2e) parses and orders every step:120 steps: 90 passed, 0 failed, 30 skipped— the skips are the build/runtime-context-gated steps, which the two runs above cover live.Rulebook compliance
/charly-distros:container-nestingand/charly-image:layerwere read; the change edits the candy and the skill together, per this repo'sAGENTS.md.unsharedenial) is RCA'd in the skill section; no warning or skip hides it. The residual/tmp-corruption trigger is recorded as retired.podman pullis deleted, not kept alongside.skopeocalls.podman pullis gone, proven by the diff.git statusclean; the work happened in a session worktree; no force-push.copy rc=0+nested rc=0).charly 2026.293.1538).disposable: truetarget ischeck-crabbox-e2e-pod; it ran green on the built tree, and the runtime step ran in its kept container.Change classification
Candy plan + skill (runtime-visible behavior). Attribution tier:
fully tested and validated— the blocked build now passes, the full e2e bed is green, and both changed paths executed live on a disposable target.Filed issues
unsharebuild blocker this PR fixes at the candy's source; thedistro-cachyosconsumer pins can now carry the 0.79.0 e2e composition.Agent: dsh-crabbox-079
Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)