package config import ( "os" "path/filepath" "testing" "gitea.dcglab.co.uk/steve/restic-manager/internal/crypto" ) func TestEnsureSecretsKeyMintsOnce(t *testing.T) { t.Parallel() c := &Config{} if err := c.EnsureSecretsKey(); err != nil { t.Fatalf("mint: %v", err) } first := c.SecretsKey if first == "" { t.Fatal("EnsureSecretsKey: SecretsKey still empty") } // Second call must be a no-op (idempotent). if err := c.EnsureSecretsKey(); err != nil { t.Fatalf("second mint: %v", err) } if c.SecretsKey != first { t.Errorf("EnsureSecretsKey is not idempotent: %q → %q", first, c.SecretsKey) } // SecretsKeyBytes returns 32 raw bytes. b, err := c.SecretsKeyBytes() if err != nil { t.Fatalf("bytes: %v", err) } if len(b) != crypto.KeyLen { t.Errorf("decoded key len = %d, want %d", len(b), crypto.KeyLen) } } func TestSecretsKeyBytesRejectsBadInput(t *testing.T) { t.Parallel() cases := map[string]Config{ "empty": {SecretsKey: ""}, "not_base64": {SecretsKey: "!!!"}, "wrong_len": {SecretsKey: "Zm9v"}, // "foo", 3 bytes } for name, c := range cases { c := c t.Run(name, func(t *testing.T) { if _, err := c.SecretsKeyBytes(); err == nil { t.Errorf("expected error for %s", name) } }) } } func TestLoadAcceptsLegacyRepoFields(t *testing.T) { t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "agent.yaml") yaml := []byte(`server_url: "https://srv" host_id: "h1" agent_token: "tok" repo_url: "rest:https://repo/h1" repo_password: "secret" `) if err := os.WriteFile(path, yaml, 0o600); err != nil { t.Fatalf("write: %v", err) } c, err := Load(path) if err != nil { t.Fatalf("load: %v", err) } if c.LegacyRepoURL != "rest:https://repo/h1" || c.LegacyRepoPassword != "secret" { t.Errorf("legacy fields not parsed: %+v", c) } // And on Save the legacy fields should round-trip out to the file // only when set (empty values use omitempty). c.LegacyRepoURL = "" c.LegacyRepoPassword = "" if err := c.Save(); err != nil { t.Fatalf("save: %v", err) } body, _ := os.ReadFile(path) if contains := string(body); contains == "" || stringContains(contains, "repo_password:") { t.Errorf("repo_password should be gone after legacy clear, got:\n%s", contains) } } func stringContains(haystack, needle string) bool { for i := 0; i+len(needle) <= len(haystack); i++ { if haystack[i:i+len(needle)] == needle { return true } } return false }