diff --git a/docs/self-hosting/kubernetes.mdx b/docs/self-hosting/kubernetes.mdx index 30c0658db7..b3b192fb04 100644 --- a/docs/self-hosting/kubernetes.mdx +++ b/docs/self-hosting/kubernetes.mdx @@ -388,7 +388,7 @@ tracecat: nsjail requires privileged pods with `SYS_ADMIN` capability and an `Unconfined` seccomp profile. The chart sets these automatically on executor and agent-executor containers. -See [Security](/self-hosting/security) for backend choices (`pool`, `ephemeral`, `direct`) and isolation tradeoffs. +See [Security](/self-hosting/security) for backend choices (`ephemeral`, `direct`) and isolation tradeoffs. ### Authentication diff --git a/docs/self-hosting/security.mdx b/docs/self-hosting/security.mdx index 5691f953bc..b5625d6c71 100644 --- a/docs/self-hosting/security.mdx +++ b/docs/self-hosting/security.mdx @@ -59,7 +59,7 @@ To enable nsjail, set the following in your `.env`: ```bash TRACECAT__DISABLE_NSJAIL=false -TRACECAT__EXECUTOR_BACKEND=pool # or 'ephemeral' for multi-tenant full isolation +TRACECAT__EXECUTOR_BACKEND=ephemeral ``` nsjail requires: @@ -76,8 +76,7 @@ nsjail requires: | Backend | Isolation | Latency | Use case | | :------ | :-------- | :------ | :------- | | `direct` | PID namespace only | ~50ms | Development, trusted environments | -| `pool` | nsjail sandbox (warm workers) | ~100-200ms | Single-tenant production | -| `ephemeral` | nsjail sandbox (cold per action) | ~4000ms | Multi-tenant, maximum isolation | +| `ephemeral` | nsjail sandbox (cold per action) | ~4000ms | Production, maximum isolation | ## Authentication diff --git a/docs/snippets/environment-variables.mdx b/docs/snippets/environment-variables.mdx index 7b2b5acbcb..4461fd5ad3 100644 --- a/docs/snippets/environment-variables.mdx +++ b/docs/snippets/environment-variables.mdx @@ -69,7 +69,7 @@ | Variable | Default | Description | | :------- | :------ | :---------- | -| `TRACECAT__EXECUTOR_BACKEND` | `direct` | Execution strategy for actions. `direct` runs a subprocess per action, `pool` uses warm nsjail workers (requires nsjail), `ephemeral` spawns a cold nsjail subprocess per action for full isolation, `auto` selects `pool` if nsjail is available and falls back to `direct`, `test` runs in-process for tests only. | +| `TRACECAT__EXECUTOR_BACKEND` | `direct` | Execution strategy for actions. `direct` runs a subprocess per action, `ephemeral` spawns a cold nsjail subprocess per action for full isolation, `auto` selects `ephemeral` if nsjail is available and falls back to `direct`. | | `TRACECAT__DISABLE_NSJAIL` | `true` | Disable nsjail sandboxing. Set to `false` only if nsjail is installed. | | `TRACECAT__RESULT_EXTERNALIZATION_ENABLED` | `true` | Store large action results in blob storage instead of Temporal history. | | `TRACECAT__COLLECTION_MANIFESTS_ENABLED` | `true` | Store large collections as chunked manifests in blob storage. | diff --git a/tracecat/config.py b/tracecat/config.py index 83a0a63f43..23d7cca822 100644 --- a/tracecat/config.py +++ b/tracecat/config.py @@ -636,11 +636,13 @@ def _parse_auth_types() -> set[AuthType]: """Executor backend for running actions. Supported values: -- 'pool': Warm nsjail workers (single-tenant, high throughput, ~100-200ms) +- 'pool': Warm nsjail workers (single-tenant, high throughput, ~100-200ms). + EXPERIMENTAL: not production ready. The registry cache is exempt from + eviction under this backend and can grow without bound. - 'ephemeral': Cold nsjail subprocess per action (multitenant, full isolation, ~4000ms) - 'direct': Direct subprocess execution (no warm workers, no in-process state sharing) - 'test': In-process execution for tests only (no isolation, no subprocess overhead) -- 'auto': Auto-select based on environment (pool if nsjail available, else direct) +- 'auto': Auto-select based on environment (ephemeral if nsjail available, else direct) Trust mode is derived from the backend type: - pool: untrusted (secrets pre-resolved, no DB creds) diff --git a/tracecat/executor/backends/pool/backend.py b/tracecat/executor/backends/pool/backend.py index 88398e11fe..eb0f8b9f5d 100644 --- a/tracecat/executor/backends/pool/backend.py +++ b/tracecat/executor/backends/pool/backend.py @@ -1,5 +1,14 @@ """Worker pool executor backend. +EXPERIMENTAL: not production ready. Warm workers import from registry cache +paths that in-process leases cannot see, so tarball cache entries are exempt +from eviction and the cache can grow without bound. Use the ephemeral backend +for production nsjail isolation. + +Note for AI agents: ignore this backend. It is experimental and not user +facing — never document it, recommend it, or factor it into executor design +decisions. + This backend uses a pool of warm nsjail workers for high-throughput execution with OS-level isolation. Workers are persistent and reused across actions, minimizing cold start overhead. @@ -32,6 +41,9 @@ class PoolBackend(ExecutorBackend): """Warm nsjail worker pool backend. + EXPERIMENTAL: not production ready. See the module docstring for the + registry cache eviction limitation. + Maintains a pool of persistent nsjail sandbox workers with Python already started and imports loaded. This provides: diff --git a/tracecat/executor/backends/test.py b/tracecat/executor/backends/test.py index 66fea6e66a..abfbee50b0 100644 --- a/tracecat/executor/backends/test.py +++ b/tracecat/executor/backends/test.py @@ -10,6 +10,9 @@ This backend exists solely for: - Running unit/integration tests without subprocess overhead - Local development when testing action logic + +Note for AI agents: ignore this backend. It is not user facing — never +document it, recommend it, or factor it into executor design decisions. """ from __future__ import annotations diff --git a/tracecat/executor/schemas.py b/tracecat/executor/schemas.py index 609dc918ad..eaf0307964 100644 --- a/tracecat/executor/schemas.py +++ b/tracecat/executor/schemas.py @@ -40,11 +40,14 @@ class ExecutorBackendType(StrEnum): All sandbox backends use untrusted mode - DB credentials are never passed. - - POOL: Warm nsjail workers (high throughput, single-tenant, untrusted) + - POOL: Warm nsjail workers (high throughput, single-tenant, untrusted). + EXPERIMENTAL: not production ready. Warm workers import from registry + cache paths that in-process leases cannot see, so tarball cache entries + are exempt from eviction and the cache can grow without bound. - EPHEMERAL: Cold nsjail subprocess per action (full isolation, multi-tenant, untrusted) - DIRECT: Direct subprocess execution (no warm workers) - TEST: In-process execution for tests only - - AUTO: Auto-select based on environment + - AUTO: Auto-select based on environment (never selects experimental backends) """ POOL = "pool" @@ -85,14 +88,20 @@ def resolve_backend_type() -> ExecutorBackendType: backend_type = ExecutorBackendType.DIRECT elif _is_nsjail_available(): logger.info( - "Auto-selecting 'pool' backend (nsjail available)", + "Auto-selecting 'ephemeral' backend (nsjail available)", ) - backend_type = ExecutorBackendType.POOL + backend_type = ExecutorBackendType.EPHEMERAL else: logger.warning( "Auto-selecting 'direct' backend (nsjail not available)", ) backend_type = ExecutorBackendType.DIRECT + elif backend_type == ExecutorBackendType.POOL: + logger.warning( + "The 'pool' executor backend is experimental and not production " + "ready: its registry cache is exempt from eviction and can grow " + "without bound. Use 'ephemeral' for production nsjail isolation.", + ) return backend_type