Skip to content

feat(rootless): the CONTAINERD.md §4 checklist, the rootless units, and a fatal nerdctl-full checksum - #12

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/rootless-checklist
Oct 22, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/rootless-checklist

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Summary

Head cbb6ba33791477cd33088a9731aa9a060d43f3c8 · tree 455802a09784b0a40440f8d11f2e5beccf6d9aa1 · 7 files, +682/−55.

The candy installed the rootless binaries but carried none of the CONTAINERD.md §2/§4
checklist, promised rootless containerd/buildkit units that no plan: step wrote, and made
the nerdctl-full checksum advisory. Both halves of #10 are closed
here, together with the checklist itself (#11).

  • The helpers and the ranges. newuidmap/newgidmap are declared per distro (shadow
    on Arch/Alpine, uidmap on Debian/Ubuntu, shadow-utils on Fedora), containerd is
    declared explicitly, and a plan step writes user:100000:65536 to /etc/subuid and
    /etc/subgid for the uid-1000 user. The step resolves the name from the UID rather than
    hardcoding user.
  • The delegation and the user bus. /etc/systemd/system/user@.service.d/delegate.conf
    carries Delegate=cpu cpuset io memory pids; dbus/dbus-daemon/dbus-user-session is
    installed for the dbus.socket the rootless unit requires.
  • The units. The candy writes ~/.config/systemd/user/containerd.service and
    buildkit.service from the upstream setuptool templates. ExecStart goes through
    /usr/bin/env so one unit serves both install prefixes (/usr/local/bin from
    nerdctl-full, /usr/bin from the distro packages), and the file carries a candy marker
    the checks assert.
  • The network driver. The containerd unit pins
    CONTAINERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns. pasta and bypass4netns are
    documented from their measured state instead of being recommended, and
    net.ipv4.ip_unprivileged_port_start is a documented option, never forced.
  • The checksum. The release publishes ONE SHA256SUMS file, not per-asset
    .sha256sum files, so the old ${url}.sha256sum fetch 404'd and || true hid it. One
    written verifier (no --ignore-missing, no || true) now checks the archive against the
    extracted line, and a negative check proves a corrupted archive is rejected.
  • The CNI plugins at the declared path. The nerdctl-full tarball extracts its CNI
    plugins to /usr/local/libexec/cni, but nerdctl.toml names /opt/cni/bin; a step links
    every real plugin at the ONE declared path, and a check asserts the five the conflist names
    resolve. (Arch's package already installs there; the tarball did not.)
  • The namespace. namespace = "default" replaces the retired charly value in
    nerdctl.toml; the charly CNI network name stays (it names a network, not a containerd
    namespace).
  • The bed. check-nerdctl-rootless is a disposable Fedora VM bed (the tarball arm — it
    proves the CNI-path fix end to end) whose candy is applied by the
    VM deploy's own add_candy: (not a nested local: member — see the filed plugin-check pin
    issue), in the three-step shape:
    ABSENCE (no rootless daemon, the system socket recorded), PERFORM (daemon-reload,
    linger, containerd-rootless-setuptool.sh install + install-buildkit), PRESENCE
    (name=rootless in nerdctl info, helpers resolve, /dev/fuse opens, units active,
    slirp4netns is the driver, a memory-limited container runs). PERFORM starts the
    candy-written units through systemd and waits for nerdctl info before running the
    setuptool: the installer gives a unit three seconds, which a cold guest can exceed, and a
    slow start must report the unit's journal rather than an opaque exit. The daemon-safety proof
    asserts the daemon's namespace socket is the USER socket by device:inode across
    /proc/<pid>/root, that the host system socket is a different object or absent, and
    that its inode/mtime is unchanged before/after.
  • The bed image declares its distro chain. Without distro: ["fedora:43", fedora]
    img.DistroDef is nil and the generator emits no declarative package installs, so the
    candy's package arms did nothing. The first run's command -v dbus-daemon failure is
    how that surfaced.
  • /image/ is ignored: the VM bed renders a disk + seed there.

How tested

Gate on the committed tree (cbb6ba3), with a fresh worktree-local charly build (2026.295.1709,
scripts/bootstrap-charly.sh from charly origin/main — the umbrella's older
2026.293.1809 binary predates the sdk repo-root skill reader and cannot render this
repo):

$ charly box validate
charly box validate: OK — checked 1 candy, 1 box, 2 deploys, 7 distros, 7 builders; 0 warnings, 0 errors

$ charly box build check-nerdctl-app
--- Building check-nerdctl-app ---

$ charly check box check-nerdctl-app
22 steps: 18 passed, 0 failed, 4 skipped

The 4 skips in check box are the three mutating run: steps (verify-only mode) and the
context: [runtime] /dev/fuse step; charly check run executes them at deploy-add.

$ charly check run check-nerdctl-rootless
[vm-build] PASS   [vm-create] PASS   [wait-ready] PASS
[deploy-add] PASS [check-live] PASS  [update] PASS
[rebuild-ready] PASS [check-live-rebuild] PASS [cleanup] PASS
PASS (steps=11)
rc=0

check-live / check-live-rebuild printed 23 steps: 20 passed, 0 failed, 3 skipped.
The 3 SKIPs are the candy's three MUTATING run: steps (tarball install, subuid write,
CNI link) under charly check live's verify-only mode; charly check run executed them at
deploy-add, and every PRESENCE assertion that depends on them PASSED (subuid range,
plugins at cni_path, nerdctl version). summary.yml reports errors: 0, warnings: 0
(allowlisted: 11, all dev-worktree-binary-notice).

Artifacts verified inside the built image beyond the checks: shadow-utils-4.18.0,
dbus-daemon-1.16.2, slirp4netns-1.3.1, fuse-overlayfs-1.13 installed; the units under
/home/user/.config/systemd/user/; namespace = "default".

Rulebook compliance

  • R1: the stale umbrella binary, the 404 checksum URL, the nil DistroDef, the wrong
    /opt/cni/bin path, and the first bed run's name=rootless spelling were each
    root-caused before the fix; all are fixed. An Arch venue needed a pacman IgnorePkg
    kernel hold to survive its full upgrade, and that hold printed an unallowlisted
    ignoring package upgrade warning; the bed now runs a Fedora guest, whose dnf install
    keeps the running kernel's modules — no hold, no warning, and the tarball arm is what
    gets proven.
  • R2: one checksum verifier (the install and the negative check call the same script); the
    units are written once for both install prefixes.
  • R5: the retired charly namespace value is deleted, proven by the claim-keyed grep in
    the PR (only the check that asserts its absence matches).
  • R7: the negative checksum check fails if the verifier regresses; the bed's PRESENCE step
    fails without the units, the helpers, the subuid entries and the daemon.
  • R9: the driver is the worktree-local CalVer build above; the umbrella's stale binary is
    not used.
  • R10: the disposable VM bed is the runtime gate; the pod bed is unchanged and still the
    nested-pod posture gate.

Change classification

Runtime change (candy install steps + a new VM R10 bed): charly box validate (0/0), the
build, charly check box and charly check run check-nerdctl-rootless on a disposable
target.

Filed issues

Closes #10
Closes #11

Agent: containerd-crabbox-program/w4c3 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
Assisted-by: Claude Code deepseek-v4.1-flash:cloud (fully tested and validated)

…nd a fatal checksum

The candy installed the rootless binaries but carried none of the CONTAINERD.md
§2/§4 checklist, promised rootless containerd/buildkit units that no plan step
wrote, and made the nerdctl-full checksum advisory: the release publishes one
SHA256SUMS file, so the per-asset `.sha256sum` fetch 404'd and `|| true` hid it.

- per-distro uidmap helpers (shadow/uidmap/shadow-utils), the user D-Bus,
  containerd explicitly, `user:100000:65536` in /etc/subuid and /etc/subgid, the
  user@.service delegation drop-in, and slirp4netns pinned as the network driver;
- the rootless containerd/buildkit user units written from the upstream setuptool
  templates (ExecStart via /usr/bin/env, so one unit serves both install prefixes);
- ONE written checksum verifier (no --ignore-missing, no || true) plus a negative
  check that proves a corrupted archive is rejected;
- the CNI plugins linked at the ONE cni_path the toml declares (/opt/cni/bin): the
  tarball extracts to /usr/local/libexec/cni, Arch's package installs to
  /opt/cni/bin, and no per-distro cni_path is needed;
- `namespace = "default"` replaces the retired `charly` value;
- check-nerdctl-rootless: a disposable Fedora VM bed in the absence/perform/presence
  shape (linger, daemon-reload, the setuptool over the written units, `nerdctl info`
  rootless, the helpers, /dev/fuse, the units active), with the daemon-safety proof
  that the daemon's namespace socket is the USER socket by device:inode and that the
  host system socket's inode/mtime is unchanged;
- the bed image declares its fedora distro chain: without it img.DistroDef is nil and
  no declarative package install is emitted at all.

Closes #10
Closes #11

Agent: containerd-crabbox-program/w4c3 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
Assisted-by: Claude Code deepseek-v4.1-flash:cloud (fully tested and validated)
@github-actions

Copy link
Copy Markdown

Review — PASS

I re-derived every claim in the body against the current diff and the (empty) comment thread.

Body honesty / arithmetic

  • "7 files, +682/−55" reconciles exactly with the per-file counts: additions 83+2+9+28+4+306+250 = 682; deletions 12+0+2+11+0+30+0 = 55; seven ### FILE: sections. ✅
  • The described changes are each actually present: the fatal checksum rewrite (old ${url}.sha256sum + || true + --ignore-missing replaced by a written verifier invoked fatally), the rootless-subuid / rootless-delegate-controllers / rootless-cni-path / rootless-containerd-unit / rootless-buildkit-unit steps, namespace = "default", the distro: ["fedora:43", fedora] box fix, the .gitignore /image/, the Fedora check-nerdctl-rootless VM bed, and the SKILL/README/AGENTS updates. ✅
  • The "3 skipped / 20 passed / 23 steps" (VM bed = 17 candy checks + 3 bed checks + 3 skipped run: steps) vs "4 skipped / 18 passed / 22 steps" (box: /dev/fuse runtime-context skipped plus the 3 run: steps) is internally consistent given the two different targets. ✅
  • R2/R5/R7 claims are reproduced: one verifier used by both the install and the negative test; the retired charly namespace deleted and asserted absent by an anchored grep; the negative checksum test genuinely fails on a corrupted archive. ✅

Correctness / tests

  • The negative checksum check is a real test that fails if the verifier regresses (corrupt the archive, expect nonzero) — R7 satisfied.
  • The bed's ABSENCE → PERFORM → PRESENCE shape is sound: the system socket device:inode+mtime is recorded before and compared after, and the daemon's namespace socket is proven to be the user socket via /proc/<pid>/root. The "unreadable must not read as absent" comment is slightly looser than the || echo absent fallback, but the whole proof is non-vacuous because PERFORM hard-fails on sudo -n systemctl daemon-reload — so the safety comparison can never pass with a broken sudo -n. Not a blocker.
  • The verifier's grep -E interpolates ${archive_name} unescaped, but the name derives from the fixed NERDCTL_FULL_VERSION/ARCH var and the caller extracts a single line, so sha256sum -c still verifies the real file. Not a blocker.

Security / scope

  • No secrets, no unsafe input handling; sudo -n is scoped to daemon-reload/linger/stat. The change is coherent: legacy checksum path, charly namespace, and cache: entry are all removed with no leftover duplicate path. Comments thread is empty, so there is no sign-off to weigh and the change stands on its own evidence.

Non-blocking observations

  • The Arch/Alpine arms are not exercised by the Fedora box/VM gates; the containerd-rootless.sh / containerd-rootless-setuptool.sh presence check on those distros rests on their packages shipping those wrappers. Worth confirming on a native arm, but not demonstrably wrong from this diff.

No derivable defect rises to blocking; the body's evidence is consistent with the diff and the tests are real.

Verdict: PASS


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants