mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-11-11 18:18:12 +00:00
Follow-up to #2125: the six non-blocking notes on its approval, with note 3 as the one that changes behaviour. **What changes** - `.env` is now read last. The hand-over of the data directory moves before it, and the only code that runs after the file is sourced reads `prepare_service_user`'s positional parameters: the account, the container's `RUN_AS_UID`/`RUN_AS_GID` (set or unset, and value) and the file's path are parked in `$1..$6` before the `.`. - The comment gives the real reason the account was already safe: the `.` happens inside `load_env_file`, so a `set -- root` in `.env` lands in that function's `$1`, not in `prepare_service_user`'s (note 1). It also says that a trusted `.env` is root's code and this does not defend against it (it can redefine functions or set `PATH`); what it cannot do by assigning variables is change the account, where the hand-over goes, or `RUN_AS_UID`/`RUN_AS_GID` as the services see them. - `svc_log` uses `printf` (note 5); the entrypoint check also pins that it does not assign `CORESCOPE_SERVICE_USER` (note 4); the test header is reflowed (note 6); `TEST_SHELL` picks the inner shell so the suite runs under dash, bash or busybox without editing. **Why** A sourced file shares the shell's variables: every global, the locals of `load_env_file`, and, by dynamic scoping, the locals of its caller too (checked under dash, bash 5.3 and busybox ash 1.37). So a trusted `.env` that assigned `_uid_before` or `_uid_was` skipped the restore and left `RUN_AS_UID=0` in the services' environment, as note 3 says. The same class reached the hand-over: with `SERVICE_DATA_DIR=/` in `.env`, the walk ran over `/`. Nothing but the entrypoint reads `RUN_AS_UID`/`RUN_AS_GID`, so the effect was a wrong value in the services' environment and a log line that said "ignoring" when it had not. **What I checked** - `docker/test-select-service-user.sh`: 116 assertions, 0 failed, under dash and bash. The new cases fail on master for the stated reasons and nothing else does. - New cases: `.env` running `set -- root` (note 1; this is the case that catches sourcing the file inline, the names case alone does not); `.env` assigning the restore's names, `_env_file`, `SERVICE_ENV_FILE` and `RUN_AS_*`, with uid 1000 and gid 1001 so a swapped parameter shows; `RUN_AS_GID` alone; `.env` pointing the three `SERVICE_*` paths elsewhere; a logged path containing `\012`. - Mutations, each applied to a copy and confirmed to make the suite fail: hand-over moved back after `.env`; restore from `load_env_file`'s locals (master); restore from `prepare_service_user`'s locals; file sourced inline in `prepare_service_user` with the refusal log kept; restore dropped; only the uid compared; gid restored from the uid's parameter; set/unset flipped; the log reading `SERVICE_ENV_FILE` after the `.`; the entrypoint reassigning the account. `svc_log` back to `echo` fails under dash only, which is where note 5 applies. - The image, built from this branch (linux/amd64), with a root-owned, root-only-writable `.env` containing all of the above plus `DISABLE_MOSQUITTO=true`, `DISABLE_CADDY=true` and `set -- root`: (A) `RUN_AS_UID` unset: root, nothing re-owned, `DISABLE_*` honoured, `RUN_AS_*` not in the services' environment. (B) `RUN_AS_UID=1000 RUN_AS_GID=1001` on A's data directory, root-owned `meshcore.db` inside: services run as 1000, their environment has `RUN_AS_UID=1000 RUN_AS_GID=1001`, `meshcore.db` and the directory are 1000:1001, `.env` stays root's, `/etc/passwd` stays root's. (C) `.env` owned by uid 1000: refused with the reason, services run as 1000. The same image with master's two scripts mounted over it, in B's shape: services' environment `RUN_AS_UID=0 RUN_AS_GID=0`, `/etc/passwd` owned by 1000, `.env` owned by 1000:1001. - `sh test-all.sh` passes; no JS or Go change. **Not checked** - Windows: the suite stops at the symlink fixture, as before. - busybox as `TEST_SHELL` on my machine: Ubuntu's busybox prefers its own applets over `PATH`, so the stubs are bypassed and 28 cases fail, on master and on this branch alike. Your WSL Debian run (103 passed) and the image itself, which runs Alpine's ash with real binaries, are what cover ash. - Rootless Docker and `userns-remap`: unchanged, docs gap already noted. Note 2: kept the names case as a second guard; the `set -- root` case is the one that pins the design. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: nullrouten <201262769+nullrouten0@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>