Skip to content

Commit 42ef4f3

Browse files
committed
fix(tooling): parse devnet.env without eval, and stop dropping lines silently
The env loader was correct but unreadable: `eval "export $key=\$val"` escapes the value so it expands after eval has parsed, and an `export name=value` assignment suppresses word splitting, so multi-word values did arrive whole. Nobody should have to know that to trust the line, and a reviewer already read it as the interpolated form that would break SERVERS="host-a host-b". Bash indirect expansion plus one quoted export word says the same thing with nothing left to reparse. While in there, the header's promise that comments and malformed lines are skipped was only half true. A `# note` after an unquoted value landed inside the value, so SERVERS picked up a host called '#' for sweep.sh to ssh to; quoted values now delimit themselves, keeping a '#' that belongs to the value (http://x/y#frag). A bare word with no '=' became a variable assigned its own name. A leading-digit name reached `export` and produced its error instead of ours. Indented lines were dropped outright. Names that can't be assigned are now reported on stderr, because a config line that goes unread is how you deploy against the wrong deployment.
1 parent bce946e commit 42ef4f3

1 file changed

Lines changed: 33 additions & 9 deletions

File tree

.claude/skills/multi-server-devnet/scripts/devnet-env.sh

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@
99
# since it names your hosts and may point at a webhook file).
1010
#
1111
# A value already set in the environment WINS over the file, so a one-off
12-
# `PROM_DS_UID=other ./deploy-finality-alert.sh` still overrides. Only simple
13-
# `KEY=value` / `export KEY=value` lines are read; `#` comments and blanks skipped.
12+
# `PROM_DS_UID=other ./deploy-finality-alert.sh` still overrides.
13+
#
14+
# Only simple `KEY=value` / `export KEY=value` lines are read. Blank lines and `#`
15+
# comments are skipped, as is a `# comment` tail following an UNQUOTED value; a
16+
# quoted value keeps its contents verbatim, `#` included. Leading indentation is
17+
# fine. A line that looks like an assignment but whose name isn't usable is
18+
# reported on stderr rather than dropped in silence, because a config line that
19+
# goes unread is how you deploy against the wrong deployment.
1420
devnet_load_env() {
1521
local dir file line key val
1622
dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -28,16 +34,34 @@ devnet_load_env() {
2834
[ -n "$file" ] || return 0
2935

3036
while IFS= read -r line || [ -n "$line" ]; do
37+
line=${line#"${line%%[![:space:]]*}"} # ltrim, so an indented line is read
3138
case "$line" in ''|'#'*) continue ;; esac
32-
line=${line#export }
39+
case "$line" in *=*) ;; *) continue ;; esac # not an assignment at all
40+
case "$line" in export[[:space:]]*)
41+
line=${line#export}; line=${line#"${line%%[![:space:]]*}"} ;;
42+
esac
3343
key=${line%%=*}
3444
val=${line#*=}
35-
# skip anything that isn't a plain shell name (comment tails, malformed lines)
36-
case "$key" in ''|*[!A-Za-z0-9_]*) continue ;; esac
37-
val=${val%\"} val=${val#\"}
38-
val=${val%\'} val=${val#\'}
39-
# file provides defaults only: keep an already-set value
40-
if eval "[ -z \"\${$key:-}\" ]"; then eval "export $key=\$val"; fi
45+
# Must be a name the shell can assign: a leading digit or any punctuation makes
46+
# `export` fail with its own confusing error, and skipping in silence would hide
47+
# the operator's typo. Name it and move on.
48+
case "$key" in ''|[0-9]*|*[!A-Za-z0-9_]*)
49+
echo "$file: ignoring '$key=...', not a variable name" >&2; continue ;;
50+
esac
51+
# Quotes, when present, DELIMIT the value, so a '#' or a trailing space inside
52+
# them survives. Unquoted, a `# comment` tail is dropped: it used to end up
53+
# inside the value, and for SERVERS that means sweep.sh ssh-ing to a host '#'.
54+
case $val in
55+
\"*) val=${val#\"}; val=${val%%\"*} ;;
56+
\'*) val=${val#\'}; val=${val%%\'*} ;;
57+
*) val=${val%%[[:space:]]#*} # comment tail
58+
val=${val%"${val##*[![:space:]]}"} ;; # rtrim what it left behind
59+
esac
60+
# File provides defaults only: keep an already-set value. No eval anywhere --
61+
# `${!key}` is bash indirect expansion, and `export` gets ONE quoted
62+
# name=value word, so a multi-word value (SERVERS="host-a host-b") arrives
63+
# whole and nothing in it is ever reparsed as shell.
64+
[ -n "${!key:-}" ] || export "$key=$val"
4165
done < "$file"
4266
echo "loaded deployment env from $file" >&2
4367
}

0 commit comments

Comments
 (0)