feat(sandbox): per-agent docker overrides
This commit is contained in:
@@ -581,6 +581,50 @@ export type QueueModeByProvider = {
|
||||
webchat?: QueueMode;
|
||||
};
|
||||
|
||||
export type SandboxDockerSettings = {
|
||||
/** Docker image to use for sandbox containers. */
|
||||
image?: string;
|
||||
/** Prefix for sandbox container names. */
|
||||
containerPrefix?: string;
|
||||
/** Container workdir mount path (default: /workspace). */
|
||||
workdir?: string;
|
||||
/** Run container rootfs read-only. */
|
||||
readOnlyRoot?: boolean;
|
||||
/** Extra tmpfs mounts for read-only containers. */
|
||||
tmpfs?: string[];
|
||||
/** Container network mode (bridge|none|custom). */
|
||||
network?: string;
|
||||
/** Container user (uid:gid). */
|
||||
user?: string;
|
||||
/** Drop Linux capabilities. */
|
||||
capDrop?: string[];
|
||||
/** Extra environment variables for sandbox exec. */
|
||||
env?: Record<string, string>;
|
||||
/** Optional setup command run once after container creation. */
|
||||
setupCommand?: string;
|
||||
/** Limit container PIDs (0 = Docker default). */
|
||||
pidsLimit?: number;
|
||||
/** Limit container memory (e.g. 512m, 2g, or bytes as number). */
|
||||
memory?: string | number;
|
||||
/** Limit container memory swap (same format as memory). */
|
||||
memorySwap?: string | number;
|
||||
/** Limit container CPU shares (e.g. 0.5, 1, 2). */
|
||||
cpus?: number;
|
||||
/**
|
||||
* Set ulimit values by name (e.g. nofile, nproc).
|
||||
* Use "soft:hard" string, a number, or { soft, hard }.
|
||||
*/
|
||||
ulimits?: Record<string, string | number | { soft?: number; hard?: number }>;
|
||||
/** Seccomp profile (path or profile name). */
|
||||
seccompProfile?: string;
|
||||
/** AppArmor profile name. */
|
||||
apparmorProfile?: string;
|
||||
/** DNS servers (e.g. ["1.1.1.1", "8.8.8.8"]). */
|
||||
dns?: string[];
|
||||
/** Extra host mappings (e.g. ["api.local:10.0.0.2"]). */
|
||||
extraHosts?: string[];
|
||||
};
|
||||
|
||||
export type GroupChatConfig = {
|
||||
mentionPatterns?: string[];
|
||||
historyLimit?: number;
|
||||
@@ -618,10 +662,7 @@ export type RoutingConfig = {
|
||||
perSession?: boolean;
|
||||
workspaceRoot?: string;
|
||||
/** Docker-specific sandbox overrides for this agent. */
|
||||
docker?: {
|
||||
/** Optional setup command run once after container creation. */
|
||||
setupCommand?: string;
|
||||
};
|
||||
docker?: SandboxDockerSettings;
|
||||
/** Tool allow/deny policy for sandboxed sessions (deny wins). */
|
||||
tools?: {
|
||||
allow?: string[];
|
||||
@@ -1050,52 +1091,7 @@ export type ClawdbotConfig = {
|
||||
/** Root directory for sandbox workspaces. */
|
||||
workspaceRoot?: string;
|
||||
/** Docker-specific sandbox settings. */
|
||||
docker?: {
|
||||
/** Docker image to use for sandbox containers. */
|
||||
image?: string;
|
||||
/** Prefix for sandbox container names. */
|
||||
containerPrefix?: string;
|
||||
/** Container workdir mount path (default: /workspace). */
|
||||
workdir?: string;
|
||||
/** Run container rootfs read-only. */
|
||||
readOnlyRoot?: boolean;
|
||||
/** Extra tmpfs mounts for read-only containers. */
|
||||
tmpfs?: string[];
|
||||
/** Container network mode (bridge|none|custom). */
|
||||
network?: string;
|
||||
/** Container user (uid:gid). */
|
||||
user?: string;
|
||||
/** Drop Linux capabilities. */
|
||||
capDrop?: string[];
|
||||
/** Extra environment variables for sandbox exec. */
|
||||
env?: Record<string, string>;
|
||||
/** Optional setup command run once after container creation. */
|
||||
setupCommand?: string;
|
||||
/** Limit container PIDs (0 = Docker default). */
|
||||
pidsLimit?: number;
|
||||
/** Limit container memory (e.g. 512m, 2g, or bytes as number). */
|
||||
memory?: string | number;
|
||||
/** Limit container memory swap (same format as memory). */
|
||||
memorySwap?: string | number;
|
||||
/** Limit container CPU shares (e.g. 0.5, 1, 2). */
|
||||
cpus?: number;
|
||||
/**
|
||||
* Set ulimit values by name (e.g. nofile, nproc).
|
||||
* Use "soft:hard" string, a number, or { soft, hard }.
|
||||
*/
|
||||
ulimits?: Record<
|
||||
string,
|
||||
string | number | { soft?: number; hard?: number }
|
||||
>;
|
||||
/** Seccomp profile (path or profile name). */
|
||||
seccompProfile?: string;
|
||||
/** AppArmor profile name. */
|
||||
apparmorProfile?: string;
|
||||
/** DNS servers (e.g. ["1.1.1.1", "8.8.8.8"]). */
|
||||
dns?: string[];
|
||||
/** Extra host mappings (e.g. ["api.local:10.0.0.2"]). */
|
||||
extraHosts?: string[];
|
||||
};
|
||||
docker?: SandboxDockerSettings;
|
||||
/** Optional sandboxed browser settings. */
|
||||
browser?: {
|
||||
enabled?: boolean;
|
||||
|
||||
@@ -224,6 +224,42 @@ const HeartbeatSchema = z
|
||||
})
|
||||
.optional();
|
||||
|
||||
const SandboxDockerSchema = z
|
||||
.object({
|
||||
image: z.string().optional(),
|
||||
containerPrefix: z.string().optional(),
|
||||
workdir: z.string().optional(),
|
||||
readOnlyRoot: z.boolean().optional(),
|
||||
tmpfs: z.array(z.string()).optional(),
|
||||
network: z.string().optional(),
|
||||
user: z.string().optional(),
|
||||
capDrop: z.array(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
setupCommand: z.string().optional(),
|
||||
pidsLimit: z.number().int().positive().optional(),
|
||||
memory: z.union([z.string(), z.number()]).optional(),
|
||||
memorySwap: z.union([z.string(), z.number()]).optional(),
|
||||
cpus: z.number().positive().optional(),
|
||||
ulimits: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.union([
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.object({
|
||||
soft: z.number().int().nonnegative().optional(),
|
||||
hard: z.number().int().nonnegative().optional(),
|
||||
}),
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
seccompProfile: z.string().optional(),
|
||||
apparmorProfile: z.string().optional(),
|
||||
dns: z.array(z.string()).optional(),
|
||||
extraHosts: z.array(z.string()).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
const RoutingSchema = z
|
||||
.object({
|
||||
groupChat: GroupChatSchema,
|
||||
@@ -265,11 +301,7 @@ const RoutingSchema = z
|
||||
.optional(),
|
||||
perSession: z.boolean().optional(),
|
||||
workspaceRoot: z.string().optional(),
|
||||
docker: z
|
||||
.object({
|
||||
setupCommand: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
docker: SandboxDockerSchema,
|
||||
tools: z
|
||||
.object({
|
||||
allow: z.array(z.string()).optional(),
|
||||
@@ -673,41 +705,7 @@ export const ClawdbotSchema = z.object({
|
||||
.optional(),
|
||||
perSession: z.boolean().optional(),
|
||||
workspaceRoot: z.string().optional(),
|
||||
docker: z
|
||||
.object({
|
||||
image: z.string().optional(),
|
||||
containerPrefix: z.string().optional(),
|
||||
workdir: z.string().optional(),
|
||||
readOnlyRoot: z.boolean().optional(),
|
||||
tmpfs: z.array(z.string()).optional(),
|
||||
network: z.string().optional(),
|
||||
user: z.string().optional(),
|
||||
capDrop: z.array(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
setupCommand: z.string().optional(),
|
||||
pidsLimit: z.number().int().positive().optional(),
|
||||
memory: z.union([z.string(), z.number()]).optional(),
|
||||
memorySwap: z.union([z.string(), z.number()]).optional(),
|
||||
cpus: z.number().positive().optional(),
|
||||
ulimits: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.union([
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.object({
|
||||
soft: z.number().int().nonnegative().optional(),
|
||||
hard: z.number().int().nonnegative().optional(),
|
||||
}),
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
seccompProfile: z.string().optional(),
|
||||
apparmorProfile: z.string().optional(),
|
||||
dns: z.array(z.string()).optional(),
|
||||
extraHosts: z.array(z.string()).optional(),
|
||||
})
|
||||
.optional(),
|
||||
docker: SandboxDockerSchema,
|
||||
browser: z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
|
||||
Reference in New Issue
Block a user