Browse Source

fix(onepassword): support native item IDs (#6073)

Chad McElligott 1 month ago
parent
commit
75cc4efe09

+ 1 - 1
providers/v1/onepassword/go.mod

@@ -10,7 +10,6 @@ require (
 	k8s.io/apiextensions-apiserver v0.35.0
 	k8s.io/apimachinery v0.35.0
 	k8s.io/client-go v0.35.0
-	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4
 	k8s.io/utils v0.0.0-20260108192941-914a6e750570
 	sigs.k8s.io/controller-runtime v0.23.1
 )
@@ -91,6 +90,7 @@ require (
 	gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	k8s.io/klog/v2 v2.130.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect
 	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
 	sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect

+ 12 - 2
providers/v1/onepassword/onepassword.go

@@ -22,6 +22,7 @@ import (
 	"errors"
 	"fmt"
 	"net/url"
+	"regexp"
 	"slices"
 	"sort"
 	"strings"
@@ -31,7 +32,6 @@ import (
 	"github.com/1Password/connect-sdk-go/connect"
 	"github.com/1Password/connect-sdk-go/onepassword"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/kube-openapi/pkg/validation/strfmt"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
@@ -502,6 +502,16 @@ func (provider *ProviderOnePassword) Close(_ context.Context) error {
 	return nil
 }
 
+// nativeItemIDPattern matches a 1Password item ID per the Connect
+// server OpenAPI spec (^[\da-z]{26}$). Despite being called "UUIDs"
+// in 1Password's SDK and docs, they are not RFC 4122 UUIDs.
+// https://github.com/1Password/connect/blob/7485a59/docs/openapi/spec.yaml#L73-L75
+var nativeItemIDPattern = regexp.MustCompile(`^[\da-z]{26}$`)
+
+func isNativeItemID(s string) bool {
+	return nativeItemIDPattern.MatchString(s)
+}
+
 func (provider *ProviderOnePassword) findItem(name string) (*onepassword.Item, error) {
 	sortedVaults := sortVaults(provider.vaults)
 	for _, vaultName := range sortedVaults {
@@ -510,7 +520,7 @@ func (provider *ProviderOnePassword) findItem(name string) (*onepassword.Item, e
 			return nil, fmt.Errorf(errGetVault, err)
 		}
 
-		if strfmt.IsUUID(name) {
+		if isNativeItemID(name) {
 			return provider.client.GetItem(name, vault.ID)
 		}
 

+ 47 - 11
providers/v1/onepassword/onepassword_test.go

@@ -38,8 +38,9 @@ import (
 
 const (
 	// vaults and items.
-	myVault, myVaultID, myVaultUUID          = "my-vault", "my-vault-id", "39c31136-d086-47e9-a52c-8fe330d2669a"
-	myItem, myItemID, myItemUUID             = "my-item", "my-item-id", "687adbe7-e6d2-4059-9a62-dbb95d291143"
+	myVault, myVaultID                       = "my-vault", "my-vault-id"
+	myItem, myItemID                         = "my-item", "my-item-id"
+	myNativeItemID                           = "gdpvdudxrico74msloimk7qjna"
 	mySharedVault, mySharedVaultID           = "my-shared-vault", "my-shared-vault-id"
 	mySharedItem, mySharedItemID             = "my-shared-item", "my-shared-item-id"
 	myOtherVault, myOtherVaultID             = "my-other-vault", "my-other-vault-id"
@@ -120,22 +121,30 @@ func TestFindItem(t *testing.T) {
 			},
 		},
 		{
-			setupNote: "uuid: valid basic: one vault, one item, one field",
+			setupNote: "native item ID: one vault, one item, one field",
 			provider: &ProviderOnePassword{
-				vaults: map[string]int{myVaultUUID: 1},
+				vaults: map[string]int{myVault: 1},
 				client: fake.NewMockClient().
-					AddPredictableVaultUUID(myVaultUUID).
-					AddPredictableItemWithFieldUUID(myVaultUUID, myItemUUID, key1, value1),
+					AddPredictableVault(myVault).
+					AppendItem(myVaultID, onepassword.Item{
+						ID:    myNativeItemID,
+						Title: "My App (Production)",
+						Vault: onepassword.ItemVault{ID: myVaultID},
+					}).
+					AppendItemField(myVaultID, myNativeItemID, onepassword.ItemField{
+						Label: key1,
+						Value: value1,
+					}),
 			},
 			checks: []check{
 				{
-					checkNote:    "pass",
-					findItemName: myItemUUID,
+					checkNote:    "find by native item ID",
+					findItemName: myNativeItemID,
 					expectedErr:  nil,
 					expectedItem: &onepassword.Item{
-						ID:    myItemUUID,
-						Title: myItemUUID,
-						Vault: onepassword.ItemVault{ID: myVaultUUID},
+						ID:    myNativeItemID,
+						Title: "My App (Production)",
+						Vault: onepassword.ItemVault{ID: myVaultID},
 						Fields: []*onepassword.ItemField{
 							{
 								Label: key1,
@@ -1584,6 +1593,33 @@ func TestSortVaults(t *testing.T) {
 	}
 }
 
+func TestIsNativeItemID(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    string
+		expected bool
+	}{
+		{"valid native ID", "gdpvdudxrico74msloimk7qjna", true},
+		{"valid native ID all letters", "abcdefghijklmnopqrstuvwxyz", true},
+		{"valid native ID with digits", "abcdefghij0123456789abcdef", true},
+		{"too short", "gdpvdudxrico74msloimk7qjn", false},
+		{"too long", "gdpvdudxrico74msloimk7qjnaa", false},
+		{"empty string", "", false},
+		{"contains uppercase", "Gdpvdudxrico74msloimk7qjna", false},
+		{"contains special char", "gdpvdudxrico7-msloimk7qjna", false},
+		{"RFC 4122 UUID", "687adbe7-e6d2-4059-9a62-dbb95d291143", false},
+		{"item title", "My App (Production)", false},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := isNativeItemID(tt.input)
+			if got != tt.expected {
+				t.Errorf("isNativeItemID(%q) = %v, want %v", tt.input, got, tt.expected)
+			}
+		})
+	}
+}
+
 func TestHasUniqueVaultNumbers(t *testing.T) {
 	type testCase struct {
 		vaults   map[string]int