mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-22 23:02:23 +02:00
feat(runtime): bind process and job resources to authority
This commit is contained in:
@@ -67,8 +67,20 @@ class ManageBgJobsTool:
|
||||
if not session_id:
|
||||
return {"error": "manage_bg_jobs: no active chat session; background jobs are scoped to a chat.", "exit_code": 1}
|
||||
|
||||
from src.agent_runtime.process_resources import active_process_operation, expected_job, require_process_admission
|
||||
from src.agent_runtime.resources import ResourceIdentityError
|
||||
bound = active_process_operation()
|
||||
if bound is None or (bound.owner, bound.thread_id) != (str(ctx.get("owner") or "").strip().casefold(), session_id):
|
||||
return {"error": "manage_bg_jobs: no exact server resource binding", "exit_code": 1,
|
||||
"blocked": True, "failure_kind": "resource_identity_denied"}
|
||||
from src.agent_runtime.authority import ExactOperation
|
||||
if bound.operation != ExactOperation.normalize("manage_bg_jobs", raw or "{}"):
|
||||
return {"error": "Job operation changed at producer entry", "exit_code": 1, "blocked": True}
|
||||
require_process_admission(bound)
|
||||
|
||||
if action in _LIST_ACTIONS:
|
||||
jobs: List[Dict[str, Any]] = bg_jobs.list_for_session(session_id)
|
||||
bound.validate()
|
||||
jobs: List[Dict[str, Any]] = [bg_jobs.peek(j.job_id) for j in bound.jobs]
|
||||
if not jobs:
|
||||
return {"output": "No background jobs in this chat.", "exit_code": 0}
|
||||
jobs.sort(key=lambda r: r.get("started_at") or 0, reverse=True)
|
||||
@@ -78,7 +90,11 @@ class ManageBgJobsTool:
|
||||
if action in _OUTPUT_ACTIONS or action in _KILL_ACTIONS:
|
||||
if not job_id:
|
||||
return {"error": f"manage_bg_jobs: action '{action}' requires a job_id (see action='list').", "exit_code": 1}
|
||||
rec = bg_jobs.get(job_id)
|
||||
try:
|
||||
resource = expected_job(job_id, action=action)
|
||||
rec = bg_jobs.get(job_id, expected=resource)
|
||||
except (ResourceIdentityError, OSError, ValueError) as error:
|
||||
return {"error": str(error), "exit_code": 1, "blocked": True, "failure_kind": "resource_identity_denied"}
|
||||
# Scope: only the chat that launched a job may see or control it.
|
||||
if rec is None or rec.get("session_id") != session_id:
|
||||
return {"error": f"manage_bg_jobs: no background job '{job_id}' in this chat.", "exit_code": 1}
|
||||
@@ -86,7 +102,7 @@ class ManageBgJobsTool:
|
||||
if action in _KILL_ACTIONS:
|
||||
if rec.get("status") != "running":
|
||||
return {"output": f"Job `{job_id}` already {_status_label(rec)}; nothing to kill.", "exit_code": 0}
|
||||
killed = bg_jobs.kill(job_id)
|
||||
killed = bg_jobs.kill(job_id, expected=resource)
|
||||
if not killed or not killed.get("killed"):
|
||||
return {"error": f"Could not verify termination of background job `{job_id}`.",
|
||||
"exit_code": 1, "teardown": (killed or {}).get("teardown")}
|
||||
|
||||
@@ -511,26 +511,47 @@ async def _run_owned_command(command, ctx: dict, *, tool: str, timeout: int, arg
|
||||
from src.tool_execution import agent_cwd, _truncate
|
||||
|
||||
grant = None
|
||||
result = None
|
||||
try:
|
||||
from src.agent_runtime.process_resources import require_launch, publish_launch, validate_launch_spec
|
||||
from src.agent_runtime.authority import active_request_authority
|
||||
launch = require_launch(tool, cwd=agent_cwd())
|
||||
authority = active_request_authority()
|
||||
if (str(ctx.get("owner") or "").strip().casefold(), str(ctx.get("session_id") or "")) != (
|
||||
authority.owner, authority.session_id):
|
||||
raise ValueError("Native producer owner or session changed")
|
||||
spec = _owned_spec(agent_cwd(), ctx.get("subproc_env"), timeout, readonly_extra)
|
||||
validate_launch_spec(launch, spec)
|
||||
grant = containment.acquire(
|
||||
_owned_spec(agent_cwd(), ctx.get("subproc_env"), timeout, readonly_extra),
|
||||
spec,
|
||||
owner=str(ctx.get("session_id") or ctx.get("owner") or tool),
|
||||
)
|
||||
containment._update_record(grant.id, launch_generation=launch.generation)
|
||||
publish_launch(launch, authority, grant.id)
|
||||
if containment.FILESYSTEM not in grant.enforced:
|
||||
if argv:
|
||||
command = [*command[:-1], _replace_workspace_alias(command[-1], grant.workspace)]
|
||||
else:
|
||||
command = _replace_workspace_alias(command, grant.workspace)
|
||||
result = await containment.run(grant, command, argv=argv, progress_cb=ctx.get("progress_cb"))
|
||||
from src.agent_runtime.process_resources import attach_containment_processes
|
||||
attach_containment_processes(launch, grant.id)
|
||||
except containment.ContainmentUnavailable as exc:
|
||||
return containment.unavailable_tool_result(exc, tool=tool)
|
||||
except (OSError, RuntimeError, ValueError) as exc:
|
||||
boundary = grant.to_dict() if grant else {}
|
||||
boundary["executed"] = bool(getattr(exc, "containment_executed", False))
|
||||
if not getattr(exc, "containment_established", False):
|
||||
if grant is not None:
|
||||
record = containment._load_records().get(grant.id, {})
|
||||
if not record.get("pid") and not record.get("release"):
|
||||
containment.release(grant, grace_s=0)
|
||||
boundary = result.grant.to_dict() if result is not None else grant.to_dict() if grant else {}
|
||||
boundary["executed"] = result is not None or bool(getattr(exc, "containment_executed", False))
|
||||
if result is None and not getattr(exc, "containment_established", False):
|
||||
boundary.update(contained=False, enforced=[])
|
||||
return {"error": f"{tool}: execution failed: {exc}", "exit_code": 1,
|
||||
"containment": boundary}
|
||||
"containment": boundary,
|
||||
**({"failure_kind": "resource_linkage_unavailable",
|
||||
"teardown": result.release.to_dict() if result.release else {"dead": False}}
|
||||
if result is not None else {})}
|
||||
|
||||
boundary = result.grant.to_dict()
|
||||
boundary["executed"] = True
|
||||
@@ -590,6 +611,12 @@ class BashTool:
|
||||
),
|
||||
"exit_code": 1,
|
||||
}
|
||||
from src.agent_runtime.process_resources import require_launch
|
||||
from src.agent_runtime.resources import ResourceIdentityError
|
||||
try:
|
||||
require_launch("bash", cwd=agent_cwd(), content=content)
|
||||
except ResourceIdentityError as error:
|
||||
return {"error": str(error), "exit_code": 1, "blocked": True, "failure_kind": "resource_identity_denied"}
|
||||
if _ffmpeg_unicode_drawtext_needs_fontfile(content):
|
||||
resolved_font = _resolve_fontfile_for_text(content)
|
||||
resolved_hint = (
|
||||
@@ -879,6 +906,12 @@ class PythonTool:
|
||||
),
|
||||
"exit_code": 1,
|
||||
}
|
||||
from src.agent_runtime.process_resources import require_launch
|
||||
from src.agent_runtime.resources import ResourceIdentityError
|
||||
try:
|
||||
require_launch("python", cwd=agent_cwd(), content=content)
|
||||
except ResourceIdentityError as error:
|
||||
return {"error": str(error), "exit_code": 1, "blocked": True, "failure_kind": "resource_identity_denied"}
|
||||
if "/tmp/" in content:
|
||||
isolated_tmp = _isolated_tmp_dir(agent_cwd())
|
||||
content = content.replace("/tmp/", isolated_tmp.rstrip("/") + "/")
|
||||
|
||||
Reference in New Issue
Block a user