The idea
mackas currently keeps two layers of indirection between the user and upstream kas so that kas itself never needs a patch:
bin/docker — a docker-CLI shim that masquerades as docker on $PATH and translates the calls kas-container issues into Apple container calls. It exists because kas-container detects its engine with command -v docker && docker -v | grep -q '^Docker'.
$MACKAS_BIN/kas-container — a generated protection wrapper (write_kas_wrapper(), mackas:4091) that recomputes --runtime-args live (the three ext4 volumes, -c/-m limits), blanks KAS_BUILD_DIR/DL_DIR/SSTATE_DIR, refuses to launch if the resulting string is missing a volume, and then execs the real upstream script.
The idea is to flip which side adapts: mackas keeps doing the real setup work (creating and sizing the ext4 volumes, deriving the project), and then execs genuinely unmodified upstream kas-container — no translation shim, no protection wrapper — because kas has learned to accept the environment mackas prepared. That means patching kas, which reverses the "zero patches to kas" design goal — but upstream patches, not a local fork, so mackas would still never carry a modified kas of its own.
Researched against real kas source (master dcbd85c, kas-container 5.4-14; line numbers below are the v5.4 tag mackas pins unless stated). Conclusion: this is two separate upstream asks, one small and structurally unblocked, one a genuine gap that needs careful framing. They should not be proposed as one thing.
Ask 1: Apple container as a third engine in kas-container — small
The XPC-vs-Docker-Engine-API concern is a non-issue. kas-container never opens a socket or speaks the Engine API; engine support is entirely "shell out to a CLI". The only engine invocation in the whole 820-line script is its last line:
trace ${KAS_CONTAINER_COMMAND} run "$@"
and KAS_CONTAINER_COMMAND is set by a small case on KAS_CONTAINER_ENGINE (master lines 552–584): auto-detect (podman when build_system: isar-rootless, else docker if docker -v | grep -q '^Docker', else podman), then a per-engine branch where podman's whole contribution is KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} --security-opt label=disable". The docker-only helper calls (docker -v, docker context show, docker context inspect) all sit inside the docker branch or the Isar/rootless paths, so a container) branch never reaches them.
Size precedent: podman was added in one commit, a5dc5f8 "kas-docker: Add support for podman", 38 insertions, structured exactly as above (auto-detect chain + case + one usage line).
What a container) branch actually has to do:
KAS_CONTAINER_COMMAND="container".
- Remove
--log-driver=none from KAS_RUNTIME_ARGS="--log-driver=none --user=root" (v5.4:449, master:456). Note this line runs before engine selection, and the engine detection was moved deliberately late (5435c6c, a440b89) so it can see the build system — so the fix belongs in the engine case, not in an earlier reordering.
- Auto-detection that doesn't match any random binary named
container: the analogue of the existing docker -v | grep -q '^Docker' probe, against container --version.
- Optionally, sane
-c/-m defaults, since Apple container defaults to cpus=4 / memory=1gb where docker on Linux inherits the host. Every OE build on the Apple engine needs these; supplying them is arguably part of what an engine branch is for.
- Docs:
docs/userguide/kas-container-description.inc ("As container backends, Docker and Podman are supported…") and the KAS_CONTAINER_ENGINE row in docs/userguide/environment-variables.inc.
--log-driver=none is the only incompatibility on the real path — smaller than bin/docker's drop list implies. The recorded argv fixture in this repo (tests/fixtures/kas-container-5.4.argv, captured from real runs) shows a plain-OE invocation emits only -v, -e, --workdir=, --rm, --init, --user=root plus mackas's -c/-m/volume args, all of which Apple container takes verbatim. The other flags bin/docker drops (--security-opt, --userns, --group-add, --privileged) only appear on the Isar/rootless paths that are already out of scope. So bin/docker is defensive breadth around a one-flag problem, and Ask 1 alone deletes it.
Ask 2: handing kas an already-prepared storage environment — real gap, harder sell
There is no near-miss flag here. forward_dir() (v5.4:286) has exactly two behaviours:
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -v ${FW_DIR_REL}:$2:$3 -e $1=$2" # dir outside KAS_WORK_DIR
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e $1=/work/${FW_DIR_REL}" # dir inside KAS_WORK_DIR
A host path either gets bind-mounted or gets rewritten to a /work subpath. The script has no concept of a named volume anywhere, and setup_kas_dirs()/check_and_expand() (v5.4:219/239) mkdir and realpath -e these values on the host before forward_dir() ever runs, so any non-path spelling has to be handled ahead of that. Hence mackas's current blanking: an unprotected KAS_BUILD_DIR would bind-mount an APFS path over the ext4 volume, and there is no way to say "this one is already provided".
--runtime-args/--docker-args is the only injection point, and it is CLI-only on purpose: KAS_EXTRA_RUNTIME_ARGS is initialised to "" at v5.4:331 by commit 567950b, whose entire rationale is "Just to avoid it is perceived as API or even used as such." So an ask framed as "let the environment supply runtime args" is dead on arrival.
Two framings that could survive:
- Volume-form values for the three dirs, e.g.
KAS_BUILD_DIR=volume:oe-build-tmp expanding to -v oe-build-tmp:/build -e KAS_BUILD_DIR=/build. These env vars already are the documented API for exactly this decision, and the feature generalises past macOS (anyone wanting TMPDIR on a filesystem the host can't supply directly). The container entrypoint needs nothing: chown_managed_dirs() already chowns /build /work /sstate /downloads /repo-ref to the invoking uid however they were mounted.
- Validation only: kas-container notices that
--runtime-args already mounts something at /build and refuses to also bind-mount KAS_BUILD_DIR over it. Cheaper, narrower, closes the actual footgun — but leaves mackas still injecting the flag, so it doesn't remove the wrapper.
What survives even if both land
bin/docker disappears outright with Ask 1 — that's the clean win. The generated kas-container wrapper does not fully disappear even with Ask 2: -c/-m limits, the monitor's -p and bind mounts, and the NFS mirror mounts still have no expression outside --runtime-args, and runtime auto-start (#33) plus the macos-local.yml fragment append are mackas's own business, not kas's. Realistically the wrapper shrinks to those, and its "refuse to launch without the three volumes" check becomes unnecessary once the volume-form env vars are inherited rather than injected. Worth having; "wrapperless" overstates the end state.
Process and prior art
Upstream contributions go to the kas-devel mailing list with Signed-off-by: per CONTRIBUTING.md; GitHub PRs get routinely redirected there by the maintainer (recent: PR #188, PR #152).
- siemens/kas#123 — the maintainer explicitly recommends
--runtime-args '-v <host>:<container>' for exactly this class of problem. mackas's current mechanism is the sanctioned one, not a hack.
- siemens/kas#116 — "that would not work across
kas-container. It needs to know this value but has no parser for configs". kas-container is deliberately a dumb bash script; that bounds how clever Ask 2 may be.
- siemens/kas#188 (open) — makes
--runtime-args honour shell quoting instead of blind word-splitting. If it lands, mackas's "no value in the runtime-args string may contain a space" constraint (kas_runtime_args(), mackas:1416) can be retired.
- No prior art at all for non-docker/non-podman runtimes: searches across all kas issues and PRs for macOS/darwin/apple/nerdctl/lima/colima turn up only #38 (2020, a Mac user on docker-machine hitting a bitbake-server socket error). Apple
container has never been raised upstream.
#179 "Support for external plugins/commands" is about the Python side: kas/plugins/__init__.py hard-codes its nine plugin modules in load() (register_plugins(build), register_plugins(checkout), …) with no entry-point mechanism, and the thread is a stalled design discussion about a stable core-kas/plugin API, referencing older kas-devel RFCs. Its one kas-container sentence ("the unsolved problem is how to add plugins to kas-container") is about surfacing a Python plugin through the container image — not about extending the bash script. Neither ask above needs a plugin system; both are ordinary patches to a shell script. Starting the conversation there would be starting it in the wrong place.
The idea
mackas currently keeps two layers of indirection between the user and upstream kas so that kas itself never needs a patch:
bin/docker— a docker-CLI shim that masquerades asdockeron$PATHand translates the calls kas-container issues into Applecontainercalls. It exists because kas-container detects its engine withcommand -v docker && docker -v | grep -q '^Docker'.$MACKAS_BIN/kas-container— a generated protection wrapper (write_kas_wrapper(), mackas:4091) that recomputes--runtime-argslive (the three ext4 volumes,-c/-mlimits), blanksKAS_BUILD_DIR/DL_DIR/SSTATE_DIR, refuses to launch if the resulting string is missing a volume, and then execs the real upstream script.The idea is to flip which side adapts: mackas keeps doing the real setup work (creating and sizing the ext4 volumes, deriving the project), and then execs genuinely unmodified upstream kas-container — no translation shim, no protection wrapper — because kas has learned to accept the environment mackas prepared. That means patching kas, which reverses the "zero patches to kas" design goal — but upstream patches, not a local fork, so mackas would still never carry a modified kas of its own.
Researched against real kas source (master
dcbd85c,kas-container5.4-14; line numbers below are the v5.4 tag mackas pins unless stated). Conclusion: this is two separate upstream asks, one small and structurally unblocked, one a genuine gap that needs careful framing. They should not be proposed as one thing.Ask 1: Apple
containeras a third engine in kas-container — smallThe XPC-vs-Docker-Engine-API concern is a non-issue. kas-container never opens a socket or speaks the Engine API; engine support is entirely "shell out to a CLI". The only engine invocation in the whole 820-line script is its last line:
and
KAS_CONTAINER_COMMANDis set by a smallcaseonKAS_CONTAINER_ENGINE(master lines 552–584): auto-detect (podmanwhenbuild_system: isar-rootless, elsedockerifdocker -v | grep -q '^Docker', elsepodman), then a per-engine branch where podman's whole contribution isKAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} --security-opt label=disable". The docker-only helper calls (docker -v,docker context show,docker context inspect) all sit inside thedockerbranch or the Isar/rootless paths, so acontainer)branch never reaches them.Size precedent: podman was added in one commit,
a5dc5f8"kas-docker: Add support for podman", 38 insertions, structured exactly as above (auto-detect chain +case+ one usage line).What a
container)branch actually has to do:KAS_CONTAINER_COMMAND="container".--log-driver=nonefromKAS_RUNTIME_ARGS="--log-driver=none --user=root"(v5.4:449, master:456). Note this line runs before engine selection, and the engine detection was moved deliberately late (5435c6c,a440b89) so it can see the build system — so the fix belongs in the enginecase, not in an earlier reordering.container: the analogue of the existingdocker -v | grep -q '^Docker'probe, againstcontainer --version.-c/-mdefaults, since Applecontainerdefaults to cpus=4 / memory=1gb where docker on Linux inherits the host. Every OE build on the Apple engine needs these; supplying them is arguably part of what an engine branch is for.docs/userguide/kas-container-description.inc("As container backends, Docker and Podman are supported…") and theKAS_CONTAINER_ENGINErow indocs/userguide/environment-variables.inc.--log-driver=noneis the only incompatibility on the real path — smaller thanbin/docker's drop list implies. The recorded argv fixture in this repo (tests/fixtures/kas-container-5.4.argv, captured from real runs) shows a plain-OE invocation emits only-v,-e,--workdir=,--rm,--init,--user=rootplus mackas's-c/-m/volume args, all of which Applecontainertakes verbatim. The other flagsbin/dockerdrops (--security-opt,--userns,--group-add,--privileged) only appear on the Isar/rootless paths that are already out of scope. Sobin/dockeris defensive breadth around a one-flag problem, and Ask 1 alone deletes it.Ask 2: handing kas an already-prepared storage environment — real gap, harder sell
There is no near-miss flag here.
forward_dir()(v5.4:286) has exactly two behaviours:A host path either gets bind-mounted or gets rewritten to a
/worksubpath. The script has no concept of a named volume anywhere, andsetup_kas_dirs()/check_and_expand()(v5.4:219/239)mkdirandrealpath -ethese values on the host beforeforward_dir()ever runs, so any non-path spelling has to be handled ahead of that. Hence mackas's current blanking: an unprotectedKAS_BUILD_DIRwould bind-mount an APFS path over the ext4 volume, and there is no way to say "this one is already provided".--runtime-args/--docker-argsis the only injection point, and it is CLI-only on purpose:KAS_EXTRA_RUNTIME_ARGSis initialised to""at v5.4:331 by commit567950b, whose entire rationale is "Just to avoid it is perceived as API or even used as such." So an ask framed as "let the environment supply runtime args" is dead on arrival.Two framings that could survive:
KAS_BUILD_DIR=volume:oe-build-tmpexpanding to-v oe-build-tmp:/build -e KAS_BUILD_DIR=/build. These env vars already are the documented API for exactly this decision, and the feature generalises past macOS (anyone wanting TMPDIR on a filesystem the host can't supply directly). The container entrypoint needs nothing:chown_managed_dirs()already chowns/build /work /sstate /downloads /repo-refto the invoking uid however they were mounted.--runtime-argsalready mounts something at/buildand refuses to also bind-mountKAS_BUILD_DIRover it. Cheaper, narrower, closes the actual footgun — but leaves mackas still injecting the flag, so it doesn't remove the wrapper.What survives even if both land
bin/dockerdisappears outright with Ask 1 — that's the clean win. The generatedkas-containerwrapper does not fully disappear even with Ask 2:-c/-mlimits, the monitor's-pand bind mounts, and the NFS mirror mounts still have no expression outside--runtime-args, and runtime auto-start (#33) plus themacos-local.ymlfragment append are mackas's own business, not kas's. Realistically the wrapper shrinks to those, and its "refuse to launch without the three volumes" check becomes unnecessary once the volume-form env vars are inherited rather than injected. Worth having; "wrapperless" overstates the end state.Process and prior art
Upstream contributions go to the kas-devel mailing list with
Signed-off-by:perCONTRIBUTING.md; GitHub PRs get routinely redirected there by the maintainer (recent: PR #188, PR #152).--runtime-args '-v <host>:<container>'for exactly this class of problem. mackas's current mechanism is the sanctioned one, not a hack.kas-container. It needs to know this value but has no parser for configs". kas-container is deliberately a dumb bash script; that bounds how clever Ask 2 may be.--runtime-argshonour shell quoting instead of blind word-splitting. If it lands, mackas's "no value in the runtime-args string may contain a space" constraint (kas_runtime_args(), mackas:1416) can be retired.containerhas never been raised upstream.siemens/kas#179 is a red herring
#179 "Support for external plugins/commands" is about the Python side:
kas/plugins/__init__.pyhard-codes its nine plugin modules inload()(register_plugins(build),register_plugins(checkout), …) with no entry-point mechanism, and the thread is a stalled design discussion about a stable core-kas/plugin API, referencing older kas-devel RFCs. Its one kas-container sentence ("the unsolved problem is how to add plugins to kas-container") is about surfacing a Python plugin through the container image — not about extending the bash script. Neither ask above needs a plugin system; both are ordinary patches to a shell script. Starting the conversation there would be starting it in the wrong place.