Feat v0.8.0 files sandbox module
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Has been skipped
CI/CD / test-runners (pull_request) Has been skipped
CI/CD / e2e-smoke (pull_request) Has been skipped
CI/CD / test-go-pg (pull_request) Successful in 2m44s
CI/CD / test-sqlite (pull_request) Successful in 2m57s
CI/CD / build-and-deploy (pull_request) Successful in 1m25s

Bridge ObjectStore (PVC/S3) into the Starlark sandbox with extension-scoped
key namespacing. New files module with put/get/meta/list/delete/exists
builtins gated by files.read and files.write permissions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 00:14:28 +00:00
parent 3b74774077
commit 5b72ed254f
13 changed files with 1169 additions and 5 deletions

View File

@@ -232,6 +232,49 @@ func (s *S3Store) Exists(ctx context.Context, key string) (bool, error) {
return true, nil
}
// List returns objects under the given prefix, up to limit entries.
func (s *S3Store) List(ctx context.Context, prefix string, limit int) ([]ObjectEntry, error) {
if prefix != "" {
if err := validateKey(prefix); err != nil {
return nil, err
}
}
if limit <= 0 {
limit = 100
}
fullPrefix := s.fullKey(prefix)
objectsCh := s.client.ListObjects(ctx, s.bucket, minio.ListObjectsOptions{
Prefix: fullPrefix,
Recursive: true,
})
var entries []ObjectEntry
for obj := range objectsCh {
if obj.Err != nil {
return entries, fmt.Errorf("storage/s3: list %q: %w", prefix, obj.Err)
}
if len(entries) >= limit {
// Drain the remaining channel entries (minio requires it).
for range objectsCh {
}
break
}
// Strip the s3 prefix to recover the storage key.
key := strings.TrimPrefix(obj.Key, s.prefix)
ct := obj.ContentType
if ct == "" {
ct = "application/octet-stream"
}
entries = append(entries, ObjectEntry{Key: key, Size: obj.Size, ContentType: ct})
}
return entries, nil
}
// Healthy checks connectivity by performing a HeadBucket.
func (s *S3Store) Healthy(ctx context.Context) error {
exists, err := s.client.BucketExists(ctx, s.bucket)