Feat v0.8.1 workspace module
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 3s
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 2m47s
CI/CD / test-sqlite (pull_request) Successful in 2m55s
CI/CD / build-and-deploy (pull_request) Successful in 1m10s
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 3s
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 2m47s
CI/CD / test-sqlite (pull_request) Successful in 2m55s
CI/CD / build-and-deploy (pull_request) Successful in 1m10s
Managed disk directories for extensions needing real filesystem access
(git, compilers, media tools). Five builtins: create, path, list,
delete, usage. Extension-scoped to {WORKSPACE_ROOT}/{packageID}/{name}/.
- New sandbox/workspace_module.go with path traversal + symlink protection
- Permission: workspace.manage; config: WORKSPACE_ROOT, WORKSPACE_QUOTA_MB
- Runner wiring with graceful degradation (module absent if root unwritable)
- 16 new tests, all passing with -race
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,8 @@ type Runner struct {
|
||||
allowPrivateIPs bool
|
||||
bus *events.Bus
|
||||
objectStore storage.ObjectStore // nil = files module unavailable
|
||||
workspaceRoot string // empty = workspace module unavailable
|
||||
workspaceQuota int // MB, 0 = unlimited
|
||||
}
|
||||
|
||||
// NewRunner creates a runner with the given sandbox and dependencies.
|
||||
@@ -123,6 +125,13 @@ func (r *Runner) SetObjectStore(s storage.ObjectStore) {
|
||||
r.objectStore = s
|
||||
}
|
||||
|
||||
// SetWorkspaceRoot sets the base directory for extension workspaces.
|
||||
// quotaMB is the per-extension quota in MB (0 = unlimited).
|
||||
func (r *Runner) SetWorkspaceRoot(root string, quotaMB int) {
|
||||
r.workspaceRoot = root
|
||||
r.workspaceQuota = quotaMB
|
||||
}
|
||||
|
||||
// SetAllowPrivateIPs disables the SSRF check that blocks connections to
|
||||
// private/loopback IPs. For self-hosted environments where extensions
|
||||
// reach internal services. Controlled by EXT_ALLOW_PRIVATE_IPS env var.
|
||||
@@ -392,6 +401,15 @@ func (r *Runner) buildModulesWithLibCtx(ctx context.Context, packageID string, m
|
||||
modules["realtime"] = BuildRealtimeModule(ctx, r.bus, packageID)
|
||||
}
|
||||
|
||||
case models.ExtPermWorkspaceManage:
|
||||
if r.workspaceRoot != "" {
|
||||
modules["workspace"] = BuildWorkspaceModule(ctx, WorkspaceModuleConfig{
|
||||
PackageID: packageID,
|
||||
WorkspaceRoot: r.workspaceRoot,
|
||||
QuotaMB: r.workspaceQuota,
|
||||
})
|
||||
}
|
||||
|
||||
case models.ExtPermBatchExec:
|
||||
hasBatchExec = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user