نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی
مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""Sandbox gateway worker — housekeeping for the only sanctioned execution path.
|
||||
|
||||
Two jobs, both about not leaking resources:
|
||||
|
||||
1. **Reap idle sessions.** A sandbox session that nobody has touched for hours
|
||||
is still consuming CPU and disk on the provider. The reaper stops it and
|
||||
writes an audit event, because "the platform killed my sandbox" must be
|
||||
answerable from the audit log.
|
||||
|
||||
2. **Report the policy in force.** The gateway is the one place where untrusted
|
||||
code runs, so the worker logs the effective network policy and the absolute
|
||||
caps at startup. An operator should be able to see the safety envelope
|
||||
without reading the source.
|
||||
|
||||
The worker never executes a command. It only stops sessions — the command path
|
||||
is ``SandboxService.run_command``, reachable from the API under a tenant check.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from app.application.container import build_sandbox_service
|
||||
from app.core.config import settings
|
||||
from app.domain.audit.models import AuditAction, AuditEvent
|
||||
from app.domain.base import utcnow
|
||||
from app.infrastructure.repositories.audit import AuditRepository
|
||||
from app.infrastructure.repositories.sandbox import WorkspaceRepository
|
||||
from app.workers.base import WorkerOutcome, worker_session
|
||||
|
||||
#: Sessions are considered abandoned after this long with no activity.
|
||||
DEFAULT_IDLE_MINUTES = 120
|
||||
|
||||
|
||||
class SandboxGatewayWorker:
|
||||
"""Stops idle sandbox sessions and records why."""
|
||||
|
||||
name = "sandbox-gateway"
|
||||
|
||||
async def reap(
|
||||
self, *, idle_minutes: int = DEFAULT_IDLE_MINUTES, limit: int = 200
|
||||
) -> WorkerOutcome:
|
||||
outcome = WorkerOutcome(name=self.name)
|
||||
idle_before = utcnow() - timedelta(minutes=max(1, idle_minutes))
|
||||
|
||||
async with worker_session() as session:
|
||||
sandbox = build_sandbox_service(session)
|
||||
workspaces = WorkspaceRepository(session)
|
||||
audit = AuditRepository(session)
|
||||
|
||||
stopped = await sandbox.reap_idle_sessions(
|
||||
idle_before=idle_before, limit=limit
|
||||
)
|
||||
|
||||
for sandbox_session in stopped:
|
||||
# Resolve the tenant for the audit trail. A session whose
|
||||
# workspace has vanished is still stopped, just recorded
|
||||
# without an organization.
|
||||
workspace = await workspaces.get(sandbox_session.workspace_id)
|
||||
await audit.record(
|
||||
event=AuditEvent(
|
||||
action=AuditAction.SANDBOX_REAP,
|
||||
organization_id=workspace.organization_id if workspace else None,
|
||||
target_type="sandbox_session",
|
||||
target_id=sandbox_session.id,
|
||||
metadata_json={
|
||||
"workspace_id": sandbox_session.workspace_id,
|
||||
"idle_minutes": idle_minutes,
|
||||
"reason": "idle_timeout",
|
||||
},
|
||||
)
|
||||
)
|
||||
outcome.processed += 1
|
||||
outcome.note(f"stopped session {sandbox_session.id}")
|
||||
|
||||
if not stopped:
|
||||
outcome.skipped += 1
|
||||
|
||||
return outcome
|
||||
|
||||
def policy_report(self) -> WorkerOutcome:
|
||||
"""Describe the safety envelope this gateway is running under."""
|
||||
outcome = WorkerOutcome(name=self.name)
|
||||
outcome.note(f"sandbox provider = {settings.sandbox_provider}")
|
||||
outcome.note(
|
||||
f"command timeout = {settings.sandbox_command_timeout_seconds}s "
|
||||
f"(absolute cap enforced in the service layer)"
|
||||
)
|
||||
outcome.note(f"max output = {settings.sandbox_max_output_bytes} bytes")
|
||||
outcome.note("egress policy default = deny_all (set per resource limit)")
|
||||
return outcome
|
||||
|
||||
|
||||
__all__ = ["DEFAULT_IDLE_MINUTES", "SandboxGatewayWorker"]
|
||||
Reference in New Issue
Block a user