Files
DoGaMa-serv/internal/notification/service_test.go
T

85 lines
3.0 KiB
Go

package notification_test
import (
"bytes"
"context"
"path/filepath"
"strings"
"testing"
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/notification"
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/persistence/sqlite"
)
func TestChannelSecretsAreEncryptedAndWriteOnly(t *testing.T) {
ctx := context.Background()
db, err := sqlite.Open(ctx, filepath.Join(t.TempDir(), "dogama.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
service, err := notification.New(db, bytes.Repeat([]byte{7}, 32))
if err != nil {
t.Fatal(err)
}
channel, err := service.Upsert(ctx, "", notification.Input{Name: "ops", Type: "webhook", Enabled: true, Events: []string{"backup.failed"}, Config: map[string]string{"url": "https://example.com/hook", "signing_secret": "highly-sensitive"}})
if err != nil {
t.Fatal(err)
}
var encrypted []byte
if err := db.QueryRowContext(ctx, `SELECT encrypted_config FROM notification_channels WHERE id=?`, channel.ID).Scan(&encrypted); err != nil {
t.Fatal(err)
}
if strings.Contains(string(encrypted), "highly-sensitive") {
t.Fatal("secret stored in plaintext")
}
channels, err := service.List(ctx)
if err != nil || len(channels) != 1 || !channels[0].Configured {
t.Fatalf("channels=%#v err=%v", channels, err)
}
}
func TestDeliveryBlocksPrivateWebhookAndRetriesWithRedactedError(t *testing.T) {
ctx := context.Background()
db, err := sqlite.Open(ctx, filepath.Join(t.TempDir(), "dogama.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
service, _ := notification.New(db, bytes.Repeat([]byte{8}, 32))
channel, err := service.Upsert(ctx, "", notification.Input{Name: "unsafe", Type: "webhook", Enabled: true, Events: []string{"backup.failed"}, Config: map[string]string{"url": "https://127.0.0.1/hook", "signing_secret": "never-leak"}})
if err != nil {
t.Fatal(err)
}
if err := service.Queue(ctx, notification.Event{Type: "backup.failed", Title: "Backup failed", Message: "Operation failed", OperationID: "op-1"}); err != nil {
t.Fatal(err)
}
if err := service.RunDue(ctx); err != nil {
t.Fatal(err)
}
var status, code string
var attempt int
if err := db.QueryRowContext(ctx, `SELECT status,attempt,last_error_code FROM notification_deliveries WHERE channel_id=?`, channel.ID).Scan(&status, &attempt, &code); err != nil {
t.Fatal(err)
}
if status != "retrying" || attempt != 1 || code != "unsafe_destination" || strings.Contains(code, "never-leak") {
t.Fatalf("status=%s attempt=%d code=%q", status, attempt, code)
}
}
func TestRejectsMissingKeyAndInsecureURL(t *testing.T) {
if _, err := notification.New(nil, []byte("short")); err == nil {
t.Fatal("short key accepted")
}
ctx := context.Background()
db, err := sqlite.Open(ctx, filepath.Join(t.TempDir(), "dogama.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
service, _ := notification.New(db, bytes.Repeat([]byte{9}, 32))
if _, err := service.Upsert(ctx, "", notification.Input{Name: "bad", Type: "discord", Enabled: true, Config: map[string]string{"url": "http://example.com"}}); err == nil {
t.Fatal("insecure URL accepted")
}
}