cfg_read_allowlist() ended on `[[ -n "$line" ]] && CFG_allow+=(...)`, so a file whose last line is a comment or blank returned 1 from the loop. load_config() calls it twice in a non-final position, so under `set -e` every run died with exit 1 and no output at all -- --dry-run and --print-policy included, with nothing to explain it. Reading a file now always succeeds. An allowlist with nothing in it stays validate_opts()'s call to refuse, with the message that says why. LLM-Generated: true
101 lines
3.9 KiB
Bash
Executable File
101 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# tests/unit/02_config.sh -- config files, allowlists and precedence.
|
|
source "$TESTS/lib.sh"
|
|
|
|
CFG="$WORK/cfg"
|
|
REPO="$WORK/repo"
|
|
mkdir -p "$CFG" "$REPO/.ai-sandbox"
|
|
export AISB_CONFIG_DIR="$CFG"
|
|
|
|
cd "$REPO" || exit 1
|
|
|
|
t_name "allow files are merged"
|
|
cat > "$CFG/allow" <<'EOF'
|
|
# user-wide allowlist
|
|
api.openai.com
|
|
|
|
registry.npmjs.org # trailing comment
|
|
EOF
|
|
cat > "$REPO/.ai-sandbox/allow" <<'EOF'
|
|
pypi.org
|
|
EOF
|
|
sb --print-policy --net allow
|
|
assert_rc 0 "print-policy runs"
|
|
assert_contains "api.openai.com" "user allowlist entry present"
|
|
assert_contains "registry.npmjs.org" "user entry with trailing comment present"
|
|
assert_contains "pypi.org" "repo allowlist entry present"
|
|
|
|
t_name "dedup"
|
|
sb --print-policy --net allow --allow pypi.org --allow pypi.org
|
|
ALLOW_LINE="$(printf '%s' "$OUT" | grep '^allow=')"
|
|
N="$(printf '%s' "$ALLOW_LINE" | grep -o 'pypi.org' | wc -l | tr -d ' ')"
|
|
assert_eq "1" "$N" "duplicate allow entries collapse into one"
|
|
|
|
t_name "key = value config"
|
|
cat > "$CFG/config" <<'EOF'
|
|
net = none
|
|
harness = none
|
|
cpus = 7
|
|
memory = 1536m
|
|
pids = 77
|
|
selinux = :Z
|
|
EOF
|
|
sb --print-policy
|
|
assert_contains "net=none" "config file sets net"
|
|
assert_contains "harness=none" "config file sets harness"
|
|
assert_contains "cpus:7" "config file sets cpus"
|
|
assert_contains "memory:1536m" "config file sets memory"
|
|
assert_contains "pids:77" "config file sets pids"
|
|
assert_contains "selinux=:Z" "config file sets selinux"
|
|
|
|
t_name "precedence: flag > env > config file"
|
|
sb --print-policy --net allow
|
|
assert_contains "net=allow" "flag beats config file"
|
|
sb_env AISB_NET=full --print-policy
|
|
assert_contains "net=full" "AISB_* env beats config file"
|
|
sb_env AISB_NET=full --print-policy --net none
|
|
assert_contains "net=none" "flag beats AISB_* env"
|
|
|
|
t_name "AISB_ALLOW / AISB_ENV lists"
|
|
sb_env AISB_ALLOW=a.example.com,b.example.com:8443 --print-policy --net none
|
|
assert_contains "a.example.com" "AISB_ALLOW entry 1"
|
|
assert_contains "b.example.com:8443" "AISB_ALLOW entry 2 with port"
|
|
sb_env AISB_ENV=HOME_X,TMPDIR --print-policy --net none
|
|
assert_contains "env_names=HOME_X TMPDIR" "AISB_ENV populates env names"
|
|
assert_contains "env_missing=HOME_X" "unset names are reported by --print-policy"
|
|
|
|
t_name "repo config wins per-directory"
|
|
cat > "$REPO/.ai-sandbox/config" <<'EOF'
|
|
pids = 42
|
|
EOF
|
|
sb --print-policy --net none
|
|
assert_contains "pids:42" "repo config overrides user config"
|
|
|
|
t_name "unknown keys warn but do not break"
|
|
echo 'bogus_key = 1' >> "$CFG/config"
|
|
sb --print-policy --net none
|
|
assert_contains "unknown key: bogus_key" "unknown key warns"
|
|
assert_rc 0 "unknown key is not fatal"
|
|
|
|
t_name "an allow file may end on a comment or a blank line"
|
|
# Regression: cfg_read_allowlist() ended on its `[[ -n "$line" ]]`, so a file whose last
|
|
# line yields no target returned 1. load_config() calls it in a non-final position, so under
|
|
# `set -e` every run died with exit 1 and *zero* bytes of output -- --dry-run and
|
|
# --print-policy included. The test above ends its file on "host # trailing comment", which
|
|
# yields a target and so never exercised this.
|
|
for last in '# a trailing comment' '' ' '; do
|
|
printf '# user-wide allowlist\napi.openai.com\n%s\n' "$last" > "$CFG/allow"
|
|
printf 'pypi.org\n%s\n' "$last" > "$REPO/.ai-sandbox/allow"
|
|
sb --print-policy --net allow
|
|
assert_rc 0 "user allow file ending on [$last] is not fatal"
|
|
assert_contains "api.openai.com" "user target survives a file ending on [$last]"
|
|
assert_contains "pypi.org" "repo target survives a file ending on [$last]"
|
|
done
|
|
# The fix must not trade one silence for another: with no target anywhere, the run still
|
|
# refuses, and says why.
|
|
printf '# nothing but a header here\n' > "$CFG/allow"
|
|
printf '# nothing but a header here\n' > "$REPO/.ai-sandbox/allow"
|
|
sb_timeout 20 --print-policy --net allow
|
|
assert_rc 1 "a header-only allow file still refuses to start"
|
|
assert_contains "no egress allowlist configured" "and refuses out loud"
|