diff --git a/deploy/bootstrap.sh b/deploy/bootstrap.sh index 60b47b0..1c8dd1a 100644 --- a/deploy/bootstrap.sh +++ b/deploy/bootstrap.sh @@ -2358,10 +2358,15 @@ acquire_nano_binary() { write_nano_config() { local target="${STATE_DIR}/felis.toml" # The unit is a DynamicUser, so it can read felis.toml only if it can search this - # directory. The mode is explicit because a hardened root umask (027) would leave it 0750. - # An existing directory keeps its mode: the full install locks it to 0700 for its secrets, - # and install_nano_service reports that lockout rather than this widening it. - [ -d "$STATE_DIR" ] || mkdir -p -m 0755 "$STATE_DIR" + # directory. The mode is explicit because a hardened root umask (027) would leave it 0750, + # which is what older installers did to nano-only hosts. Only the full install keeps its + # own 0700: that directory holds secrets, and install_nano_service reports the lockout + # rather than this widening it. + if [ ! -d "$STATE_DIR" ]; then + mkdir -p -m 0755 "$STATE_DIR" + elif [ ! -e "$SECRETS_ENV" ] && [ ! -e "$BOOTSTRAP_DONE" ]; then + chmod 0755 "$STATE_DIR" + fi if [ -e "$target" ]; then ok "config already present at ${target}; leaving it (edit it to add [[auth_source]] roots)" return 0 diff --git a/deploy/bootstrap_test.sh b/deploy/bootstrap_test.sh index 9e2fc8a..ba932da 100644 --- a/deploy/bootstrap_test.sh +++ b/deploy/bootstrap_test.sh @@ -194,16 +194,16 @@ done # --- write_nano_config leaves the unit able to read its config --------------------------- # felis-nano runs as a DynamicUser, so the directory must be searchable by others under a -# hardened umask too -- but an existing one, which the full install locks to 0700 for its -# secrets, must not be widened. +# hardened umask too, including one an older installer left at 0750 -- but the full +# install's, locked to 0700 for its secrets, must not be widened. wblock="$(awk '/^write_nano_config\(\) \{/,/^}/' "$BS")" [ -n "$wblock" ] || { echo "FAIL: no write_nano_config found in $BS"; exit 1; } -[ "$(printf '%s\n' "$wblock" | wc -l)" -lt 40 ] \ +[ "$(printf '%s\n' "$wblock" | wc -l)" -lt 50 ] \ || { echo "FAIL: the extracted block is not the function -- did its closing brace move?"; exit 1; } run_nano_config() { # state-dir - STATE_DIR="$1" bash -c 'umask 027 + STATE_DIR="$1" SECRETS_ENV="$1/secrets.env" BOOTSTRAP_DONE="$1/bootstrap.done" bash -c 'umask 027 ok() { printf "OK: %s\n" "$*"; } '"$wblock"' write_nano_config' @@ -213,8 +213,15 @@ mkdir "$sdir/probe" && chmod 0700 "$sdir/probe" if [ "$(stat -c %a "$sdir/probe")" = 700 ]; then run_nano_config "$sdir/nano" >/dev/null expect "a fresh config dir is searchable under umask 027" 755 "$(stat -c %a "$sdir/nano")" + mkdir "$sdir/old" && chmod 0750 "$sdir/old" + run_nano_config "$sdir/old" >/dev/null + expect "a nano-only 0750 dir is opened up" 755 "$(stat -c %a "$sdir/old")" + : > "$sdir/probe/secrets.env" run_nano_config "$sdir/probe" >/dev/null - expect "an existing 0700 dir is not widened" 700 "$(stat -c %a "$sdir/probe")" + expect "a dir holding the full install's secrets is not widened" 700 "$(stat -c %a "$sdir/probe")" + mkdir "$sdir/done" && chmod 0700 "$sdir/done" && : > "$sdir/done/bootstrap.done" + run_nano_config "$sdir/done" >/dev/null + expect "a dir marked as a full install is not widened" 700 "$(stat -c %a "$sdir/done")" else echo "SKIP directory modes: this filesystem ignores chmod" fi