Browse Source

fix(onepasswordsdk): support native 1Password item IDs in findItem (#6167)

Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Leah Armstrong 1 week ago
parent
commit
fc364c7234

+ 12 - 2
providers/v1/onepasswordsdk/client.go

@@ -23,11 +23,11 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/1password/onepassword-sdk-go"
 	"github.com/1password/onepassword-sdk-go"
 	corev1 "k8s.io/api/core/v1"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/kube-openapi/pkg/validation/strfmt"
 
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	"github.com/external-secrets/external-secrets/runtime/constants"
 	"github.com/external-secrets/external-secrets/runtime/constants"
@@ -47,6 +47,16 @@ const (
 // ErrKeyNotFound is returned when a key is not found in the 1Password Vaults.
 // ErrKeyNotFound is returned when a key is not found in the 1Password Vaults.
 var ErrKeyNotFound = errors.New("key not found")
 var ErrKeyNotFound = errors.New("key not found")
 
 
+// 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)
+}
+
 // PushSecretMetadataSpec defines the metadata configuration for pushing secrets to 1Password.
 // PushSecretMetadataSpec defines the metadata configuration for pushing secrets to 1Password.
 type PushSecretMetadataSpec struct {
 type PushSecretMetadataSpec struct {
 	Tags []string `json:"tags,omitempty"`
 	Tags []string `json:"tags,omitempty"`
@@ -430,7 +440,7 @@ func (p *SecretsClient) findItem(ctx context.Context, name string) (onepassword.
 	var item onepassword.Item
 	var item onepassword.Item
 	var err error
 	var err error
 
 
-	if strfmt.IsUUID(name) {
+	if isNativeItemID(name) {
 		item, err = p.client.Items().Get(ctx, p.vaultID, name)
 		item, err = p.client.Items().Get(ctx, p.vaultID, name)
 		metrics.ObserveAPICall(constants.ProviderOnePasswordSDK, constants.CallOnePasswordSDKItemsGet, err)
 		metrics.ObserveAPICall(constants.ProviderOnePasswordSDK, constants.CallOnePasswordSDKItemsGet, err)
 		if err != nil {
 		if err != nil {

+ 27 - 0
providers/v1/onepasswordsdk/client_test.go

@@ -1189,3 +1189,30 @@ var _ onepassword.VaultsAPI = &fakeClient{}
 var _ onepassword.ItemsAPI = &fakeLister{}
 var _ onepassword.ItemsAPI = &fakeLister{}
 var _ onepassword.SecretsAPI = &fakeClientWithCounter{}
 var _ onepassword.SecretsAPI = &fakeClientWithCounter{}
 var _ onepassword.ItemsAPI = &fakeListerWithCounter{}
 var _ onepassword.ItemsAPI = &fakeListerWithCounter{}
+
+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)
+			}
+		})
+	}
+}

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

@@ -10,7 +10,6 @@ require (
 	github.com/stretchr/testify v1.11.1
 	github.com/stretchr/testify v1.11.1
 	k8s.io/api v0.35.0
 	k8s.io/api v0.35.0
 	k8s.io/apimachinery v0.35.0
 	k8s.io/apimachinery v0.35.0
-	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4
 	sigs.k8s.io/controller-runtime v0.23.1
 	sigs.k8s.io/controller-runtime v0.23.1
 )
 )
 
 
@@ -96,6 +95,7 @@ require (
 	k8s.io/apiextensions-apiserver v0.35.0 // indirect
 	k8s.io/apiextensions-apiserver v0.35.0 // indirect
 	k8s.io/client-go v0.35.0 // indirect
 	k8s.io/client-go v0.35.0 // indirect
 	k8s.io/klog/v2 v2.130.1 // indirect
 	k8s.io/klog/v2 v2.130.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect
 	k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
 	k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
 	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
 	sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect