package publish import ( "encoding/json" "errors" "os" "os/exec" "path/filepath" "strings" "testing" ) func recordGit(t *testing.T, dir string, args ...string) string { t.Helper() cmd := exec.Command("git", append([]string{"-C", dir}, args...)...) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("git %v: %v: %s", args, err, out) } return string(out) } func recordRepo(t *testing.T) string { t.Helper() dir := t.TempDir() recordGit(t, dir, "init", "-q") recordGit(t, dir, "config", "user.name", "Test") recordGit(t, dir, "config", "user.email", "test@example.invalid") if err := os.WriteFile(filepath.Join(dir, "file"), []byte("x"), 0600); err != nil { t.Fatal(err) } recordGit(t, dir, "add", "file") recordGit(t, dir, "commit", "-qm", "init") return dir } func TestLoadEvidenceAcceptsPartialAndRejectsMalformedRecords(t *testing.T) { dir := t.TempDir() partial := filepath.Join(dir, "partial.json") if err := os.WriteFile(partial, []byte(`{"format_version":1,"evidence":{}}`), 0600); err != nil { t.Fatal(err) } got, err := LoadEvidence(partial) if err != nil || got != (Evidence{}) { t.Fatalf("partial record = %#v, %v", got, err) } for name, data := range map[string]string{"bad-json": "{", "unsupported": `{"format_version":2,"evidence":{}}`, "type": `{"format_version":1,"evidence":{"tag":false}}`, "trailing": `{"format_version":1,"evidence":{}} {}`} { t.Run(name, func(t *testing.T) { path := filepath.Join(dir, name) if err := os.WriteFile(path, []byte(data), 0600); err != nil { t.Fatal(err) } _, err := LoadEvidence(path) var recovery *RecoveryError if !errors.As(err, &recovery) || recovery.Kind != "record_format" { t.Fatalf("LoadEvidence() error=%v", err) } }) } } func TestLoadEvidenceReadFailureHasTypedError(t *testing.T) { _, err := LoadEvidence(filepath.Join(t.TempDir(), "missing.json")) var recovery *RecoveryError if !errors.As(err, &recovery) || recovery.Kind != "record_read" || !errors.Is(err, os.ErrNotExist) { t.Fatalf("LoadEvidence() error = %v", err) } } func TestSaveEvidenceUsesPrivateUniqueRecordsAndLinkedWorktreeMetadata(t *testing.T) { repo := recordRepo(t) worktree := filepath.Join(t.TempDir(), "linked") recordGit(t, repo, "worktree", "add", "--detach", worktree) evidence := Evidence{Tag: "v1.2.3", Endpoint: "https://user:secret@example.invalid/repo.git"} first, err := SaveEvidence(worktree, "", evidence) if err != nil { t.Fatal(err) } second, err := SaveEvidence(worktree, "", evidence) if err != nil { t.Fatal(err) } if first == second { t.Fatalf("record paths collided: %q", first) } common := recordGit(t, repo, "rev-parse", "--path-format=absolute", "--git-common-dir") wantDir := filepath.Join(strings.TrimSpace(common), "releasekit", "publication-attempts") if filepath.Dir(first) != wantDir { t.Fatalf("record dir=%q want %q", filepath.Dir(first), wantDir) } dirInfo, err := os.Stat(wantDir) if err != nil { t.Fatal(err) } if dirInfo.Mode().Perm() != 0700 { t.Fatalf("record directory permissions=%o", dirInfo.Mode().Perm()) } info, err := os.Stat(first) if err != nil { t.Fatal(err) } if info.Mode().Perm() != 0600 { t.Fatalf("record permissions=%o", info.Mode().Perm()) } loaded, err := LoadEvidence(first) if err != nil { t.Fatal(err) } if loaded.Endpoint != evidence.Endpoint || loaded.RecordedAt == "" { t.Fatalf("loaded evidence=%#v", loaded) } var envelope map[string]json.RawMessage data, err := os.ReadFile(first) if err != nil { t.Fatal(err) } if err := json.Unmarshal(data, &envelope); err != nil { t.Fatal(err) } if !strings.Contains(string(data), "user:secret@example.invalid") { t.Fatal("private record did not retain the exact endpoint") } } func TestSaveEvidenceResolvesRelativeAndIgnoredOverrides(t *testing.T) { repo := recordRepo(t) if err := os.WriteFile(filepath.Join(repo, ".gitignore"), []byte("saved-records/\n"), 0600); err != nil { t.Fatal(err) } if _, err := SaveEvidence(repo, "saved-records", Evidence{Tag: "v1.2.3"}); err != nil { t.Fatalf("ignored override: %v", err) } if _, err := os.Stat(filepath.Join(repo, "saved-records")); err != nil { t.Fatal(err) } external := filepath.Join(t.TempDir(), "external-store") path, err := SaveEvidence(repo, external, Evidence{Tag: "v2.0.0"}) if err != nil || !strings.HasPrefix(path, external+string(filepath.Separator)) { t.Fatalf("absolute external override path=%q error=%v", path, err) } } func TestSaveEvidenceRejectsUnignoredOverrideInsideWorktree(t *testing.T) { repo := recordRepo(t) _, err := SaveEvidence(repo, "records", Evidence{Tag: "v1.2.3"}) var recovery *RecoveryError if !errors.As(err, &recovery) || recovery.Kind != "record_write" { t.Fatalf("SaveEvidence() error=%v", err) } if _, err := os.Stat(filepath.Join(repo, "records")); err != nil { t.Fatalf("expected parent directory to exist without record: %v", err) } if _, err := os.Stat(filepath.Join(repo, "records", "attempt")); !os.IsNotExist(err) { t.Fatalf("unexpected record: %v", err) } }