server init (and the setup screens) write guard.default [baseline] — secrets refused, cards masked, injection recorded, the judge refusing S1-S4, S7, S9-S12 in prompts and answers, fail open after 5s — fetch the judge into the mirror and run it on a node's CPU. --no-guard-model leaves it out. The closing text names what init cannot do: TLS on the client port and backup recipients. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
105 lines
3.8 KiB
Go
105 lines
3.8 KiB
Go
package cli
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
func typeIn(m tea.Model, s string) tea.Model {
|
|
return send(m, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(s)})
|
|
}
|
|
|
|
func TestTheInitFormBecomesInitsSettings(t *testing.T) {
|
|
in := &serverInit{pkiDir: "/etc/llmgw/pki"}
|
|
var m tea.Model = newInitModel(in, []string{"10.0.0.140"}, true)
|
|
if v := m.View(); !strings.Contains(v, "Already in the certificate: 10.0.0.140") {
|
|
t.Fatalf("the addresses found are not shown:\n%s", v)
|
|
}
|
|
m = typeIn(m, "ops@example.com")
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab})
|
|
m = typeIn(m, "llm.example.com, 203.0.113.10")
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(" ")}) // PostgreSQL on
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyTab},
|
|
tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(" ")}) // starter model off
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(" ")}) // judge off
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyEnter})
|
|
|
|
if in.admin != "ops@example.com" || strings.Join(in.hosts, "|") != "llm.example.com|203.0.113.10" {
|
|
t.Errorf("admin %q hosts %q", in.admin, in.hosts)
|
|
}
|
|
if !in.postgres || in.noMirror || in.noNode || !in.noModel || !in.noGuardModel {
|
|
t.Errorf("toggles: postgres %v mirror %v node %v model %v", in.postgres, !in.noMirror, !in.noNode, !in.noModel)
|
|
}
|
|
if m.(initModel).form {
|
|
t.Error("the form stayed up after Set up")
|
|
}
|
|
}
|
|
|
|
func TestAnEmailThatIsNotOneIsSaidSo(t *testing.T) {
|
|
in := &serverInit{}
|
|
var m tea.Model = newInitModel(in, nil, true)
|
|
m = typeIn(m, "not an address")
|
|
for range fStart {
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab})
|
|
}
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyEnter})
|
|
if !m.(initModel).form || !strings.Contains(m.View(), "not an address") {
|
|
t.Errorf("a bad email was accepted:\n%s", m.View())
|
|
}
|
|
}
|
|
|
|
func TestInitsLinesAreFiledAndThePasswordKeptInView(t *testing.T) {
|
|
in := &serverInit{admin: "ops@example.com", pkiDir: "/etc/llmgw/pki"}
|
|
var m tea.Model = newInitModel(in, nil, false)
|
|
for _, l := range []string{
|
|
" ok system user llmgw",
|
|
" kept certificate authority in /etc/llmgw/pki",
|
|
" ok administrator ops@example.com (u1)",
|
|
"",
|
|
" password: Tr0ub4dor-3",
|
|
" shown once — sign in and change it from /profile",
|
|
"",
|
|
" .. downloading qwen2.5-0.5b-instruct into the mirror",
|
|
" .. 40%",
|
|
" .. 80%",
|
|
" !! an NVIDIA card is on the PCI bus but nvidia-smi does not answer",
|
|
"The control plane is up. Next:",
|
|
" llmgw ctl status",
|
|
} {
|
|
m = send(m, initLineMsg(l))
|
|
}
|
|
m = send(m, initDoneMsg{})
|
|
im := m.(initModel)
|
|
if im.password != "Tr0ub4dor-3" {
|
|
t.Errorf("password %q", im.password)
|
|
}
|
|
v := m.View()
|
|
for _, want := range []string{"✓ system user llmgw", "Tr0ub4dor-3", "Shown once", "80%", "! an NVIDIA card", "Back up /etc/llmgw/pki", "node add"} {
|
|
if !strings.Contains(v, want) {
|
|
t.Errorf("screen lacks %q:\n%s", want, v)
|
|
}
|
|
}
|
|
if strings.Contains(v, "40%") {
|
|
t.Error("progress lines piled up instead of replacing each other")
|
|
}
|
|
if strings.Contains(v, "llmgw ctl status") {
|
|
t.Error("the closing text was listed as a step")
|
|
}
|
|
}
|
|
|
|
func TestWithAMirrorElsewhereTheFormDoesNotOfferOne(t *testing.T) {
|
|
in := &serverInit{mirrorURL: "http://10.0.0.150:8082"}
|
|
var m tea.Model = newInitModel(in, nil, true)
|
|
if v := m.View(); !strings.Contains(v, "at http://10.0.0.150:8082, from --mirror") {
|
|
t.Errorf("the mirror in use is not shown:\n%s", v)
|
|
}
|
|
// Tab from the addresses goes past the mirror line to PostgreSQL, then
|
|
// the node.
|
|
m = send(m, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyTab}, tea.KeyMsg{Type: tea.KeyTab})
|
|
if f := m.(initModel).focus; f != fNode {
|
|
t.Errorf("focus %d, want the node toggle %d", f, fNode)
|
|
}
|
|
}
|