Keep the sandbox's own chatter off the stream the command owns
stdout inside the container belongs to the command that ran. Two readers take it as data: ai-sandbox-autophase's preflight reads its answer from that stream, and progress.mjs reads the child pi's JSON event stream from it. Five notices in the pi-seeding block went there instead of stderr, and the steady state (host file unchanged, so cur = prev) prints one on *every* pi-bridged run -- the driver refused a working sandbox on every project. They all go to stderr now, like log() and fail(). The preflight takes the aisb-ok marker from wherever it appears instead of insisting it come first: a banner from an older image or from the user's own launcher is warned about and quoted back, because that stream is parsed as data in every unit. It still refuses on a non-zero exit, on silence, and on a launcher that runs no command -- the failures that would repeat in every unit -- and quotes the foreign stdout instead of a bare exit code. The same block, second contract: the thinking level is policy, so a home the sandbox creates gets it on the *first* seed, not one run later via the merge. tests/unit/06_entrypoint.sh runs the seeding block with the two streams split and asserts stdout empty in every state (cold, steady, edited inside, unparseable, level changed), and greps the entrypoint for any [aisb] line without >&2. tests/unit/10_autophase.sh adds the noisy and the yapping launcher fixtures. LLM-Generated: true
This commit is contained in:
@@ -138,6 +138,66 @@ jq -n --slurpfile T "$M_IN/broken.json" --slurpfile B /dev/null --slurpfile N "$
|
||||
-f "$MJQ" > /dev/null 2>&1 \
|
||||
&& _bad "unparseable input fails loudly for the caller to handle" || _ok "unparseable input fails loudly for the caller to handle"
|
||||
|
||||
t_name "the sandbox keeps its own chatter off the stream the command owns"
|
||||
# stdout inside the container is data. ai-sandbox-autophase reads its preflight answer from
|
||||
# it and progress.mjs reads the child pi event stream from it, so every word the sandbox says
|
||||
# about itself belongs on stderr. Five notices in this very block were once on stdout, and one
|
||||
# of them fires on every pi-bridged run -- which made the driver refuse a working sandbox.
|
||||
# Hence a test that runs the block and separates the two streams, not one that reads it.
|
||||
if grep -nE '(echo|printf).*\[aisb\]' "$EP" | grep -v '>&2' | grep -q .; then
|
||||
_bad "every [aisb] line in the entrypoint is redirected" \
|
||||
"$(grep -nE '(echo|printf).*\[aisb\]' "$EP" | grep -v '>&2' | head -2 | tr '\n' ' ')"
|
||||
else
|
||||
_ok "every [aisb] line in the entrypoint is redirected"
|
||||
fi
|
||||
|
||||
# The extracted block, run as the entrypoint runs it (bash -c with the policy directory, the
|
||||
# level and the merge program as $1..$3). Only this snippet sees the substituted HOME, and it
|
||||
# starts no container, so podman's own HOME is untouched.
|
||||
SP="$WORK/seed"; mkdir -p "$SP/pi"
|
||||
printf '{ "providers": { "gateway": { "models": [ { "id": "turbo" } ] } } }\n' > "$SP/pi/models.json"
|
||||
printf '{ "theme": "dark/dark" }\n' > "$SP/pi/settings.json"
|
||||
SEED_OUT="$WORK/seed.out"; SEED_ERR="$WORK/seed.err"
|
||||
seed_run() { # <level>
|
||||
HOME="$SP/home" bash -c "$(cat "$INNER")" aisb-seed "$SP" "${1-xhigh}" "$(cat "$MJQ")" \
|
||||
> "$SEED_OUT" 2> "$SEED_ERR"
|
||||
}
|
||||
seed_says() { grep -qF -- "$1" "$SEED_ERR"; }
|
||||
seed_stdout() { [[ -s "$SEED_OUT" ]] && printf '%s' "$(tr '\n' ';' < "$SEED_OUT")"; }
|
||||
seed_level() { jq -r '.defaultThinkingLevel // "absent"' "$SP/home/.pi/agent/settings.json" 2>/dev/null; }
|
||||
|
||||
seed_run xhigh; RC=$?
|
||||
assert_eq 0 "$RC" "seeding runs outside a container"
|
||||
[[ -z "$(seed_stdout)" ]] && _ok "and it writes nothing on stdout (cold seed)" \
|
||||
|| _bad "stdout belongs to the command (cold seed): $(seed_stdout)"
|
||||
seed_says "seeded models.json" && _ok "the notice went to stderr" || _bad "the notice went to stderr"
|
||||
seed_says "seeded settings.json" && _ok "including the settings one" || _bad "including the settings one"
|
||||
# the level is policy, so a home we create must not run one unit at the default of pi itself
|
||||
assert_eq "xhigh" "$(seed_level)" "the first seed already carries the thinking policy"
|
||||
|
||||
seed_run xhigh; RC=$?
|
||||
assert_eq 0 "$RC" "and on the next run"
|
||||
[[ -z "$(seed_stdout)" ]] && _ok "nothing on stdout once the files exist (the steady state)" \
|
||||
|| _bad "steady-state stdout is not clean: $(seed_stdout)"
|
||||
seed_says "refreshed models.json from the host config" \
|
||||
&& _ok "the line that broke the driver is on stderr" || _bad "the line that broke the driver is on stderr"
|
||||
|
||||
sed -i 's/turbo/juggernaut/' "$SP/home/.pi/agent/models.json"
|
||||
seed_run xhigh
|
||||
[[ -z "$(seed_stdout)" ]] && _ok "an in-sandbox edit is reported without touching stdout" \
|
||||
|| _bad "edited-file stdout: $(seed_stdout)"
|
||||
seed_says "left models.json alone" && _ok "and the explanation still arrives" || _bad "and the explanation still arrives"
|
||||
|
||||
printf '{oops' > "$SP/home/.pi/agent/settings.json"
|
||||
seed_run xhigh
|
||||
[[ -z "$(seed_stdout)" ]] && _ok "even a repair is announced off stdout" || _bad "broken-json stdout: $(seed_stdout)"
|
||||
seed_says "not usable JSON" && _ok "with the warning on stderr" || _bad "with the warning on stderr"
|
||||
|
||||
seed_run low
|
||||
assert_eq "low" "$(seed_level)" "a changed level is applied over the merged file"
|
||||
seed_says "thinking -> low" && _ok "and announced there too" || _bad "and announced there too"
|
||||
[[ -z "$(seed_stdout)" ]] && _ok "with stdout still empty" || _bad "level-change stdout: $(seed_stdout)"
|
||||
|
||||
t_name "privilege drop is the last thing that happens"
|
||||
tail -5 "$EP" | grep -q 'setpriv' && _ok "exec setpriv at the end" || _bad "setpriv last: $(tail -3 "$EP" | tr '\n' ' ')"
|
||||
grep -q -- '--bounding-set=-all' "$EP" && _ok "bounding set cleared" || _bad "bounding set cleared"
|
||||
|
||||
Reference in New Issue
Block a user