src/inject.rs: Added user: Option<String> to the Config struct (serde maps User → user). The inject() function now writes /slim/user into the rootfs at build time when the field is set.
src/build.rs: Passes config.user through build_inner into inject().
src/scripts/slim-init.sh: Reads /slim/user at boot and drops privileges via su before executing the command. Numeric uids are resolved to usernames via /etc/passwd (BusyBox su doesn't accept numeric args). When dropping privileges, the command runs as a child (not exec) so PID 1 stays root and can poweroff -f after the command exits — non-root cannot call poweroff.
example/test.sh: Added test_user verifying both build-time CMD and --cmd override run as the configured user.
How it works
At build time, inject() reads .Config.User from the podman image and writes it to /slim/user in the rootfs.
At boot, slim-init.sh reads /slim/user and stores it in SLIM_USER.
Before executing the command (either /slim/exec or the decoded slim.cmd=), the slim_exec function drops privileges:
If SLIM_USER is empty → exec /bin/sh -c "..." (original behavior)
If SLIM_USER is set → resolve numeric uids to usernames, then su "$user" -c "..." as a child, followed by poweroff -f as root
Test results
=== Testing USER directive ===
-- Test 1: build-time CMD runs as USER
PASS: USER build-time CMD runs as testuser
-- Test 2: run --cmd override runs as USER
PASS: USER run --cmd override runs as testuser
All existing alpine tests continue to pass. cargo clippy, cargo fmt --check, and cargo test all clean.
## Summary
Implements support for the Dockerfile `USER` directive so that the container's CMD/ENTRYPOINT runs as the configured user instead of root.
Closes #7.
## Changes
- **`src/inject.rs`**: Added `user: Option<String>` to the `Config` struct (serde maps `User` → `user`). The `inject()` function now writes `/slim/user` into the rootfs at build time when the field is set.
- **`src/build.rs`**: Passes `config.user` through `build_inner` into `inject()`.
- **`src/scripts/slim-init.sh`**: Reads `/slim/user` at boot and drops privileges via `su` before executing the command. Numeric uids are resolved to usernames via `/etc/passwd` (BusyBox `su` doesn't accept numeric args). When dropping privileges, the command runs as a child (not `exec`) so PID 1 stays root and can `poweroff -f` after the command exits — non-root cannot call `poweroff`.
- **`example/test.sh`**: Added `test_user` verifying both build-time CMD and `--cmd` override run as the configured user.
## How it works
1. At build time, `inject()` reads `.Config.User` from the podman image and writes it to `/slim/user` in the rootfs.
2. At boot, `slim-init.sh` reads `/slim/user` and stores it in `SLIM_USER`.
3. Before executing the command (either `/slim/exec` or the decoded `slim.cmd=`), the `slim_exec` function drops privileges:
- If `SLIM_USER` is empty → `exec /bin/sh -c "..."` (original behavior)
- If `SLIM_USER` is set → resolve numeric uids to usernames, then `su "$user" -c "..."` as a child, followed by `poweroff -f` as root
## Test results
```
=== Testing USER directive ===
-- Test 1: build-time CMD runs as USER
PASS: USER build-time CMD runs as testuser
-- Test 2: run --cmd override runs as USER
PASS: USER run --cmd override runs as testuser
```
All existing alpine tests continue to pass. `cargo clippy`, `cargo fmt --check`, and `cargo test` all clean.
Add support for the Dockerfile USER directive so that the container's
CMD/ENTRYPOINT runs as the configured user instead of root.
Changes:
- inject.rs: Add user field to Config struct, write /slim/user at
build time
- build.rs: Pass config.user through to inject()
- slim-init.sh: Read /slim/user and drop privileges via su before
executing the command. Numeric uids are resolved to usernames via
/etc/passwd (BusyBox su does not accept numeric args). When dropping
privileges, run as a child (not exec) so PID 1 stays root and can
poweroff after the command exits.
- test.sh: Add test_user verifying build-time CMD and --cmd override
both run as the configured user
Closes#7
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Implements support for the Dockerfile
USERdirective so that the container's CMD/ENTRYPOINT runs as the configured user instead of root.Closes #7.
Changes
src/inject.rs: Addeduser: Option<String>to theConfigstruct (serde mapsUser→user). Theinject()function now writes/slim/userinto the rootfs at build time when the field is set.src/build.rs: Passesconfig.userthroughbuild_innerintoinject().src/scripts/slim-init.sh: Reads/slim/userat boot and drops privileges viasubefore executing the command. Numeric uids are resolved to usernames via/etc/passwd(BusyBoxsudoesn't accept numeric args). When dropping privileges, the command runs as a child (notexec) so PID 1 stays root and canpoweroff -fafter the command exits — non-root cannot callpoweroff.example/test.sh: Addedtest_userverifying both build-time CMD and--cmdoverride run as the configured user.How it works
inject()reads.Config.Userfrom the podman image and writes it to/slim/userin the rootfs.slim-init.shreads/slim/userand stores it inSLIM_USER./slim/execor the decodedslim.cmd=), theslim_execfunction drops privileges:SLIM_USERis empty →exec /bin/sh -c "..."(original behavior)SLIM_USERis set → resolve numeric uids to usernames, thensu "$user" -c "..."as a child, followed bypoweroff -fas rootTest results
All existing alpine tests continue to pass.
cargo clippy,cargo fmt --check, andcargo testall clean.f6b0721f06to524ef3e793