v0.279.0: after_install (decision 45), known default logins on the page, Part D empty-backup alarm, night chain (R-705), R-706
gates / gates (push) Successful in 27s

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-28 18:38:30 +02:00
parent 2e9a948cbd
commit 0c702f834a
35 changed files with 1119 additions and 16 deletions
@@ -0,0 +1,91 @@
package stacks
import (
"bytes"
"errors"
"log"
"path/filepath"
"strings"
"testing"
"time"
)
// v0.279.0 (decision 45) — after_install: the one command after a FRESH install that replaces a known default
// login with the generated one. The exec is the seam; nothing reaches Docker.
// COMPANION RED-PROOFS: (1) drop the success-marker check in runAfterInstallNow → a failing command is
// recorded ok and the second case fails; (2) make expandAfterInstall allow an undeclared/empty name → the
// command runs with a hole and the third case fails.
func TestAfterInstall_ReplacesTheDefaultLoginOnceAndRecordsIt(t *testing.T) {
m, _ := keptManager(t)
var logBuf bytes.Buffer
m.logger = log.New(&logBuf, "", 0)
afterInstallTries, afterInstallGap = 3, 0
t.Cleanup(func() { afterInstallTries, afterInstallGap = 6, 20*time.Second })
dir := filepath.Dir(m.stacks["cloudapp"].ComposePath)
must(t, SaveAppConfig(dir, &AppConfig{Deployed: true, Env: map[string]string{"ADMIN_PASSWORD": "Gen3r4tedValue"}}, m.encKey, nil))
ai := &AfterInstallCommand{Service: "cloudapp", Env: []string{"ADMIN_PASSWORD"},
Command: []string{"/app/bin/tool", "set-admin", "${ADMIN_PASSWORD}"}, Success: "FELHOM_OK"}
m.mu.Lock()
m.stacks["cloudapp"].Meta.AfterInstall = ai
m.mu.Unlock()
record := func(ok bool, d string) {
m.mutateAppConfig("cloudapp", dir, "after_install", func(c *AppConfig) bool {
c.AfterInstall = &AfterInstallRecord{At: "t", OK: ok, Detail: d}
return true
})
}
// 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 }
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 {
t.Fatal(err)
}
if len(calls) != 1 || strings.Join(calls[0], " ") != "exec -T cloudapp /app/bin/tool set-admin Gen3r4tedValue" {
t.Fatalf("ran %v", calls)
}
if c := LoadAppConfig(dir); c.AfterInstall == nil || !c.AfterInstall.OK {
t.Fatalf("record: %+v", c.AfterInstall)
}
if strings.Contains(logBuf.String(), "Gen3r4tedValue") {
t.Fatal("the generated password reached the log")
}
// 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") }
if err := m.runAfterInstallNow("cloudapp", ai, cmd, record); err == nil {
t.Fatal("a failing command reported success")
}
if len(calls) != 3 {
t.Fatalf("tries %d, want 3", len(calls))
}
if c := LoadAppConfig(dir); c.AfterInstall == nil || c.AfterInstall.OK {
t.Fatalf("a failure was recorded as ok: %+v", c.AfterInstall)
}
// 2b. Exit 0 WITHOUT the marker (claper's `rpc` exits 0 on an Elixir error): still a failure.
calls = nil
m.afterLoadFn = func(_ string, args ...string) (string, error) {
calls = append(calls, args)
return "FELHOM_AFTER_INSTALL_FAILED {:error, changeset}", nil
}
if err := m.runAfterInstallNow("cloudapp", ai, cmd, record); err == nil {
t.Fatal("an exit-0 command without the success marker reported success")
}
if c := LoadAppConfig(dir); c.AfterInstall == nil || c.AfterInstall.OK {
t.Fatalf("an exit-0 failure was recorded as ok: %+v", c.AfterInstall)
}
// 3. A value that is not declared, or empty, refuses BEFORE anything runs (never an empty password).
for _, env := range []map[string]string{{}, {"ADMIN_PASSWORD": ""}} {
if _, err := expandAfterInstall(ai.Command, ai.Env, env); err == nil {
t.Fatalf("expanded with env %v", env)
}
}
if _, err := expandAfterInstall([]string{"x ${OTHER}"}, ai.Env, map[string]string{"OTHER": "v"}); err == nil {
t.Fatal("an undeclared name was filled in")
}
}