Skip to content
Merged
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
8 changes: 8 additions & 0 deletions runtime/internal/launcher/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ func (m maliciousPattern) String() string {
return "a*a"
}

func (m maliciousPattern) ExpandID(secrets.ID) (secrets.ID, error) {
panic("implement me")
}

func (m maliciousPattern) ExpandPattern(secrets.Pattern) (secrets.Pattern, error) {
panic("implement me")
}

func testExternalPluginConfig(t *testing.T) p.Config {
t.Helper()
return p.Config{Version: api.MustNewVersion("v4"), Pattern: mockPattern, Logger: testhelper.TestLogger(t)}
Expand Down
8 changes: 8 additions & 0 deletions x/api/resolver/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ func (m maliciousPattern) String() string {
return "/"
}

func (m maliciousPattern) ExpandID(secrets.ID) (secrets.ID, error) {
panic("implement me")
}

func (m maliciousPattern) ExpandPattern(secrets.Pattern) (secrets.Pattern, error) {
panic("implement me")
}

func newGetSecretRequest(pattern secrets.Pattern) *connect.Request[resolverv1.GetSecretsRequest] {
return connect.NewRequest(resolverv1.GetSecretsRequest_builder{
Pattern: proto.String(pattern.String()),
Expand Down
36 changes: 36 additions & 0 deletions x/secrets/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package secrets

import (
"errors"
"fmt"
"strings"
)

var ErrInvalidPattern = errors.New("invalid pattern")
Expand Down Expand Up @@ -71,6 +73,9 @@ type Pattern interface {
Includes(other Pattern) bool
// String formats the [Pattern] as a string
String() string

ExpandID(other ID) (ID, error)
ExpandPattern(other Pattern) (Pattern, error)
}

type pattern string
Expand Down Expand Up @@ -118,6 +123,22 @@ func MustParsePattern(s string) Pattern {
return pattern(s)
}

func (p pattern) ExpandID(other ID) (ID, error) {
val, err := replace1(string(p), other.String())
if err != nil {
return nil, err
}
return id(val), err
}

func (p pattern) ExpandPattern(other Pattern) (Pattern, error) {
val, err := replace1(string(p), other.String())
if err != nil {
return nil, err
}
return pattern(val), err
}

// Filter returns a reduced [Pattern] that is subset equal to [filter].
// Returns false if there's no overlap between [filter] and [other].
// Examples:
Expand All @@ -134,3 +155,18 @@ func Filter(filter, other Pattern) (Pattern, bool) {
}
return nil, false
}

func replace1(original, other string) (string, error) {
components := split(original)
var candidates []int
for idx, val := range components {
if val == "**" {
candidates = append(candidates, idx)
}
}
if len(candidates) != 1 {
return "", fmt.Errorf("expand only supports one expansion glob, pattern %s has %d", original, len(candidates))
}
components[candidates[0]] = other

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we only have 1 replace wouldn't this end up like:

pattern: docker/**/bar/**
input ID: bob
output: docker/bob/bar/**

@joe0BAB joe0BAB Jan 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we could implement what you're describing, but right now it isn't. Instead if the candidate positions where we could replace are not equal 1, we return an error.

I'm hesitant to do this as eg the following could be a bit surprising:

pattern: docker/**/bar/**
input Pattern: bob/**
output: docker/bob/**/bar/**

🤷

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also complicates things as with

pattern: docker/**/bar/**
input ID: bob
output: docker/bob/bar/**

you're converting an ID into a pattern. Then it wouldn't be ExpandID(ID) (ID, error) anymore.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i was asking if the output would be not should be.

return strings.Join(components, "/"), nil
}
69 changes: 69 additions & 0 deletions x/secrets/pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,72 @@ func Test_Filter(t *testing.T) {
})
}
}

func Test_apply(t *testing.T) {
type query struct {
pattern string
result string
}
tests := []struct {
pattern string
queries []query
}{
{
pattern: "foo/bar/**",
queries: []query{
{
pattern: "baz",
result: "foo/bar/baz",
},
{
pattern: "**",
result: "foo/bar/**",
},
{
pattern: "**/*",
result: "foo/bar/**/*",
},
},
},
{
pattern: "**/*",
queries: []query{
{
pattern: "baz",
result: "baz/*",
},
{
pattern: "bar/baz",
result: "bar/baz/*",
},
{
pattern: "**",
result: "**/*",
},
},
},
{
pattern: "**/**",
queries: []query{
{
pattern: "**/bar",
},
},
},
}
for idx, test := range tests {
t.Run(fmt.Sprintf("%d - %s", idx, test.pattern), func(t *testing.T) {
for inner, query := range test.queries {
t.Run(fmt.Sprintf("%d-%d %s %s", idx, inner, test.pattern, query.pattern), func(t *testing.T) {
result, err := replace1(test.pattern, query.pattern)
if query.result == "" {
assert.Error(t, err, fmt.Sprintf("got: %s", result))
return
}
require.NoError(t, err, fmt.Sprintf("query: %s, expected out: %s", query.pattern, query.result))
assert.Equal(t, query.result, result)
})
}
})
}
}
Loading