2026-11-02 19:03:24 +00:00
|
|
|
package releasekit_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2026-11-02 22:22:31 +00:00
|
|
|
"strings"
|
2026-11-02 19:03:24 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
releasekit "go.maximumdirect.net/releasekit"
|
|
|
|
|
)
|
|
|
|
|
|
2026-11-02 22:22:31 +00:00
|
|
|
func TestRecoveryFacadeRedactsSelectedPathAndRetainsRawCause(t *testing.T) {
|
|
|
|
|
path := "https://audit-user:audit-secret@example.invalid/attempt.json"
|
|
|
|
|
_, err := releasekit.LoadPublicationEvidence(path)
|
|
|
|
|
var recovery *releasekit.PublicationRecoveryError
|
|
|
|
|
var pathErr *os.PathError
|
|
|
|
|
if !errors.As(err, &recovery) || recovery.RecordPath != path || !errors.As(err, &pathErr) || pathErr.Path != path {
|
|
|
|
|
t.Fatalf("raw diagnostic context lost: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if strings.Contains(err.Error(), "audit-secret") || strings.Contains(err.Error(), "audit-user") {
|
|
|
|
|
t.Fatalf("credentials in displayed error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-11-02 19:03:24 +00:00
|
|
|
func TestRecoveryFacadeLoadsPartialEvidenceAndPreservesCause(t *testing.T) {
|
|
|
|
|
path := filepath.Join(t.TempDir(), "attempt.json")
|
|
|
|
|
if err := os.WriteFile(path, []byte(`{"format_version":1,"evidence":{}}`), 0600); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
evidence, err := releasekit.LoadPublicationEvidence(path)
|
|
|
|
|
if err != nil || evidence != (releasekit.PublicationEvidence{}) {
|
|
|
|
|
t.Fatalf("LoadPublicationEvidence()=%#v, %v", evidence, err)
|
|
|
|
|
}
|
|
|
|
|
result, err := releasekit.ReconcilePublication(context.Background(), evidence)
|
|
|
|
|
var recovery *releasekit.PublicationRecoveryError
|
|
|
|
|
if !errors.As(err, &recovery) || recovery.Kind != "missing_evidence" || result.State != releasekit.PublicationUnknown {
|
|
|
|
|
t.Fatalf("ReconcilePublication()=%#v, %v", result, err)
|
|
|
|
|
}
|
|
|
|
|
if len(recovery.MissingFields) != 2 || recovery.MissingFields[0] != "endpoint" || recovery.MissingFields[1] != "tag" {
|
|
|
|
|
t.Fatalf("missing fields=%v", recovery.MissingFields)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRecoveryFacadeErrorUnwrapsCancellation(t *testing.T) {
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
cancel()
|
|
|
|
|
_, err := releasekit.ReconcilePublication(ctx, releasekit.PublicationEvidence{Endpoint: "file:///unused", Tag: "v1.2.3"})
|
|
|
|
|
var recovery *releasekit.PublicationRecoveryError
|
|
|
|
|
if !errors.As(err, &recovery) || recovery.Kind != "canceled" || !errors.Is(err, context.Canceled) {
|
|
|
|
|
t.Fatalf("error=%v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-11-02 19:09:26 +00:00
|
|
|
|
|
|
|
|
func TestListPublicationAttemptsReadsExplicitExternalStore(t *testing.T) {
|
|
|
|
|
directory := t.TempDir()
|
|
|
|
|
good := filepath.Join(directory, "attempt-a.json")
|
|
|
|
|
if err := os.WriteFile(good, []byte(`{"format_version":1,"evidence":{"tag":"v1.2.3"}}`), 0600); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if err := os.WriteFile(filepath.Join(directory, "attempt-b.json"), []byte("{"), 0600); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
listed, err := releasekit.ListPublicationAttempts(context.Background(), releasekit.PublicationAttemptsRequest{RecordDir: directory})
|
|
|
|
|
if err != nil || listed.RecordDir != directory || len(listed.Attempts) != 1 || len(listed.Diagnostics) != 1 {
|
|
|
|
|
t.Fatalf("listing=%#v error=%v", listed, err)
|
|
|
|
|
}
|
|
|
|
|
if listed.Attempts[0].RecordPath != good || listed.Attempts[0].Evidence.Tag != "v1.2.3" || listed.Diagnostics[0].Kind != "record_format" {
|
|
|
|
|
t.Fatalf("listing=%#v", listed)
|
|
|
|
|
}
|
|
|
|
|
}
|