package credentials import ( "context" "errors" "fmt" "strconv" "strings" "sync" "testing" "time" ) func TestMemoryStorePutIsIdempotentForUnchangedScope(t *testing.T) { store, err := NewMemoryStore(2) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } value := Value{Username: "alice", Password: "secret-password"} first, err := store.Put(context.Background(), "provider-a", value) if err != nil { t.Fatalf("Put(first): %v", err) } second, err := store.Put(context.Background(), "provider-a", value) if err != nil { t.Fatalf("Put(second): %v", err) } if first != second { t.Fatalf("second reference = %#v, want %#v", second, first) } if first.SecretRef == "" || first.CredentialVersion != "v1" { t.Fatalf("first reference = %#v, want opaque ref at v1", first) } for _, plaintext := range []string{"provider-a", value.Username, value.Password} { if strings.Contains(first.SecretRef, plaintext) { t.Fatalf("SecretRef %q contains plaintext %q", first.SecretRef, plaintext) } } got, err := store.Resolve(context.Background(), first) if err != nil { t.Fatalf("Resolve(): %v", err) } if got != value { t.Fatalf("Resolve() = %#v, want %#v", got, value) } } func TestCredentialFormattingRedactsSensitiveMaterial(t *testing.T) { value := Value{Username: "alice", Password: "secret-password"} for _, formatted := range []string{ fmt.Sprintf("%v", value), fmt.Sprintf("%+v", value), fmt.Sprintf("%#v", value), fmt.Sprintf("%s", value), fmt.Sprintf("%q", value), } { if strings.Contains(formatted, value.Password) { t.Fatalf("formatted Value exposes password: %s", formatted) } } store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } reference, err := store.Put(context.Background(), "provider-secret-scope", value) if err != nil { t.Fatalf("Put(): %v", err) } for _, formatted := range []string{ fmt.Sprintf("%v", store), fmt.Sprintf("%+v", store), fmt.Sprintf("%#v", store), fmt.Sprintf("%s", store), fmt.Sprintf("%q", store), } { for _, secret := range []string{ "provider-secret-scope", value.Username, value.Password, reference.SecretRef, } { if strings.Contains(formatted, secret) { t.Fatalf("formatted MemoryStore exposes sensitive material: %s", formatted) } } } } func TestMemoryStorePutIncrementsVersionAndRejectsStaleReference(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } oldReference, err := store.Put(context.Background(), "provider-a", Value{ Username: "alice", Password: "old-password", }) if err != nil { t.Fatalf("Put(old): %v", err) } want := Value{Username: "alice", Password: "new-password"} newReference, err := store.Put(context.Background(), "provider-a", want) if err != nil { t.Fatalf("Put(new): %v", err) } if newReference.SecretRef != oldReference.SecretRef { t.Fatalf("new SecretRef changed across versions") } if newReference.CredentialVersion != "v2" { t.Fatalf("new CredentialVersion = %q, want v2", newReference.CredentialVersion) } if _, err := store.Resolve(context.Background(), oldReference); !errors.Is(err, ErrCredentialVersionMismatch) { t.Fatalf("Resolve(stale) error = %v, want ErrCredentialVersionMismatch", err) } got, err := store.Resolve(context.Background(), newReference) if err != nil { t.Fatalf("Resolve(new): %v", err) } if got != want { t.Fatalf("Resolve(new) returned unexpected credentials") } } func TestMemoryStoreEnforcesCapacityWithoutChangingExistingCredentials(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } want := Value{Username: "alice", Password: "first-password"} reference, err := store.Put(context.Background(), "provider-a", want) if err != nil { t.Fatalf("Put(first scope): %v", err) } if _, err := store.Put(context.Background(), "provider-b", Value{ Username: "bob", Password: "second-password", }); !errors.Is(err, ErrCapacityExceeded) { t.Fatalf("Put(over capacity) error = %v, want ErrCapacityExceeded", err) } got, err := store.Resolve(context.Background(), reference) if err != nil { t.Fatalf("Resolve(existing): %v", err) } if got != want { t.Fatalf("Resolve(existing) returned changed credentials") } if _, err := store.Put(context.Background(), "provider-a", want); err != nil { t.Fatalf("Put(idempotent at capacity): %v", err) } } func TestMemoryStoreStrictlyValidatesCredentialVersion(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } reference, err := store.Put(context.Background(), "provider-a", Value{Password: "password"}) if err != nil { t.Fatalf("Put(): %v", err) } for _, version := range []string{"", "v0", "v01", "1", "latest", "v-1"} { invalid := reference invalid.CredentialVersion = version if _, err := store.Resolve(context.Background(), invalid); !errors.Is(err, ErrInvalidReference) { t.Fatalf("Resolve(version %q) error = %v, want ErrInvalidReference", version, err) } } if _, err := store.Put(context.Background(), " \t\n", Value{}); !errors.Is(err, ErrInvalidScope) { t.Fatalf("Put(blank scope) error = %v, want ErrInvalidScope", err) } } func TestMemoryStoreValidatesCapacityAndHonorsCancellation(t *testing.T) { if _, err := NewMemoryStore(0); !errors.Is(err, ErrInvalidCapacity) { t.Fatalf("NewMemoryStore(0) error = %v, want ErrInvalidCapacity", err) } store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(1): %v", err) } canceled, cancel := context.WithCancel(context.Background()) cancel() if _, err := store.Put(canceled, "provider-a", Value{}); !errors.Is(err, context.Canceled) { t.Fatalf("Put(canceled) error = %v, want context.Canceled", err) } if _, err := store.Resolve(canceled, Reference{ SecretRef: "cred_000000000000000000000000000000000000000000000000", CredentialVersion: "v1", }); !errors.Is(err, context.Canceled) { t.Fatalf("Resolve(canceled) error = %v, want context.Canceled", err) } } func TestMemoryStoreRejectsNilAndZeroValueStores(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() for _, store := range []*MemoryStore{nil, {}} { if _, err := store.Put(ctx, "provider-a", Value{}); !errors.Is(err, ErrInvalidStore) { t.Fatalf("Put() error = %v, want ErrInvalidStore", err) } if _, err := store.Resolve(ctx, Reference{ SecretRef: "cred_000000000000000000000000000000000000000000000000", CredentialVersion: "v1", }); !errors.Is(err, ErrInvalidStore) { t.Fatalf("Resolve() error = %v, want ErrInvalidStore", err) } } } func TestMemoryStoreIsConcurrencySafeAndIdempotent(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } want := Value{Username: "alice", Password: "shared-password"} const workers = 100 references := make(chan Reference, workers) errorsSeen := make(chan error, workers) var wait sync.WaitGroup for range workers { wait.Add(1) go func() { defer wait.Done() reference, err := store.Put(context.Background(), "provider-a", want) if err != nil { errorsSeen <- err return } references <- reference }() } wait.Wait() close(references) close(errorsSeen) for err := range errorsSeen { t.Errorf("concurrent Put(): %v", err) } var first Reference for reference := range references { if first == (Reference{}) { first = reference } if reference != first { t.Errorf("concurrent Put() reference differs from first") } } if first.CredentialVersion != "v1" { t.Fatalf("concurrent version = %q, want v1", first.CredentialVersion) } got, err := store.Resolve(context.Background(), first) if err != nil { t.Fatalf("Resolve(): %v", err) } if got != want { t.Fatalf("Resolve() returned unexpected credentials") } } func TestMemoryStoreSerializesConcurrentCredentialChanges(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } type result struct { value Value reference Reference err error } const workers = 100 results := make(chan result, workers) var wait sync.WaitGroup for index := range workers { wait.Add(1) go func() { defer wait.Done() value := Value{Username: "alice", Password: "password-" + strconv.Itoa(index)} reference, err := store.Put(context.Background(), "provider-a", value) results <- result{value: value, reference: reference, err: err} }() } wait.Wait() close(results) versions := make(map[string]struct{}, workers) var secretRef string var latest result for current := range results { if current.err != nil { t.Fatalf("concurrent Put(): %v", current.err) } if secretRef == "" { secretRef = current.reference.SecretRef } if current.reference.SecretRef != secretRef { t.Fatal("SecretRef changed across concurrent updates") } versions[current.reference.CredentialVersion] = struct{}{} if current.reference.CredentialVersion == "v100" { latest = current } } if len(versions) != workers { t.Fatalf("unique versions = %d, want %d", len(versions), workers) } if latest.reference == (Reference{}) { t.Fatal("highest version v100 was not returned") } got, err := store.Resolve(context.Background(), latest.reference) if err != nil { t.Fatalf("Resolve(latest): %v", err) } if got != latest.value { t.Fatal("Resolve(latest) returned a different concurrent write") } } func TestMemoryStoreErrorsDoNotExposeInputs(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } value := Value{Username: "sensitive-user", Password: "sensitive-password"} reference, err := store.Put(context.Background(), "sensitive-scope", value) if err != nil { t.Fatalf("Put(): %v", err) } _, capacityErr := store.Put(context.Background(), "other-sensitive-scope", value) unknown := Reference{ SecretRef: "sensitive-secret-ref", CredentialVersion: "v1", } _, missingErr := store.Resolve(context.Background(), unknown) stale := reference stale.CredentialVersion = "v2" _, versionErr := store.Resolve(context.Background(), stale) for _, operationErr := range []error{capacityErr, missingErr, versionErr} { if operationErr == nil { t.Fatal("operation unexpectedly succeeded") } for _, sensitive := range []string{ "sensitive-scope", "other-sensitive-scope", value.Username, value.Password, unknown.SecretRef, reference.SecretRef, } { if strings.Contains(operationErr.Error(), sensitive) { t.Fatalf("error exposes sensitive input: %v", operationErr) } } } }