Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pkg/environment/environment_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-FileCopyrightText: Copyright 2026 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package environment
Expand Down Expand Up @@ -43,6 +43,10 @@ func (*mockSecretsProvider) ListSecrets(_ context.Context) ([]secrets.SecretDesc
return nil, nil
}

func (*mockSecretsProvider) BulkDeleteSecrets(_ context.Context, _ []string) error {
return nil
}

func (*mockSecretsProvider) Cleanup() error {
return nil
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/secrets/1password.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-FileCopyrightText: Copyright 2026 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package secrets
Expand Down Expand Up @@ -92,6 +92,11 @@ func (o *OnePasswordManager) ListSecrets(ctx context.Context) ([]SecretDescripti
return secrets, nil
}

// BulkDeleteSecrets is a no-op for the 1Password provider (read-only).
func (*OnePasswordManager) BulkDeleteSecrets(_ context.Context, _ []string) error {
return nil
}

// Cleanup is not needed for 1Password.
func (*OnePasswordManager) Cleanup() error {
return nil
Expand Down
12 changes: 11 additions & 1 deletion pkg/secrets/encrypted.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-FileCopyrightText: Copyright 2026 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package secrets
Expand Down Expand Up @@ -89,6 +89,16 @@ func (e *EncryptedManager) ListSecrets(_ context.Context) ([]SecretDescription,
return secretNames, nil
}

// BulkDeleteSecrets removes all named keys from the store.
func (e *EncryptedManager) BulkDeleteSecrets(_ context.Context, keys []string) error {
return fileutils.WithFileLock(e.filePath, func() error {
for _, key := range keys {
e.secrets.Delete(key)
}
return e.updateFile()
})
}

// Cleanup removes all secrets managed by this manager.
func (e *EncryptedManager) Cleanup() error {
return fileutils.WithFileLock(e.filePath, func() error {
Expand Down
56 changes: 55 additions & 1 deletion pkg/secrets/encrypted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,61 @@ func TestEncryptedManager_Concurrency(t *testing.T) {
}
}

// End of tests
func TestEncryptedManager_BulkDeleteSecrets(t *testing.T) {
t.Parallel()
ctx := t.Context()

tempFile := createTempFile(t)
defer os.Remove(tempFile)

key := generateRandomKey(t)
manager := createEncryptedManager(t, tempFile, key)

require.NoError(t, manager.SetSecret(ctx, "key1", "value1"), "Setting key1 should not return an error")
require.NoError(t, manager.SetSecret(ctx, "key2", "value2"), "Setting key2 should not return an error")
require.NoError(t, manager.SetSecret(ctx, "key3", "value3"), "Setting key3 should not return an error")

// Case 1: Deletes specified keys, leaves others untouched.
err := manager.BulkDeleteSecrets(ctx, []string{"key1", "key2"})
assert.NoError(t, err, "BulkDeleteSecrets should not return an error")

_, err = manager.GetSecret(ctx, "key1")
assert.Error(t, err, "key1 should have been deleted")
assert.Contains(t, err.Error(), "not found", "Error should indicate key1 was not found")

_, err = manager.GetSecret(ctx, "key2")
assert.Error(t, err, "key2 should have been deleted")
assert.Contains(t, err.Error(), "not found", "Error should indicate key2 was not found")

value3, err := manager.GetSecret(ctx, "key3")
assert.NoError(t, err, "key3 should still exist")
assert.Equal(t, "value3", value3, "key3 value should be unchanged")

// Case 2: Persists to disk — reload from the same file and verify only key3 remains.
reloaded := createEncryptedManager(t, tempFile, key)

_, err = reloaded.GetSecret(ctx, "key1")
assert.Error(t, err, "key1 should be gone after reload")

_, err = reloaded.GetSecret(ctx, "key2")
assert.Error(t, err, "key2 should be gone after reload")

reloadedValue3, err := reloaded.GetSecret(ctx, "key3")
assert.NoError(t, err, "key3 should persist across reload")
assert.Equal(t, "value3", reloadedValue3, "key3 value should match after reload")

// Case 3: Empty key list is a no-op.
err = manager.BulkDeleteSecrets(ctx, []string{})
assert.NoError(t, err, "BulkDeleteSecrets with empty list should not return an error")

remaining, err := manager.ListSecrets(ctx)
assert.NoError(t, err, "ListSecrets should not return an error after no-op bulk delete")
assert.Len(t, remaining, 1, "Only key3 should remain after no-op bulk delete")

// Case 4: Non-existent keys do not error.
err = manager.BulkDeleteSecrets(ctx, []string{"does-not-exist"})
assert.NoError(t, err, "BulkDeleteSecrets with non-existent key should not return an error")
}

// Helper functions
func createTempFile(t *testing.T) string {
Expand Down
7 changes: 6 additions & 1 deletion pkg/secrets/environment.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-FileCopyrightText: Copyright 2026 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package secrets
Expand Down Expand Up @@ -58,6 +58,11 @@ func (*EnvironmentProvider) ListSecrets(_ context.Context) ([]SecretDescription,
return nil, errors.New("environment provider does not support listing secrets for security reasons")
}

// BulkDeleteSecrets is a no-op for the environment provider (read-only).
func (*EnvironmentProvider) BulkDeleteSecrets(_ context.Context, _ []string) error {
return nil
}

// Cleanup is a no-op for environment provider
func (*EnvironmentProvider) Cleanup() error {
return nil
Expand Down
7 changes: 6 additions & 1 deletion pkg/secrets/fallback.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-FileCopyrightText: Copyright 2026 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package secrets
Expand Down Expand Up @@ -67,6 +67,11 @@ func (f *FallbackProvider) ListSecrets(ctx context.Context) ([]SecretDescription
return f.primary.ListSecrets(ctx)
}

// BulkDeleteSecrets delegates to the primary provider.
func (f *FallbackProvider) BulkDeleteSecrets(ctx context.Context, keys []string) error {
return f.primary.BulkDeleteSecrets(ctx, keys)
}

// Cleanup delegates to the primary provider
func (f *FallbackProvider) Cleanup() error {
return f.primary.Cleanup()
Expand Down
17 changes: 15 additions & 2 deletions pkg/secrets/mocks/mock_provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading