Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ TRACECAT__RESULT_EXTERNALIZATION_THRESHOLD_BYTES=128000
# --- Agent filesystem persistence ---
# Maximum compressed bytes retained in each worker's local agent snapshot archive cache.
TRACECAT__AGENT_FS_ARCHIVE_CACHE_MAX_BYTES=10737418240
# Per-sandbox cgroup memory limit and executor memory reserved outside activity slots.
TRACECAT__AGENT_SANDBOX_MEMORY_MB=4096
TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED=true
TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB=4096
# Readiness sentinel path shared by the worker and the compose healthcheck.
TRACECAT__AGENT_EXECUTOR_READY_FILE=/var/run/tracecat/agent-executor-ready

# --- Local registry ---
# Enable this only for local-registry development. Leave disabled for normal remote/builtin registry use.
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ ENV PYTHONPATH="/home/apiuser/.local"

RUN mkdir -p /home/apiuser/.local/bin && ln -s $(which uv) /home/apiuser/.local/bin/uv

COPY docker/scripts/agent-executor-entrypoint.sh /usr/local/bin/agent-executor-entrypoint.sh
RUN chmod +x /usr/local/bin/agent-executor-entrypoint.sh

# Switch to non-root user (matches production, required for pasta userspace networking)
USER apiuser

Expand Down Expand Up @@ -278,6 +281,9 @@ ENV TMPDIR="/home/apiuser/.cache/tmp" TEMP="/home/apiuser/.cache/tmp" TMP="/home

RUN mkdir -p /app/.scripts && chown -R apiuser:apiuser /app

COPY docker/scripts/agent-executor-entrypoint.sh /usr/local/bin/agent-executor-entrypoint.sh
RUN chmod +x /usr/local/bin/agent-executor-entrypoint.sh

# Switch to non-root user
USER apiuser

Expand Down
9 changes: 9 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ services:
TRACECAT__AGENT_EXECUTOR_QUEUE: ${TRACECAT__AGENT_EXECUTOR_QUEUE:-shared-agent-executor-queue}
TRACECAT__EXECUTOR_QUEUE: ${TRACECAT__EXECUTOR_QUEUE:-shared-action-queue}
TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES: ${TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES:-1}
TRACECAT__AGENT_SANDBOX_MEMORY_MB: ${TRACECAT__AGENT_SANDBOX_MEMORY_MB:-4096}
TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED: ${TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED:-true}
TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB: ${TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB:-4096}
TRACECAT__AGENT_EXECUTOR_READY_FILE: ${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}
TRACECAT__LLM_PROXY_READ_TIMEOUT: ${TRACECAT__LLM_PROXY_READ_TIMEOUT:-600}
TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS: ${TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS:-60}
TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS: ${TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS:-30}
Expand All @@ -430,6 +434,11 @@ services:
- ${TRACECAT__LOCAL_REPOSITORY_PATH}:/app/local_registry
- sandbox-cache:/var/lib/tracecat/sandbox-cache
command: ["python", "-m", "tracecat.agent.executor_worker"]
healthcheck:
test: ["CMD", "test", "-f", "${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}"]
interval: 30s
retries: 3
start_period: 120s
depends_on:
litellm:
condition: service_healthy
Expand Down
9 changes: 9 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ services:
TRACECAT__AGENT_EXECUTOR_QUEUE: ${TRACECAT__AGENT_EXECUTOR_QUEUE:-shared-agent-executor-queue}
TRACECAT__EXECUTOR_QUEUE: ${TRACECAT__EXECUTOR_QUEUE:-shared-action-queue}
TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES: ${TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES:-1}
TRACECAT__AGENT_SANDBOX_MEMORY_MB: ${TRACECAT__AGENT_SANDBOX_MEMORY_MB:-4096}
TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED: ${TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED:-true}
TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB: ${TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB:-4096}
TRACECAT__AGENT_EXECUTOR_READY_FILE: ${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}
TRACECAT__LLM_PROXY_READ_TIMEOUT: ${TRACECAT__LLM_PROXY_READ_TIMEOUT:-600}
TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS: ${TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS:-60}
TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS: ${TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS:-30}
Expand All @@ -450,6 +454,11 @@ services:
- ${TRACECAT__LOCAL_REPOSITORY_PATH}:/app/local_registry
- sandbox-cache:/var/lib/tracecat/sandbox-cache
command: ["python", "-m", "tracecat.agent.executor_worker"]
healthcheck:
test: ["CMD", "test", "-f", "${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}"]
interval: 30s
retries: 3
start_period: 120s
depends_on:
litellm:
condition: service_healthy
Expand Down
15 changes: 15 additions & 0 deletions docker-compose.sandbox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,23 @@ services:
# Required for nsjail sandbox execution.
cap_add:
- SYS_ADMIN
# Start as root so the entrypoint can delegate the container's cgroup v2
# subtree to apiuser for per-sandbox memory limits; it drops privileges
# before the worker starts. Override neither independently.
user: "0:0"
entrypoint: ["/usr/local/bin/agent-executor-entrypoint.sh"]
environment:
TRACECAT__AGENT_SANDBOX_MEMORY_MB: ${TRACECAT__AGENT_SANDBOX_MEMORY_MB:-4096}
TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED: ${TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED:-true}
TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB: ${TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB:-4096}
TRACECAT__AGENT_EXECUTOR_READY_FILE: ${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}
security_opt:
- seccomp:unconfined
- systempaths=unconfined
devices:
- /dev/net/tun:/dev/net/tun
healthcheck:
test: ["CMD", "test", "-f", "${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}"]
Comment thread
daryllimyt marked this conversation as resolved.
interval: 30s
retries: 3
start_period: 120s
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ services:
TRACECAT__AGENT_EXECUTOR_QUEUE: ${TRACECAT__AGENT_EXECUTOR_QUEUE:-shared-agent-executor-queue}
TRACECAT__EXECUTOR_QUEUE: ${TRACECAT__EXECUTOR_QUEUE:-shared-action-queue}
TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES: ${TRACECAT__AGENT_EXECUTOR_MAX_CONCURRENT_ACTIVITIES:-1}
TRACECAT__AGENT_SANDBOX_MEMORY_MB: ${TRACECAT__AGENT_SANDBOX_MEMORY_MB:-4096}
TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED: ${TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED:-true}
Comment thread
daryllimyt marked this conversation as resolved.
TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB: ${TRACECAT__AGENT_EXECUTOR_MEMORY_RESERVE_MB:-4096}
TRACECAT__AGENT_EXECUTOR_READY_FILE: ${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}
TRACECAT__LLM_PROXY_READ_TIMEOUT: ${TRACECAT__LLM_PROXY_READ_TIMEOUT:-600}
TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS: ${TRACECAT__LLM_GATEWAY_CREDENTIAL_CACHE_TTL_SECONDS:-60}
TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS: ${TRACECAT__LLM_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS:-30}
Expand All @@ -445,6 +449,11 @@ services:
- ${TRACECAT__LOCAL_REPOSITORY_PATH}:/app/local_registry
- sandbox-cache:/var/lib/tracecat/sandbox-cache
command: ["python", "-m", "tracecat.agent.executor_worker"]
healthcheck:
test: ["CMD", "test", "-f", "${TRACECAT__AGENT_EXECUTOR_READY_FILE:-/var/run/tracecat/agent-executor-ready}"]
interval: 30s
retries: 3
start_period: 120s
depends_on:
litellm:
condition: service_healthy
Expand Down
49 changes: 49 additions & 0 deletions docker/scripts/agent-executor-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail

# Agent-executor entrypoint for deployments that enable per-sandbox cgroup
# memory limits. Start the container as root with this entrypoint (compose:
# user "0:0"; Kubernetes: runAsUser 0) and it hands the container's own
# cgroup v2 directory to apiuser so the worker can prepare nsjail child
# cgroups without root, then drops privileges before starting it. Where the
# needed privileges are absent the worker starts unchanged and falls back to
# rlimit-only sandbox limits. Non-root invocations pass straight through.
if [[ "$(id -u)" == "0" ]]; then
Comment thread
daryllimyt marked this conversation as resolved.
# Mirror config.env_bool falsy values so disabling the feature also skips
# the root-side delegation, not just the Python-side preparation. The
# privilege drop below is unconditional: root never reaches the worker.
cgroup_enabled="$(printf '%s' "${TRACECAT__AGENT_SANDBOX_CGROUP_ENABLED:-true}" | tr '[:upper:]' '[:lower:]')"
case "$cgroup_enabled" in 0 | false | no | off) cgroup_enabled=false ;; *) cgroup_enabled=true ;; esac

if [[ "$cgroup_enabled" == "true" ]]; then
Comment thread
daryllimyt marked this conversation as resolved.
Outdated
# Resolve this container's cgroup v2 directory: the mount root under a
# private cgroup namespace, a subpath of the host cgroupfs otherwise
# (e.g. privileged Kubernetes). Never touch anything above it, and
# never touch anything at all without a unified v2 entry — on a
# cgroup v1 host an empty match would otherwise point at the
# cgroupfs root.
cgroup_path="$(sed -n 's/^0:://p' /proc/self/cgroup | head -n 1)"
if [[ -z "$cgroup_path" ]]; then
echo "No cgroup v2 entry in /proc/self/cgroup; agent sandbox" \
"cgroup limits will be unavailable." >&2
else
cgroup_rel="${cgroup_path#/}"
cgroup_dir="/sys/fs/cgroup${cgroup_rel:+/$cgroup_rel}"
mount -o remount,rw /sys/fs/cgroup 2>/dev/null || true
if [[ -f "$cgroup_dir/cgroup.controllers" ]] &&
chown apiuser:apiuser "$cgroup_dir" "$cgroup_dir/cgroup.procs" \
"$cgroup_dir/cgroup.subtree_control" "$cgroup_dir/cgroup.threads"; then
echo "Delegated $cgroup_dir to apiuser."
else
echo "Unable to delegate $cgroup_dir to apiuser; agent sandbox" \
"cgroup limits will be unavailable." >&2
fi
fi
fi
# setpriv changes only IDs; fix the identity env vars ourselves instead of
# --reset-env, which would clear the service configuration environment.
export HOME=/home/apiuser USER=apiuser LOGNAME=apiuser
exec setpriv --reuid=apiuser --regid=apiuser --init-groups "$@"
fi

exec "$@"
Loading
Loading