v0.281.0: 'Done' asks the probe first; sign-up closed after the first admin (decision 47); R-713 code-bound values refused, ${NAME|base64}
gates / gates (push) Successful in 23s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-29 09:57:58 +02:00
parent 3a12c7341a
commit 149467c795
28 changed files with 1928 additions and 15 deletions
@@ -37,7 +37,10 @@ func TestAfterInstall_ReplacesTheDefaultLoginOnceAndRecordsIt(t *testing.T) {
// 1. Success: the value is filled in, the command runs ONCE, the record says ok, the log never carries it.
var calls [][]string
m.afterLoadFn = func(_ string, args ...string) (string, error) { calls = append(calls, args); return "... FELHOM_OK", nil }
m.afterLoadFn = func(_ string, args ...string) (string, error) {
calls = append(calls, args)
return "... FELHOM_OK", nil
}
cmd, err := expandAfterInstall(ai.Command, ai.Env, map[string]string{"ADMIN_PASSWORD": "Gen3r4tedValue"})
must(t, err)
if err := m.runAfterInstallNow("cloudapp", ai, cmd, record); err != nil {
@@ -55,7 +58,10 @@ func TestAfterInstall_ReplacesTheDefaultLoginOnceAndRecordsIt(t *testing.T) {
// 2. No success marker: retried, then recorded as FAILED — never recorded ok.
calls = nil
m.afterLoadFn = func(_ string, args ...string) (string, error) { calls = append(calls, args); return "boom", errors.New("exit 1") }
m.afterLoadFn = func(_ string, args ...string) (string, error) {
calls = append(calls, args)
return "boom", errors.New("exit 1")
}
if err := m.runAfterInstallNow("cloudapp", ai, cmd, record); err == nil {
t.Fatal("a failing command reported success")
}
@@ -89,3 +95,34 @@ func TestAfterInstall_ReplacesTheDefaultLoginOnceAndRecordsIt(t *testing.T) {
t.Fatal("an undeclared name was filled in")
}
}
// R-713 (v0.281.0): a value pasted into CODE must not be able to end a string or start an interpolation; the
// same value as its own argument, a plain argument, or ${NAME|base64} is fine.
// COMPANION RED-PROOF: make argumentShaped return true always → the claper-shaped case runs with the quote.
func TestR713_AValueThatWouldBeReadAsCodeIsRefused(t *testing.T) {
typed := map[string]string{"ADMIN_PASSWORD": `My"pass#{System.halt()}`}
allowed := []string{"ADMIN_PASSWORD"}
claperShaped := []string{"/app/bin/claper", "rpc", `Claper.x(u, %{password: "${ADMIN_PASSWORD}"})`}
if _, err := expandAfterInstall(claperShaped, allowed, typed); err == nil || !strings.Contains(err.Error(), "read as code") {
t.Fatalf("a quote and #{ went into Elixir code: %v", err)
}
for _, cmd := range [][]string{
{"python3", "-c", "import sys; f(sys.argv[1])", "${ADMIN_PASSWORD}"}, // its own argument (mealie, wger)
{"php", "artisan", "x", "--password=${ADMIN_PASSWORD}"}, // a plain argument (bookstack)
{"python3", "cps.py", "-s", "admin:${ADMIN_PASSWORD}"}, // calibre-web
{"/app/bin/claper", "rpc", `x(Base.decode64!("${ADMIN_PASSWORD|base64}"))`}, // claper, fixed
} {
out, err := expandAfterInstall(cmd, allowed, typed)
if err != nil {
t.Fatalf("%v: refused a safe placement: %v", cmd, err)
}
if strings.Contains(cmd[len(cmd)-1], "|base64") {
if strings.ContainsAny(out[len(out)-1][len(`x(Base.decode64!("`):], `'\{}$`+"`") || strings.Contains(out[len(out)-1], `My"pass`) {
t.Fatalf("base64 form leaked the raw value: %q", out[len(out)-1])
}
}
}
if _, err := expandAfterInstall([]string{"x", "${ADMIN_PASSWORD|rot13}"}, allowed, typed); err == nil {
t.Fatal("an unknown encoding was accepted")
}
}