mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-04-10 08:36:35 +00:00
fix(storage): strip Root prefix from S3 List() returned paths (#1413)
This commit is contained in:
@@ -138,7 +138,7 @@ func (s *s3Storage) List(ctx context.Context, path string) ([]ObjectInfo, error)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
objects = append(objects, ObjectInfo{
|
objects = append(objects, ObjectInfo{
|
||||||
Path: aws.ToString(obj.Key),
|
Path: s.pathFromKey(aws.ToString(obj.Key)),
|
||||||
Size: aws.ToInt64(obj.Size),
|
Size: aws.ToInt64(obj.Size),
|
||||||
ModTime: aws.ToTime(obj.LastModified),
|
ModTime: aws.ToTime(obj.LastModified),
|
||||||
})
|
})
|
||||||
@@ -147,6 +147,13 @@ func (s *s3Storage) List(ctx context.Context, path string) ([]ObjectInfo, error)
|
|||||||
return objects, nil
|
return objects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *s3Storage) pathFromKey(key string) string {
|
||||||
|
if s.prefix == "" {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(key, s.prefix+"/")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *s3Storage) Walk(ctx context.Context, root string, fn func(ObjectInfo) error) error {
|
func (s *s3Storage) Walk(ctx context.Context, root string, fn func(ObjectInfo) error) error {
|
||||||
objects, err := s.List(ctx, root)
|
objects, err := s.List(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -35,6 +35,50 @@ func TestS3Helpers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("pathFromKey strips prefix to honor relative-path contract", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
prefix string
|
||||||
|
key string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{name: "no prefix returns key unchanged", prefix: "", key: "images/logo.png", expected: "images/logo.png"},
|
||||||
|
{name: "no prefix empty key", prefix: "", key: "", expected: ""},
|
||||||
|
{name: "prefix matches and is stripped", prefix: "data/uploads", key: "data/uploads/application-images/logo.svg", expected: "application-images/logo.svg"},
|
||||||
|
{name: "single-segment prefix stripped", prefix: "root", key: "root/foo/bar.txt", expected: "foo/bar.txt"},
|
||||||
|
{name: "prefix equal to key without trailing slash is unchanged", prefix: "root", key: "root", expected: "root"},
|
||||||
|
{name: "key without expected prefix returned unchanged", prefix: "data/uploads", key: "other/path.txt", expected: "other/path.txt"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
s := &s3Storage{
|
||||||
|
bucket: "bucket",
|
||||||
|
prefix: tc.prefix,
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.expected, s.pathFromKey(tc.key))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("pathFromKey is the inverse of buildObjectKey for clean paths", func(t *testing.T) {
|
||||||
|
paths := []string{
|
||||||
|
"images/logo.png",
|
||||||
|
"application-images/logo.svg",
|
||||||
|
"oidc-client-images/abc.png",
|
||||||
|
"deeply/nested/file.bin",
|
||||||
|
}
|
||||||
|
prefixes := []string{"", "root", "data/uploads"}
|
||||||
|
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
for _, p := range paths {
|
||||||
|
s := &s3Storage{bucket: "bucket", prefix: prefix}
|
||||||
|
assert.Equal(t, p, s.pathFromKey(s.buildObjectKey(p)),
|
||||||
|
"round-trip failed for prefix=%q path=%q", prefix, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("isS3NotFound detects expected errors", func(t *testing.T) {
|
t.Run("isS3NotFound detects expected errors", func(t *testing.T) {
|
||||||
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NoSuchKey"}))
|
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NoSuchKey"}))
|
||||||
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NotFound"}))
|
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NotFound"}))
|
||||||
|
|||||||
Reference in New Issue
Block a user