diff --git a/.gitignore b/.gitignore index a093374..8eaede2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # Editor / OS .DS_Store *.swp +.check/ +.containerignore +.dockerignore diff --git a/box/check-nerdctl-app/charly.yml b/box/check-nerdctl-app/charly.yml new file mode 100644 index 0000000..9b4f66f --- /dev/null +++ b/box/check-nerdctl-app/charly.yml @@ -0,0 +1,18 @@ +# check-nerdctl-app — the disposable bed image for the layer-nerdctl R10: a Fedora +# base composing the nerdctl stack candy, so the nested-pod posture (cap_add ALL, +# /dev/fuse, /dev/net/tun, unmask /proc/*) is emitted onto a real pod. +check-nerdctl-app: + candy: + version: 2026.266.1730 + description: | + Disposable bed image for the layer-nerdctl R10 — a Fedora base composing + layer-nerdctl, so the nested-pod posture is emitted and can be asserted. + base: quay.io/fedora/fedora:43 + candy: + - layer-nerdctl + plan: + - check: nerdctl is installed by the composed layer-nerdctl candy + command: command -v nerdctl + exit_status: 0 + - check: the nerdctl.toml written by the candy is present + file: /etc/nerdctl/nerdctl.toml diff --git a/candy/layer-nerdctl/charly.yml b/candy/layer-nerdctl/charly.yml index ca7f1e0..652cc5a 100644 --- a/candy/layer-nerdctl/charly.yml +++ b/candy/layer-nerdctl/charly.yml @@ -22,6 +22,19 @@ layer-nerdctl: info, the rootless probe, and the fuse-overlayfs snapshotter. var: NERDCTL_FULL_VERSION: "2.1.2" + security: + # The nested-pod posture for the OUTER pod (userns-scoped): the inner + # rootless engine needs the full capability set WITHIN its user namespace, + # /dev/fuse for the fuse-overlayfs snapshotter, /dev/net/tun for the CNI + # bridge, and the /proc/* unmask so the inner runtime can re-mount /proc. + # These are userns-scoped — the inner engine's userns-root is NOT host root. + cap_add: + - ALL + devices: + - /dev/fuse + - /dev/net/tun + security_opt: + - unmask=/proc/* distro: arch: package: @@ -107,3 +120,46 @@ layer-nerdctl: exit_status: 0 - check: the charly CNI network conflist is present file: /etc/cni/net.d/charly.conflist + +# ---- HARNESS SKILL ---- +layer-nerdctl-skill: + skill: + name: layer-nerdctl + family: distros + owner: layer-nerdctl + description: "nerdctl (containerd CLI) + the rootless containerd/buildkit/CNI stack — native Arch/Alpine packages, the pinned sha256 nerdctl-full tarball on Fedora/Debian/Ubuntu, nerdctl.toml + the charly CNI conflist + the nested-pod posture. Use when working with the nerdctl engine, the layer-nerdctl candy, or engine: nerdctl deploys." + content: | + # layer-nerdctl + + nerdctl (the containerd CLI) plus the rootless containerd + buildkit + CNI + stack, as ONE candy. Composed by a box that wants the opt-in `engine: nerdctl` + engine. + + ## What it installs + + - **Native packages** on Arch/CachyOS/Omarchy and Alpine: `nerdctl`, + `cni-plugins`, `rootlesskit`, `slirp4netns`, `buildkit`, `fuse-overlayfs`, + `crun`, `iptables-nft` (arch) / `iptables` (alpine). + - **Non-native distros** (Fedora/Debian/Ubuntu) install the pinned, + sha256-verified `nerdctl-full` tarball (step `nerdctl-full-tarball`), which + supplies nerdctl + containerd + `containerd-fuse-overlayfs-grpc` + CNI + + buildkit + rootlesskit in one archive. + - `/etc/nerdctl/nerdctl.toml` (charly namespace + rootless buildkit host) and + the `charly` CNI network conflist at `/etc/cni/net.d/charly.conflist`. + - The **nested-pod posture**: userns-scoped `cap_add: ALL`, `/dev/fuse`, + `/dev/net/tun`, `unmask=/proc/*`. + + ## Engine capability + + The `engine: nerdctl` word is served by `opencharly/plugin-nerdctl` + (out-of-process) or compiled in; every engine op delegates to + `container.InvokeEngineOp("nerdctl", …)` in the spec module. nerdctl has no + `--keep-id`, so the start-plan runs the workload as `--user 0:0` (uid 0 == the + host user under rootless), guaranteeing uid-identical sharing; a non-zero uid + needs the subuid caveat. + + ## Use when + + Working with the nerdctl engine, the layer-nerdctl candy, or an + `engine: nerdctl` deploy. + diff --git a/charly.yml b/charly.yml index 5ab36ab..5a3a11a 100644 --- a/charly.yml +++ b/charly.yml @@ -26,3 +26,31 @@ defaults: platform: - linux/amd64 build: [rpm] + +# check-nerdctl-nested — the R10 bed for the layer-nerdctl nested-pod posture: a +# disposable pod composing the nerdctl stack, asserting the emitted devices + +# capability posture on a FRESH deploy. Fails without the security: block. +check-nerdctl-nested: + pod: + image: check-nerdctl-app + disposable: true + lifecycle: test + description: | + The nested-pod R10 bed: deploy a disposable pod composing layer-nerdctl and + assert the outer-pod posture the inner rootless engine needs — /dev/fuse, + /dev/net/tun, and the userns-scoped full capability set (cap_add: ALL). + plan: + - check: the fuse device is present for the fuse-overlayfs snapshotter + file: /dev/fuse + - check: the tun device is present for the CNI bridge + file: /dev/net/tun + - check: the exact full capability mask is retained (cap_add ALL) + command: grep -qE '^CapEff:\s+000001ffffffffff$' /proc/self/status + exit_status: 0 + - check: the pod is userns-scoped (uid 0 inside maps to the host user, not host root) + command: grep -qE '^\s+0\s+1000\s+1\s*$' /proc/self/uid_map + exit_status: 0 + - check: nerdctl is on PATH in the nested pod + command: command -v nerdctl + exit_status: 0 +