Make delivery and integration failures explicit

Persist reminder presentations and retry state, atomically complete collapsed deliveries, fall back across away reaches, and block permanent failures visibly (V-715, V-678). Fail closed when enabled integrations lack credentials and keep remote arms explicitly dark (V-691). Give mavweb one sanitized, request-correlated error contract (V-689). Owner explicitly requested direct commits to master.
This commit is contained in:
2026-08-13 02:50:59 +04:00
parent da9114b623
commit 35c6ff5a71
67 changed files with 3174 additions and 477 deletions
+119 -1
View File
@@ -435,10 +435,21 @@ func TestNormaliseDropsAddresslessWorkstation(t *testing.T) {
}
}
func TestModelDisabledKeepsLiveSTT(t *testing.T) {
p := writeConfig(t, `{"workstation":{"model_disabled":true,"stt":{"url":"http://192.168.1.105:8081/transcribe","token":"secret"}}}`)
c, err := Load(p)
if err != nil {
t.Fatalf("Load: %v", err)
}
if c.Workstation == nil || c.Workstation.Stt == nil || !c.Workstation.ModelDisabled {
t.Fatalf("model-only dark state did not preserve STT: %+v", c.Workstation)
}
}
// The health endpoint defaults to the supervisor's, not llama-server's: mavgpud
// answers 503 while the card is held, and that refusal is the whole signal.
func TestNormaliseFillsWorkstationDefaults(t *testing.T) {
c := &Config{Workstation: &WorkstationConfig{URL: "http://192.168.1.105:8080/"}}
c := &Config{Workstation: &WorkstationConfig{URL: "http://192.168.1.105:8080/", Token: "secret"}}
c.applyDefaults()
if c.Workstation == nil {
t.Fatal("dropped a usable workstation block")
@@ -460,6 +471,7 @@ func TestNormaliseKeepsExplicitWorkstationHealth(t *testing.T) {
c := &Config{Workstation: &WorkstationConfig{
URL: "http://192.168.1.105:8080",
Health: "http://192.168.1.105:9000/ready",
Token: "secret",
}}
c.applyDefaults()
if got, want := c.Workstation.Health, "http://192.168.1.105:9000/ready"; got != want {
@@ -467,6 +479,112 @@ func TestNormaliseKeepsExplicitWorkstationHealth(t *testing.T) {
}
}
func TestWorkstationLANEndpointsRequireSecrets(t *testing.T) {
for _, tc := range []struct {
name string
body string
}{
{"model", `{"workstation":{"url":"http://192.168.1.105:8080"}}`},
{"stt", `{"workstation":{"url":"http://127.0.0.1:8080","stt":{"url":"http://192.168.1.105:8081/transcribe"}}}`},
} {
t.Run(tc.name, func(t *testing.T) {
if _, err := Load(writeConfig(t, tc.body)); err == nil {
t.Fatal("Load accepted an enabled LAN endpoint with no secret")
}
})
}
}
func TestWorkstationDisabledAllowsEmptySecrets(t *testing.T) {
p := writeConfig(t, `{"workstation":{"disabled":true,"url":"http://192.168.1.105:8080","stt":{"url":"http://192.168.1.105:8081/transcribe"}}}`)
c, err := Load(p)
if err != nil {
t.Fatalf("Load: %v", err)
}
if c.Workstation != nil {
t.Fatalf("disabled workstation survived normalisation: %+v", c.Workstation)
}
}
func TestWorkstationArmsMayBeDisabledIndependently(t *testing.T) {
modelOff := writeConfig(t, `{"workstation":{"model_disabled":true,"url":"http://192.168.1.105:8080","stt":{"url":"http://127.0.0.1:8081/transcribe"}}}`)
if _, err := Load(modelOff); err != nil {
t.Fatalf("Load model-disabled config: %v", err)
}
sttOff := writeConfig(t, `{"workstation":{"url":"http://127.0.0.1:8080","stt":{"disabled":true,"url":"http://192.168.1.105:8081/transcribe"}}}`)
c, err := Load(sttOff)
if err != nil {
t.Fatalf("Load STT-disabled config: %v", err)
}
if c.Workstation == nil || c.Workstation.Stt != nil {
t.Fatalf("STT-only dark state changed model arm: %+v", c.Workstation)
}
}
func TestWorkstationLoopbackMayRunWithoutSecret(t *testing.T) {
p := writeConfig(t, `{"workstation":{"url":"http://127.0.0.1:8080","stt":{"url":"http://localhost:8081/transcribe"}}}`)
if _, err := Load(p); err != nil {
t.Fatalf("Load loopback development endpoints: %v", err)
}
}
func TestTelegramLiveBlockRequiresBothSecrets(t *testing.T) {
for _, body := range []string{
`{"telegram":{"chat_id":"42"}}`,
`{"telegram":{"bot_token":"token"}}`,
} {
if _, err := Load(writeConfig(t, body)); err == nil {
t.Fatalf("Load accepted enabled Telegram block: %s", body)
}
}
}
func TestTelegramDisabledAllowsEmptySecrets(t *testing.T) {
if _, err := Load(writeConfig(t, `{"telegram":{"disabled":true}}`)); err != nil {
t.Fatalf("Load disabled Telegram: %v", err)
}
}
func TestNtfyLiveBlockRequiresSecret(t *testing.T) {
p := writeConfig(t, `{"ntfy":{"base_url":"https://ntfy.example","topic":"maven"}}`)
if _, err := Load(p); err == nil {
t.Fatal("Load accepted enabled ntfy block with no credential")
}
}
func TestNtfyDisabledAllowsEmptySecret(t *testing.T) {
p := writeConfig(t, `{"ntfy":{"disabled":true,"base_url":"https://ntfy.example","topic":"maven"}}`)
if _, err := Load(p); err != nil {
t.Fatalf("Load disabled ntfy: %v", err)
}
}
func TestSmartHomeLiveBlockRequiresSecret(t *testing.T) {
p := writeConfig(t, `{"smarthome":{"enabled":true,"provider":"homeassistant","url":"http://192.168.1.50:8123"}}`)
if _, err := Load(p); err == nil {
t.Fatal("Load accepted enabled Home Assistant block with no token")
}
}
func TestSmartHomeDisabledAllowsEmptySecret(t *testing.T) {
p := writeConfig(t, `{"smarthome":{"enabled":false,"provider":"homeassistant","url":"http://192.168.1.50:8123"}}`)
if _, err := Load(p); err != nil {
t.Fatalf("Load disabled Home Assistant: %v", err)
}
}
func TestConfiguredDBKeyEnvCannotBeEmpty(t *testing.T) {
t.Setenv("MAVEN_TEST_DB_KEY", "")
c := &Config{DBKeyEnv: "MAVEN_TEST_DB_KEY"}
if _, err := c.DBEncryptionKey(); err == nil {
t.Fatal("configured empty database key did not fail startup resolution")
}
if key, err := (&Config{}).DBEncryptionKey(); err != nil || key != nil {
t.Fatalf("explicit plaintext config = (%v, %v), want (nil, nil)", key, err)
}
}
func TestTelegramIntakeRefusesNamedChat(t *testing.T) {
// The push half accepts an @channelusername and the intake half cannot use
// one, so a box with both boots clean and answers nothing. Refuse the