package credentials import ( "context" "errors" "fmt" "strconv" "strings" "sync" "testing" "time" ) func TestMemoryStorePutCreatesIndependentLeasesForUnchangedScope(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 || first.SecretRef == second.SecretRef { t.Fatalf("references = %#v and %#v, want independent leases", first, second) } if first.SecretRef == "" || first.CredentialVersion != "v1" || second.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) } if err := store.Release(context.Background(), first); err != nil { t.Fatalf("Release(first lease): %v", err) } if got, err := store.Resolve(context.Background(), second); err != nil || got != value { t.Fatalf("Resolve(second lease) = %#v, %v", got, err) } } 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 TestMemoryStorePutIncrementsVersionWithoutRevokingActiveLease(t *testing.T) { store, err := NewMemoryStore(2) 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 reused an active lease") } if newReference.CredentialVersion != "v2" { t.Fatalf("new CredentialVersion = %q, want v2", newReference.CredentialVersion) } old, err := store.Resolve(context.Background(), oldReference) if err != nil || old.Password != "old-password" { t.Fatalf("Resolve(active old lease) = %#v, %v", old, 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); !errors.Is(err, ErrCapacityExceeded) { t.Fatalf("Put(second lease at capacity) error = %v, want ErrCapacityExceeded", err) } if err := store.Release(context.Background(), reference); err != nil { t.Fatalf("Release(first lease): %v", err) } if _, err := store.Put(context.Background(), "provider-a", want); err != nil { t.Fatalf("Put(after lease release): %v", err) } } func TestMemoryStoreReleaseMakesCapacityReusable(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } first, err := store.Put(context.Background(), "provider-a", Value{Password: "first-password"}) if err != nil { t.Fatalf("Put(first): %v", err) } if err := store.Release(context.Background(), first); err != nil { t.Fatalf("Release(first): %v", err) } if _, err := store.Resolve(context.Background(), first); !errors.Is(err, ErrCredentialMissing) { t.Fatalf("Resolve(released) error = %v, want ErrCredentialMissing", err) } if _, err := store.Put(context.Background(), "provider-b", Value{Password: "second-password"}); err != nil { t.Fatalf("Put(after release): %v", err) } if err := store.Release(context.Background(), first); err != nil { t.Fatalf("Release(idempotent): %v", err) } } func TestMemoryStoreReleaseOfStaleReferencePreservesCurrentVersion(t *testing.T) { store, err := NewMemoryStore(2) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } stale, err := store.Put(context.Background(), "provider-a", Value{Password: "old-password"}) if err != nil { t.Fatalf("Put(old): %v", err) } current, err := store.Put(context.Background(), "provider-a", Value{Password: "new-password"}) if err != nil { t.Fatalf("Put(new): %v", err) } if err := store.Release(context.Background(), stale); err != nil { t.Fatalf("Release(stale): %v", err) } if _, err := store.Resolve(context.Background(), current); err != nil { t.Fatalf("Resolve(current): %v", err) } } func TestMemoryStoreEnsureCapacityOnlyGrowsLimit(t *testing.T) { store, err := NewMemoryStore(1) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } if err := store.EnsureCapacity(context.Background(), 2); err != nil { t.Fatalf("EnsureCapacity(2): %v", err) } if _, err := store.Put(context.Background(), "provider-a", Value{}); err != nil { t.Fatalf("Put(provider-a): %v", err) } if _, err := store.Put(context.Background(), "provider-b", Value{}); err != nil { t.Fatalf("Put(provider-b): %v", err) } if err := store.EnsureCapacity(context.Background(), 1); err != nil { t.Fatalf("EnsureCapacity(shrink request): %v", err) } if _, err := store.Put(context.Background(), "provider-c", Value{}); !errors.Is(err, ErrCapacityExceeded) { t.Fatalf("Put(provider-c) error = %v, want retained capacity 2", 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 TestMemoryStoreCreatesIndependentConcurrentLeases(t *testing.T) { const workers = 100 store, err := NewMemoryStore(workers) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } want := Value{Username: "alice", Password: "shared-password"} 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) } secretRefs := make(map[string]struct{}, workers) for reference := range references { if reference.CredentialVersion != "v1" { t.Errorf("concurrent version = %q, want v1", reference.CredentialVersion) } secretRefs[reference.SecretRef] = struct{}{} } if len(secretRefs) != workers { t.Fatalf("unique concurrent leases = %d, want %d", len(secretRefs), workers) } for secretRef := range secretRefs { got, err := store.Resolve(context.Background(), Reference{ SecretRef: secretRef, CredentialVersion: "v1", }) if err != nil || got != want { t.Fatalf("Resolve(concurrent lease) = %#v, %v", got, err) } } } func TestMemoryStoreSerializesConcurrentCredentialChanges(t *testing.T) { const workers = 100 store, err := NewMemoryStore(workers) if err != nil { t.Fatalf("NewMemoryStore(): %v", err) } type result struct { value Value reference Reference err error } 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) secretRefs := make(map[string]struct{}, workers) var latest result for current := range results { if current.err != nil { t.Fatalf("concurrent Put(): %v", current.err) } secretRefs[current.reference.SecretRef] = struct{}{} 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 len(secretRefs) != workers { t.Fatalf("unique leases = %d, want %d", len(secretRefs), 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) } } } }