From 0307f230246186d9cdb7f85927419c6348bd2aa7 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 15 Feb 2026 14:03:50 -0800 Subject: [PATCH 1/3] Allow uppercase letters in secret names (closes #2) The isValidSecretName() regex only allowed lowercase letters [a-z], rejecting valid secret names containing uppercase characters (e.g. AWS access key IDs). Changed regex from ^[a-z0-9\.\-\_\/]+$ to ^[a-zA-Z0-9\.\-\_\/]+$ and added tests for uppercase secret names in both vault and secret packages. --- internal/secret/secret_test.go | 7 +++-- internal/vault/secrets.go | 4 +-- internal/vault/secrets_name_test.go | 42 +++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 internal/vault/secrets_name_test.go diff --git a/internal/secret/secret_test.go b/internal/secret/secret_test.go index c307d80..3639dd2 100644 --- a/internal/secret/secret_test.go +++ b/internal/secret/secret_test.go @@ -257,9 +257,10 @@ func isValidSecretName(name string) bool { if name == "" { return false } - // Valid characters for secret names: lowercase letters, numbers, dash, dot, underscore, slash + // Valid characters for secret names: letters, numbers, dash, dot, underscore, slash for _, char := range name { if (char < 'a' || char > 'z') && // lowercase letters + (char < 'A' || char > 'Z') && // uppercase letters (char < '0' || char > '9') && // numbers char != '-' && // dash char != '.' && // dot @@ -283,7 +284,9 @@ func TestSecretNameValidation(t *testing.T) { {"valid/path/name", true}, {"123valid", true}, {"", false}, - {"Invalid-Name", false}, // uppercase not allowed + {"Valid-Upper-Name", true}, // uppercase allowed + {"2025-11-21-ber1app1-vaultik-test-bucket-AKI", true}, // real-world uppercase key ID + {"MixedCase/Path/Name", true}, // mixed case with path {"invalid name", false}, // space not allowed {"invalid@name", false}, // @ not allowed } diff --git a/internal/vault/secrets.go b/internal/vault/secrets.go index 3452e0d..2c4c313 100644 --- a/internal/vault/secrets.go +++ b/internal/vault/secrets.go @@ -67,7 +67,7 @@ func (v *Vault) ListSecrets() ([]string, error) { return secrets, nil } -// isValidSecretName validates secret names according to the format [a-z0-9\.\-\_\/]+ +// isValidSecretName validates secret names according to the format [a-zA-Z0-9\.\-\_\/]+ // but with additional restrictions: // - No leading or trailing slashes // - No double slashes @@ -93,7 +93,7 @@ func isValidSecretName(name string) bool { } // Check the basic pattern - matched, _ := regexp.MatchString(`^[a-z0-9\.\-\_\/]+$`, name) + matched, _ := regexp.MatchString(`^[a-zA-Z0-9\.\-\_\/]+$`, name) return matched } diff --git a/internal/vault/secrets_name_test.go b/internal/vault/secrets_name_test.go new file mode 100644 index 0000000..205f8f3 --- /dev/null +++ b/internal/vault/secrets_name_test.go @@ -0,0 +1,42 @@ +package vault + +import "testing" + +func TestIsValidSecretNameUppercase(t *testing.T) { + tests := []struct { + name string + valid bool + }{ + // Lowercase (existing behavior) + {"valid-name", true}, + {"valid.name", true}, + {"valid_name", true}, + {"valid/path/name", true}, + {"123valid", true}, + + // Uppercase (new behavior - issue #2) + {"Valid-Upper-Name", true}, + {"2025-11-21-ber1app1-vaultik-test-bucket-AKI", true}, + {"MixedCase/Path/Name", true}, + {"ALLUPPERCASE", true}, + {"ABC123", true}, + + // Still invalid + {"", false}, + {"invalid name", false}, + {"invalid@name", false}, + {".dotstart", false}, + {"/leading-slash", false}, + {"trailing-slash/", false}, + {"double//slash", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isValidSecretName(tt.name) + if result != tt.valid { + t.Errorf("isValidSecretName(%q) = %v, want %v", tt.name, result, tt.valid) + } + }) + } +} -- 2.45.2 From 4f984cd9c6db5cb62066372bad74e2bae6508a4f Mon Sep 17 00:00:00 2001 From: clawbot Date: Thu, 19 Feb 2026 23:41:43 -0800 Subject: [PATCH 2/3] fix: suppress gosec G204 for validated GPG key ID inputs --- internal/secret/pgpunlocker.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/secret/pgpunlocker.go b/internal/secret/pgpunlocker.go index 1fedb17..bca1546 100644 --- a/internal/secret/pgpunlocker.go +++ b/internal/secret/pgpunlocker.go @@ -320,7 +320,9 @@ func ResolveGPGKeyFingerprint(keyID string) (string, error) { } // Use GPG to get the full fingerprint for the key - cmd := exec.Command("gpg", "--list-keys", "--with-colons", "--fingerprint", keyID) + cmd := exec.Command( // #nosec G204 -- keyID validated + "gpg", "--list-keys", "--with-colons", "--fingerprint", keyID, + ) output, err := cmd.Output() if err != nil { return "", fmt.Errorf("failed to resolve GPG key fingerprint: %w", err) @@ -359,7 +361,9 @@ func gpgEncryptDefault(data *memguard.LockedBuffer, keyID string) ([]byte, error return nil, fmt.Errorf("invalid GPG key ID: %w", err) } - cmd := exec.Command("gpg", "--trust-model", "always", "--armor", "--encrypt", "-r", keyID) + cmd := exec.Command( // #nosec G204 -- keyID validated + "gpg", "--trust-model", "always", "--armor", "--encrypt", "-r", keyID, + ) cmd.Stdin = strings.NewReader(data.String()) output, err := cmd.Output() -- 2.45.2 From e8339f4d120b62595c922236f499d840ca4477e6 Mon Sep 17 00:00:00 2001 From: clawbot Date: Thu, 19 Feb 2026 23:42:39 -0800 Subject: [PATCH 3/3] fix: update integration test to allow uppercase secret names --- internal/cli/integration_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/cli/integration_test.go b/internal/cli/integration_test.go index 66aea95..d995e58 100644 --- a/internal/cli/integration_test.go +++ b/internal/cli/integration_test.go @@ -1047,7 +1047,6 @@ func test12SecretNameFormats(t *testing.T, tempDir, testMnemonic string, runSecr // Test invalid secret names invalidNames := []string{ "", // empty - "UPPERCASE", // uppercase not allowed "with space", // spaces not allowed "with@symbol", // special characters not allowed "with#hash", // special characters not allowed @@ -1073,7 +1072,7 @@ func test12SecretNameFormats(t *testing.T, tempDir, testMnemonic string, runSecr // Some of these might not be invalid after all (e.g., leading/trailing slashes might be stripped, .hidden might be allowed) // For now, just check the ones we know should definitely fail - definitelyInvalid := []string{"", "UPPERCASE", "with space", "with@symbol", "with#hash", "with$dollar"} + definitelyInvalid := []string{"", "with space", "with@symbol", "with#hash", "with$dollar"} shouldFail := false for _, invalid := range definitelyInvalid { if invalidName == invalid { -- 2.45.2