Skip to content

fix(podman): keep host repo ownership on rootless podman via keep-id#69

Merged
Pyronewbic merged 1 commit into
mainfrom
fix/podman-keepid-chown
Jul 5, 2026
Merged

fix(podman): keep host repo ownership on rootless podman via keep-id#69
Pyronewbic merged 1 commit into
mainfrom
fix/podman-keepid-chown

Conversation

@Pyronewbic

Copy link
Copy Markdown
Owner

The bug (pre-existing, HIGH — surfaced by review-launcher on #67)

On rootless podman the host user maps to container-root, so the entrypoint's chown of the bind-mounted repo to the uid-1000 sluice user (core/entrypoint.sh) lands host-side as a subuid. After one run the host user can no longer write their own repo — and sluice's own host-side config writes (apply_allowlist) EACCES and die. On docker the mount keeps the host uid so the chown no-ops; the bug is podman-only. The repo's own test harness documents the subuid behavior, but the launcher never handled it for real project dirs.

The fix

resolve_podman_userns (new, src/40-runtime.sh) adds --userns=keep-id:uid=1000,gid=1000 on rootless podman ≥ 4.3, mapping the host user straight onto the sandbox uid. Then:

  • the project mount reads as uid 1000 in the box → writable without a chown (which now no-ops on it) → the repo stays host-owned;
  • container-internal overlay/state volumes are still chowned as before (that chown was never the problem).

Injected via RUNTIME_RUN_OPTS (the same channel kata uses), called from start() before runtime_run. Docker and rootful podman are a strict no-op (early return). Older podman (< 4.3, no keep-id:uid=) warns and falls back to today's behavior with the recovery command: podman unshare chown -R 0:0 "$PWD".

Why keep-id and not "skip the chown"

The chown is load-bearing: without it (or keep-id) the uid-1000 sandbox user can't write the podman bind mount at all. keep-id removes the need for it on the project dir while preserving host ownership — the only approach that fixes the re-own without breaking writability.

Tests / verification

  • verify-podman-userns-unit.bats (7 tests, no Docker): the version gate (4.9.3/5.0.0 inject; 4.2.0 warns + falls back), rootful/docker no-ops, kata-compose append, and a structural guard that start() calls it before runtime_run. This is the only local coverage — rootless podman runs only on the best-effort CI leg, which exercises the integration path.
  • Docker unaffected: make test-acceptance green (16/16), build-check + lint clean, full unit lane 310 green.
  • docs/hardening.md documents the behavior + the older-podman recovery.

Scoped to this one pre-existing finding; the other 5 from the #67 review remain separate follow-ups.

Rootless podman maps the host user to container-root, so the entrypoint's
chown of the bind-mounted repo to the uid-1000 sluice user landed host-side as
a subuid - after one run the host user could no longer write their own repo
(and sluice's own host-side config writes EACCES'd). resolve_podman_userns
adds --userns=keep-id:uid=1000,gid=1000 on rootless podman >= 4.3, mapping the
host user straight onto the sluice uid: the mount is writable without a chown
(which then no-ops on it) and the repo stays host-owned, while container-
internal overlay/state volumes are still chowned as before. Docker and rootful
podman are untouched (early-return no-op). Older podman warns with the
'podman unshare chown' recovery. Version gate + no-ops covered by
verify-podman-userns-unit.bats (rootless podman itself runs only on the
best-effort CI leg); docs/hardening.md documents the behavior.
@Pyronewbic Pyronewbic merged commit 6bcfc79 into main Jul 5, 2026
8 of 9 checks passed
Pyronewbic added a commit that referenced this pull request Jul 6, 2026
…localhost/, rootless caveats) (#71)

Post-review cleanup of the pre-existing findings review-launcher surfaced on #67
(the HIGH chown one shipped as #69); none are regressions.

- build(): hoist `_chash="$(config_hash)"` out of the `local args=(...)` array.
  local returns 0, so a failing hash (shasum rc 127) baked an empty confighash
  label under set -e, after which every maybe_build silently rebuilt. Assigned
  alone the failure propagates and the build dies.
- ls/prune: strip podman's `localhost/` image-name prefix at the two `image ls`
  seeds so the name matches the canonical sluice-<slug> everywhere downstream
  (ps status filter, box_blocked_count, the ${#sluice-} receipt slug,
  remove_box_volumes label) - it was breaking all of them on podman. No-op on
  docker (never emits the prefix).
- doctor: a shared _rootless_podman helper surfaces the rootless-podman host
  limits - pids/memory caps need cgroups-v2 + systemd delegation, ports <1024
  can't bind (flagged per configured port), netfilter modules must be loaded;
  additive rootless_podman JSON field; docs/hardening.md documents all three.

Tests: verify-build-hash-unit.bats (new), + podman-prefix and rootless-doctor
cases in verify-ls-egress-unit / verify-doctor-checks. Unit 318 green,
acceptance 16 green; podman-specific paths ride the best-effort podman CI leg.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant