mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 16:14:43 +00:00
fix(collaboration): harden delegated task isolation (#1486)
* feat(collaboration): isolate delegated artifacts and child runs Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution. * fix(collaboration): harden delegated task isolation Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces. * fix(collaboration): recover interrupted async tasks * fix(collaboration): normalize persisted child-run status --------- Co-authored-by: ntduc <ntduc@cpp.ai.vn>
This commit is contained in:
1 parent
496b7ffce6
commit
bb7712a9ff
186 files changed
+18858
-1233
No files matched your search
+15
-2
@@ -27,6 +27,8 @@ const (
|
||||
ExecDefaultTimeoutSeconds = 60
|
||||
ExecMinTimeoutSeconds = 1
|
||||
ExecMaxTimeoutSeconds = 3600
|
||||
|
||||
delegatedExecSandboxRequiredError = "delegated artifact exec requires an active sandbox manager and sandbox key; host execution is not allowed"
|
||||
)
|
||||
|
||||
// Dangerous command patterns organized into configurable deny groups.
|
||||
@@ -246,6 +248,14 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *Result {
|
||||
return ErrorResult("command contains invalid NUL byte")
|
||||
}
|
||||
|
||||
// Delegation artifact runs are a physical isolation boundary. Reject before
|
||||
// credential lookup, adapter preparation, approval prompts, or ordinary
|
||||
// command handling unless execution can be routed into an identified sandbox.
|
||||
if IsDelegationArtifactRun(ctx) &&
|
||||
(t.sandboxMgr == nil || ToolSandboxKeyFromCtx(ctx) == "") {
|
||||
return ErrorResult(delegatedExecSandboxRequiredError)
|
||||
}
|
||||
|
||||
// Normalize command before all deny checks: NFKC + zero-width strip prevents
|
||||
// Unicode-based pattern bypass while preserving functional command content.
|
||||
normalizedCommand := normalizeCommand(command)
|
||||
@@ -655,14 +665,17 @@ func (t *ExecTool) executeInSandbox(ctx context.Context, command, cwd, sandboxKe
|
||||
if err != nil {
|
||||
return ErrorResult(err.Error())
|
||||
}
|
||||
containerCwd, cwdErr := sandboxCwdForHostPath(cwd, mountWorkspace, sandbox.DefaultContainerWorkdir)
|
||||
containerCwd, cwdErr := sandboxCwdForHostPath(cwd, mountWorkspace, sandboxContainerWorkdir(ctx))
|
||||
if cwdErr != nil {
|
||||
return ErrorResult(fmt.Sprintf("sandbox path mapping: %v", cwdErr))
|
||||
}
|
||||
|
||||
sb, err := t.sandboxMgr.Get(ctx, sandboxKey, mountWorkspace, SandboxConfigFromCtx(ctx))
|
||||
sb, err := acquireToolSandbox(ctx, t.sandboxMgr, sandboxKey, mountWorkspace)
|
||||
if err != nil {
|
||||
if errors.Is(err, sandbox.ErrSandboxDisabled) {
|
||||
if IsDelegationArtifactRun(ctx) {
|
||||
return ErrorResult(delegatedExecSandboxRequiredError)
|
||||
}
|
||||
return t.executeOnHost(ctx, command, cwd)
|
||||
}
|
||||
// Docker unavailable (binary missing, daemon down) → fail closed.
|
||||
|
||||
Reference in new issue
Block a user