Ensure code is not run as root #414

Closed
opened 2026-06-04 07:55:30 +00:00 by guettli · 2 comments
guettli commented 2026-06-04 07:55:30 +00:00 (Migrated from codeberg.org)

Ensure code is not run as root

Goal

Ensure that developer commands, runner scripts, and test suites are not executed as the root user, particularly when interacting with host-level binaries or wrappers.

Action Items

  • Enforce non-root execution policies for all local test scripts and task runners.
  • Audit helper scripts to ensure they never require or encourage SSH access to localhost as the root user.
  • Ensure that any wrapper creation scripts safely delete existing symlinks/files using rm -f instead of blindly overwriting them via redirection.
# Ensure code is not run as root ## Goal Ensure that developer commands, runner scripts, and test suites are not executed as the `root` user, particularly when interacting with host-level binaries or wrappers. ## Action Items - Enforce non-root execution policies for all local test scripts and task runners. - Audit helper scripts to ensure they never require or encourage SSH access to localhost as the `root` user. - Ensure that any wrapper creation scripts safely delete existing symlinks/files using `rm -f` instead of blindly overwriting them via redirection.
guettlibot commented 2026-06-04 08:10:04 +00:00 (Migrated from codeberg.org)

I have everything I need. Here is the implementation plan:


Implementation Plan for Issue #414: Ensure code is not run as root

Audit findings

  1. No non-root guard exists — neither Taskfile.yml nor any shell script currently rejects execution as root.
  2. No root@localhost SSH foundscripts/setup_dagger_remote.sh SSHes as dagger@$DAGGER_ENGINE_HOST; deploy.sh uses the configurable $SSH_USER; DEVELOPMENT.md already recommends ssh $DEV_USER@localhost. No changes needed for SSH user policy.
  3. One unsafe file writescripts/setup_dagger_remote.sh:53 uses echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key, which silently clobbers an existing symlink's target rather than replacing the file entry. A preceding rm -f is the fix.
  4. Dagger containers internally use root (e.g. /root/.ssh/ in ci/main.go) — this is expected and isolated to Dagger container layers, not host execution.

Changes

1. Taskfile.yml — add non-root precondition to _preflight

_preflight is the shared dependency for all local task commands (analyze, test, test-widget, format, build-linux, check-fast, etc.). Add one entry to its preconditions: block:

preconditions:
  - sh: '[ "$(id -u)" != "0" ]'
    msg: "Do not run as root. Use the dedicated dev user (see DEVELOPMENT.md)."
  - sh: test -n "${IN_NIX_SHELL}"
    msg: "Not in nix dev shell. Run: nix develop"

This is the minimal, centrally-enforced gate. Dagger-only tasks (test-backend, integration-ui, sync-reliability, check-dagger) do not pass through _preflight; they run in containers where root is acceptable, so no change is needed there.

2. Add non-root guard to directly-invocable scripts

The following scripts can be invoked directly (via CI entrypoints or manually), bypassing Taskfile:

  • stalwart-dev/test.sh
  • stalwart-dev/integration_ui_test.sh
  • stalwart-dev/integration_android_test.sh
  • scripts/setup_dagger_remote.sh
  • deploy.sh

Insert the following line immediately after set -euo pipefail (or set -Eeuo pipefail) in each:

[ "$(id -u)" != "0" ] || { echo "ERROR: Do not run as root. See DEVELOPMENT.md."; exit 1; }

Scripts invoked only via Taskfile (scripts/run_unit_tests.sh, scripts/run_widget_tests.sh, etc.) are already covered by the _preflight gate and do not need their own guard.

3. scripts/setup_dagger_remote.sh:53 — safe SSH key write

Replace:

echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key

with:

rm -f ~/.ssh/dagger_key
echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key

This ensures an existing stale file or symlink is removed before the new key is written, preventing silent clobbering.


No schema or Dart code changes

These are all shell/YAML changes. No dart run build_runner run is needed.

I have everything I need. Here is the implementation plan: --- ## Implementation Plan for Issue #414: Ensure code is not run as root ### Audit findings 1. **No non-root guard exists** — neither `Taskfile.yml` nor any shell script currently rejects execution as root. 2. **No `root@localhost` SSH found** — `scripts/setup_dagger_remote.sh` SSHes as `dagger@$DAGGER_ENGINE_HOST`; `deploy.sh` uses the configurable `$SSH_USER`; `DEVELOPMENT.md` already recommends `ssh $DEV_USER@localhost`. No changes needed for SSH user policy. 3. **One unsafe file write** — `scripts/setup_dagger_remote.sh:53` uses `echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key`, which silently clobbers an existing symlink's target rather than replacing the file entry. A preceding `rm -f` is the fix. 4. **Dagger containers internally use root** (e.g. `/root/.ssh/` in `ci/main.go`) — this is expected and isolated to Dagger container layers, not host execution. --- ### Changes **1. `Taskfile.yml` — add non-root precondition to `_preflight`** `_preflight` is the shared dependency for all local task commands (`analyze`, `test`, `test-widget`, `format`, `build-linux`, `check-fast`, etc.). Add one entry to its `preconditions:` block: ```yaml preconditions: - sh: '[ "$(id -u)" != "0" ]' msg: "Do not run as root. Use the dedicated dev user (see DEVELOPMENT.md)." - sh: test -n "${IN_NIX_SHELL}" msg: "Not in nix dev shell. Run: nix develop" ``` This is the minimal, centrally-enforced gate. Dagger-only tasks (`test-backend`, `integration-ui`, `sync-reliability`, `check-dagger`) do not pass through `_preflight`; they run in containers where root is acceptable, so no change is needed there. **2. Add non-root guard to directly-invocable scripts** The following scripts can be invoked directly (via CI entrypoints or manually), bypassing Taskfile: - `stalwart-dev/test.sh` - `stalwart-dev/integration_ui_test.sh` - `stalwart-dev/integration_android_test.sh` - `scripts/setup_dagger_remote.sh` - `deploy.sh` Insert the following line immediately after `set -euo pipefail` (or `set -Eeuo pipefail`) in each: ```bash [ "$(id -u)" != "0" ] || { echo "ERROR: Do not run as root. See DEVELOPMENT.md."; exit 1; } ``` Scripts invoked only via Taskfile (`scripts/run_unit_tests.sh`, `scripts/run_widget_tests.sh`, etc.) are already covered by the `_preflight` gate and do not need their own guard. **3. `scripts/setup_dagger_remote.sh:53` — safe SSH key write** Replace: ```bash echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key ``` with: ```bash rm -f ~/.ssh/dagger_key echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key ``` This ensures an existing stale file or symlink is removed before the new key is written, preventing silent clobbering. --- ### No schema or Dart code changes These are all shell/YAML changes. No `dart run build_runner` run is needed.
guettlibot commented 2026-06-04 20:50:03 +00:00 (Migrated from codeberg.org)

Done. Here's a summary of what was implemented:


What changed

Issue #414 — Ensure code is not run as root

Three categories of changes, 8 lines total:

1. Taskfile.yml_preflight precondition
Added a [ "$(id -u)" != "0" ] check as the first precondition in _preflight. Since virtually every local task command (task check, task test, task analyze, task build-linux, etc.) depends on _preflight, this is a single central gate that blocks root execution for all local task work.

2. Root guard in five directly-invocable scripts
Scripts that CI or developers can run outside of task now each include the same one-liner guard immediately after set -e:

  • deploy.sh
  • scripts/setup_dagger_remote.sh
  • stalwart-dev/test.sh
  • stalwart-dev/integration_ui_test.sh
  • stalwart-dev/integration_android_test.sh

3. scripts/setup_dagger_remote.sh — safe SSH key write
Added rm -f ~/.ssh/dagger_key before the echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key line, so any existing file or symlink at that path is explicitly removed rather than silently clobbered via shell redirection.

Audit result: No root@localhost SSH patterns found anywhere in the scripts. setup_dagger_remote.sh uses dagger@$DAGGER_ENGINE_HOST; deploy.sh uses the configurable $SSH_USER; DEVELOPMENT.md already correctly recommends ssh $DEV_USER@localhost. No changes needed for SSH user policy.

PR: https://codeberg.org/guettli/sharedinbox/pulls/433

Done. Here's a summary of what was implemented: --- ## What changed **Issue #414 — Ensure code is not run as root** Three categories of changes, 8 lines total: **1. `Taskfile.yml` — `_preflight` precondition** Added a `[ "$(id -u)" != "0" ]` check as the first precondition in `_preflight`. Since virtually every local `task` command (`task check`, `task test`, `task analyze`, `task build-linux`, etc.) depends on `_preflight`, this is a single central gate that blocks root execution for all local task work. **2. Root guard in five directly-invocable scripts** Scripts that CI or developers can run outside of `task` now each include the same one-liner guard immediately after `set -e`: - `deploy.sh` - `scripts/setup_dagger_remote.sh` - `stalwart-dev/test.sh` - `stalwart-dev/integration_ui_test.sh` - `stalwart-dev/integration_android_test.sh` **3. `scripts/setup_dagger_remote.sh` — safe SSH key write** Added `rm -f ~/.ssh/dagger_key` before the `echo "$DAGGER_SSH_KEY" > ~/.ssh/dagger_key` line, so any existing file or symlink at that path is explicitly removed rather than silently clobbered via shell redirection. **Audit result:** No `root@localhost` SSH patterns found anywhere in the scripts. `setup_dagger_remote.sh` uses `dagger@$DAGGER_ENGINE_HOST`; `deploy.sh` uses the configurable `$SSH_USER`; `DEVELOPMENT.md` already correctly recommends `ssh $DEV_USER@localhost`. No changes needed for SSH user policy. **PR:** https://codeberg.org/guettli/sharedinbox/pulls/433
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: guettli/sharedinbox#414