Переглянути джерело

fix: provider/infisical provider sub-folder references in remoteRef.key (#6338)

Co-authored-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Signed-off-by: Daniel <daniel@infisical.com>
Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
varonix 1 місяць тому
батько
коміт
0755b0af7d
2 змінених файлів з 39 додано та 34 видалено
  1. 18 20
      providers/v1/infisical/client.go
  2. 21 14
      providers/v1/infisical/client_test.go

+ 18 - 20
providers/v1/infisical/client.go

@@ -22,6 +22,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"path"
 	"strings"
 
 	infisical "github.com/infisical/go-sdk"
@@ -53,38 +54,35 @@ func getPropertyValue(jsonData, propertyName, keyName string) ([]byte, error) {
 	return []byte(result.Str), nil
 }
 
-// getSecretAddress returns the path and key from the given key.
+// getSecretAddress returns the (folder, name) pair to look up in Infisical for the given key.
 //
-// Users can configure a root path, and when a SecretKey is provided with a slash we assume that it is
-// within a path appended to the root path.
-//
-// If the key is not addressing a path at all (i.e. has no `/`), simply return the original
-// path and key.
-func getSecretAddress(defaultPath, key string) (string, string, error) {
+// Resolution rules:
+//   - No slash in key: treat key as a bare secret name in defaultPath.
+//     ("foo" + defaultPath="/scope")            -> ("/scope", "foo")
+//   - Key starts with `/`: treat key as an absolute path; defaultPath is ignored.
+//     ("/a/b/foo" + defaultPath="/scope")       -> ("/a/b", "foo")
+//   - Otherwise (slash present, no leading `/`): treat key as a folder path relative to defaultPath.
+//     ("sub/foo" + defaultPath="/scope")        -> ("/scope/sub", "foo")
+func getSecretAddress(defaultPath, key string) (string, string) {
 	if !strings.Contains(key, "/") {
-		return defaultPath, key, nil
+		return defaultPath, key
 	}
 
-	// Check if `key` starts with a `/`, and throw and error if it does not.
-	if !strings.HasPrefix(key, "/") {
-		return "", "", fmt.Errorf("a secret key referencing a folder must start with a '/' as it is an absolute path, key: %s", key)
+	lastIndex := strings.LastIndex(key, "/")
+	folder, name := key[:lastIndex], key[lastIndex+1:]
+
+	if strings.HasPrefix(key, "/") {
+		return folder, name
 	}
 
-	// Otherwise, take the prefix from `key` and use that as the path. We intentionally discard
-	// `defaultPath`.
-	lastIndex := strings.LastIndex(key, "/")
-	return key[:lastIndex], key[lastIndex+1:], nil
+	return path.Join(defaultPath, folder), name
 }
 
 // GetSecret retrieves a secret value from Infisical.
 // If this returns an error with type NoSecretError then the secret entry will be deleted depending on the
 // deletionPolicy.
 func (p *Provider) GetSecret(_ context.Context, ref esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	path, key, err := getSecretAddress(p.apiScope.SecretPath, ref.Key)
-	if err != nil {
-		return nil, err
-	}
-
+	path, key := getSecretAddress(p.apiScope.SecretPath, ref.Key)
 	secret, err := p.sdkClient.Secrets().Retrieve(infisical.RetrieveSecretOptions{
 		Environment:            p.apiScope.EnvironmentSlug,
 		ProjectSlug:            p.apiScope.ProjectSlug,

+ 21 - 14
providers/v1/infisical/client_test.go

@@ -24,41 +24,48 @@ import (
 
 func TestGetSecretAddress(t *testing.T) {
 	t.Run("when the key is not addressing a path and uses the default path", func(t *testing.T) {
-		path, key, err := getSecretAddress("/", "foo")
-		assert.NoError(t, err)
+		path, key := getSecretAddress("/", "foo")
 		assert.Equal(t, "/", path)
 		assert.Equal(t, "foo", key)
 
-		path, key, err = getSecretAddress("/foo", "bar")
-		assert.NoError(t, err)
+		path, key = getSecretAddress("/foo", "bar")
 		assert.Equal(t, "/foo", path)
 		assert.Equal(t, "bar", key)
 	})
 
 	t.Run("when the key is addressing a path", func(t *testing.T) {
-		path, key, err := getSecretAddress("/", "/foo/bar")
-		assert.NoError(t, err)
+		path, key := getSecretAddress("/", "/foo/bar")
 		assert.Equal(t, path, "/foo")
 		assert.Equal(t, key, "bar")
 	})
 
 	t.Run("when the key is addressing a path and ignores the default path", func(t *testing.T) {
-		path, key, err := getSecretAddress("/foo", "/bar/baz")
-		assert.NoError(t, err)
+		path, key := getSecretAddress("/foo", "/bar/baz")
 		assert.Equal(t, "/bar", path)
 		assert.Equal(t, "baz", key)
 	})
 
 	t.Run("works with a nested directory", func(t *testing.T) {
-		path, key, err := getSecretAddress("/", "/foo/bar/baz")
-		assert.NoError(t, err)
+		path, key := getSecretAddress("/", "/foo/bar/baz")
 		assert.Equal(t, "/foo/bar", path)
 		assert.Equal(t, "baz", key, "baz")
 	})
 
-	t.Run("fails when the key is a folder but does not begin with a slash", func(t *testing.T) {
-		_, _, err := getSecretAddress("/", "bar/baz")
-		assert.Error(t, err)
-		assert.Equal(t, err.Error(), "a secret key referencing a folder must start with a '/' as it is an absolute path, key: bar/baz")
+	t.Run("relative key joins onto the default path", func(t *testing.T) {
+		path, key := getSecretAddress("/secrets/mysql-core", "azure/admin-users")
+		assert.Equal(t, "/secrets/mysql-core/azure", path)
+		assert.Equal(t, "admin-users", key)
+	})
+
+	t.Run("relative key with default root path", func(t *testing.T) {
+		path, key := getSecretAddress("/", "azure/admin-users")
+		assert.Equal(t, "/azure", path)
+		assert.Equal(t, "admin-users", key)
+	})
+
+	t.Run("relative key with nested folders", func(t *testing.T) {
+		path, key := getSecretAddress("/scope", "a/b/c/name")
+		assert.Equal(t, "/scope/a/b/c", path)
+		assert.Equal(t, "name", key)
 	})
 }