refactor: clarify sandbox cron elevated gating terminology
This commit is contained in:
parent
fed475f9ac
commit
548b44b40d
@ -134,6 +134,7 @@ Delivery notes:
|
||||
- If `to` is set, cron auto-delivers the agent’s final output even if `deliver` is omitted.
|
||||
- Use `deliver: true` when you want last-route delivery without an explicit `to`.
|
||||
- Use `deliver: false` to keep output internal even if a `to` is present.
|
||||
- Sandboxed sessions may restrict delivery targets via `agents.defaults.sandbox.cron.delivery` (see [Sandboxing](/gateway/sandboxing) and [Configuration](/gateway/configuration#agentsdefaultssandbox)).
|
||||
|
||||
Target format reminders:
|
||||
- Slack/Discord/Mattermost (plugin) targets should use explicit prefixes (e.g. `channel:<id>`, `user:<id>`) to avoid ambiguity.
|
||||
|
||||
@ -2175,6 +2175,15 @@ Defaults (if enabled):
|
||||
- optional sandboxed browser (Chromium + CDP, noVNC observer)
|
||||
- hardening knobs: `network`, `user`, `pidsLimit`, `memory`, `cpus`, `ulimits`, `seccompProfile`, `apparmorProfile`
|
||||
|
||||
Cron policy (only applies when a session is sandboxed and the `cron` tool is allowed):
|
||||
- `cron.visibility`: `"agent"` (default) scopes cron jobs to the current agent; `"all"` allows cross-agent cron visibility.
|
||||
- `cron.elevated`: `"off"` (default) never bypasses sandbox cron restrictions; `"on"` bypasses when session elevated is on/ask/full; `"full"` bypasses only when elevated is full.
|
||||
- `cron.allowMainSessionJobs`: `false` (default) blocks main-session cron jobs and wake events from sandboxed sessions.
|
||||
- `cron.delivery`: `"last-only"` (default) allows last-route delivery only (no explicit `to`; if `channel` is set it must be `last`); `"off"` disables delivery; `"explicit"` allows explicit delivery targets.
|
||||
|
||||
Notes:
|
||||
- This does not enable the `cron` tool inside the sandbox. Cron is denied by default in sandbox tool policy; allow it via `tools.sandbox.tools` (or per-agent `agents.list[].tools.sandbox.tools`).
|
||||
|
||||
Warning: `scope: "shared"` means a shared container and shared workspace. No
|
||||
cross-session isolation. Use `scope: "session"` for per-session isolation.
|
||||
|
||||
@ -2193,6 +2202,12 @@ For package installs, ensure network egress, a writable root FS, and a root user
|
||||
scope: "agent", // session | agent | shared (agent is default)
|
||||
workspaceAccess: "none", // none | ro | rw
|
||||
workspaceRoot: "~/.clawdbot/sandboxes",
|
||||
cron: {
|
||||
visibility: "agent", // agent | all
|
||||
elevated: "off", // off | on | full
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only" // off | last-only | explicit
|
||||
},
|
||||
docker: {
|
||||
image: "moltbot-sandbox:bookworm-slim",
|
||||
containerPrefix: "moltbot-sbx-",
|
||||
|
||||
@ -90,6 +90,20 @@ Available groups:
|
||||
- `group:nodes`: `nodes`
|
||||
- `group:moltbot`: all built-in Moltbot tools (excludes provider plugins)
|
||||
|
||||
### Cron policy inside the sandbox
|
||||
|
||||
If the `cron` tool is allowed, sandboxed sessions can still be restricted by
|
||||
`agents.defaults.sandbox.cron` (and `agents.list[].sandbox.cron`):
|
||||
- Visibility: `agents.defaults.sandbox.cron.visibility` can scope cron jobs to the current agent.
|
||||
- Main session gating: `agents.defaults.sandbox.cron.allowMainSessionJobs: false` blocks main-session cron jobs and wake events from sandboxed sessions.
|
||||
- Delivery gating: `agents.defaults.sandbox.cron.delivery` can disable delivery or restrict it to last-route delivery.
|
||||
- Elevated gate: `agents.defaults.sandbox.cron.elevated` can use the session elevated level as an escape signal for cron restrictions.
|
||||
|
||||
Notes:
|
||||
- Elevated remains exec-only (it does not grant extra tools), but cron policy can consult the session elevated level.
|
||||
- Fix-it keys live under `agents.defaults.sandbox.cron.*` / `agents.list[].sandbox.cron.*` (see [Configuration](/gateway/configuration#agentsdefaultssandbox)).
|
||||
- This is in addition to tool policy; if `cron` is denied by sandbox tool policy, allow it via `tools.sandbox.tools` (or per-agent `agents.list[].tools.sandbox.tools`).
|
||||
|
||||
## Elevated: exec-only “run on host”
|
||||
|
||||
Elevated does **not** grant extra tools; it only affects `exec`.
|
||||
|
||||
@ -145,6 +145,24 @@ globally or per-agent, sandboxing doesn’t bring it back.
|
||||
`/exec` directives only apply for authorized senders and persist per session; to hard-disable
|
||||
`exec`, use tool policy deny (see [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated)).
|
||||
|
||||
## Cron policy (sandboxed sessions)
|
||||
|
||||
If the `cron` tool is allowed in a sandboxed session, Clawdbot can still apply
|
||||
additional restrictions to cron access and delivery via:
|
||||
- `agents.defaults.sandbox.cron`
|
||||
- `agents.list[].sandbox.cron` (per-agent override)
|
||||
|
||||
This is useful when you want sandboxed agents to schedule reminders but prevent:
|
||||
- cross-agent cron visibility (`visibility: "agent"`)
|
||||
- main-session jobs and wake events (`allowMainSessionJobs: false`)
|
||||
- explicit delivery targets (`delivery: "last-only"` or `"off"`)
|
||||
|
||||
Note: this does not enable cron in the sandbox. If `cron` is denied by sandbox tool policy,
|
||||
allow it via `tools.sandbox.tools` (or per-agent `agents.list[].tools.sandbox.tools`).
|
||||
|
||||
See [Configuration](/gateway/configuration#agentsdefaultssandbox) for the exact keys and defaults.
|
||||
If you see “blocked” errors, also check [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated).
|
||||
|
||||
Debugging:
|
||||
- Use `moltbot sandbox explain` to inspect effective sandbox mode, tool policy, and fix-it config keys.
|
||||
- See [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) for the “why is this blocked?” mental model.
|
||||
|
||||
@ -178,6 +178,43 @@ For debugging “why is this blocked?”, see [Sandbox vs Tool Policy vs Elevate
|
||||
|
||||
---
|
||||
|
||||
### Example 4: Sandbox Cron Policy Per Agent
|
||||
|
||||
This is useful when you want sandboxed agents to schedule cron jobs, but keep them
|
||||
scoped (and limit delivery):
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"sandbox": {
|
||||
"mode": "all",
|
||||
"cron": {
|
||||
"visibility": "agent",
|
||||
"elevated": "off",
|
||||
"allowMainSessionJobs": false,
|
||||
"delivery": "last-only"
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "admin",
|
||||
"sandbox": {
|
||||
"cron": {
|
||||
"visibility": "all",
|
||||
"elevated": "full",
|
||||
"delivery": "explicit"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Precedence
|
||||
|
||||
When both global (`agents.defaults.*`) and agent-specific (`agents.list[].*`) configs exist:
|
||||
@ -189,12 +226,14 @@ agents.list[].sandbox.mode > agents.defaults.sandbox.mode
|
||||
agents.list[].sandbox.scope > agents.defaults.sandbox.scope
|
||||
agents.list[].sandbox.workspaceRoot > agents.defaults.sandbox.workspaceRoot
|
||||
agents.list[].sandbox.workspaceAccess > agents.defaults.sandbox.workspaceAccess
|
||||
agents.list[].sandbox.cron.* > agents.defaults.sandbox.cron.*
|
||||
agents.list[].sandbox.docker.* > agents.defaults.sandbox.docker.*
|
||||
agents.list[].sandbox.browser.* > agents.defaults.sandbox.browser.*
|
||||
agents.list[].sandbox.prune.* > agents.defaults.sandbox.prune.*
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- `agents.list[].sandbox.cron.*` overrides `agents.defaults.sandbox.cron.*` for that agent.
|
||||
- `agents.list[].sandbox.{docker,browser,prune}.*` overrides `agents.defaults.sandbox.{docker,browser,prune}.*` for that agent (ignored when sandbox scope resolves to `"shared"`).
|
||||
|
||||
### Tool Restrictions
|
||||
|
||||
@ -361,6 +361,7 @@ Core actions:
|
||||
Notes:
|
||||
- `add` expects a full cron job object (same schema as `cron.add` RPC).
|
||||
- `update` uses `{ id, patch }`.
|
||||
- In sandboxed sessions, cron access and delivery may be further restricted by `agents.defaults.sandbox.cron` (and per-agent overrides via `agents.list[].sandbox.cron`).
|
||||
|
||||
### `gateway`
|
||||
Restart or apply updates to the running Gateway process (in-place).
|
||||
|
||||
@ -131,19 +131,19 @@ describe("sandbox config merges", () => {
|
||||
const resolved = resolveSandboxCronConfig({
|
||||
globalCron: {
|
||||
visibility: "all",
|
||||
escape: "elevated",
|
||||
elevated: "on",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
},
|
||||
agentCron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
},
|
||||
});
|
||||
|
||||
expect(resolved).toEqual({
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
});
|
||||
|
||||
@ -132,7 +132,7 @@ export function resolveSandboxCronConfig(params: {
|
||||
return {
|
||||
visibility:
|
||||
agentCron?.visibility ?? globalCron?.visibility ?? DEFAULT_SANDBOX_CRON_POLICY.visibility,
|
||||
escape: agentCron?.escape ?? globalCron?.escape ?? DEFAULT_SANDBOX_CRON_POLICY.escape,
|
||||
elevated: agentCron?.elevated ?? globalCron?.elevated ?? DEFAULT_SANDBOX_CRON_POLICY.elevated,
|
||||
allowMainSessionJobs:
|
||||
agentCron?.allowMainSessionJobs ??
|
||||
globalCron?.allowMainSessionJobs ??
|
||||
|
||||
@ -39,7 +39,7 @@ export const DEFAULT_TOOL_DENY = [
|
||||
|
||||
export const DEFAULT_SANDBOX_CRON_POLICY = {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
} as const;
|
||||
|
||||
@ -50,7 +50,7 @@ export type SandboxScope = "session" | "agent" | "shared";
|
||||
|
||||
export type SandboxCronPolicy = {
|
||||
visibility: "agent" | "all";
|
||||
escape: "off" | "elevated" | "elevated-full";
|
||||
elevated: "off" | "on" | "full";
|
||||
allowMainSessionJobs: boolean;
|
||||
delivery: "off" | "last-only" | "explicit";
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@ const resolveSandboxRuntimeStatusMock = vi.fn(() => ({ sandboxed: false, agentId
|
||||
const resolveSandboxConfigForAgentMock = vi.fn(() => ({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -43,7 +43,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -285,7 +285,7 @@ describe("cron tool", () => {
|
||||
expect(call.params).toEqual({ includeDisabled: false, actorAgentId: "agent-123" });
|
||||
});
|
||||
|
||||
it("skips actor scoping when sandbox escape is elevated", async () => {
|
||||
it("skips actor scoping when sandbox cron elevated gate is on", async () => {
|
||||
resolveSandboxRuntimeStatusMock.mockReturnValue({
|
||||
sandboxed: true,
|
||||
agentId: "agent-123",
|
||||
@ -293,7 +293,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "elevated",
|
||||
elevated: "on",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -311,7 +311,7 @@ describe("cron tool", () => {
|
||||
expect(call.params).toEqual({ includeDisabled: false });
|
||||
});
|
||||
|
||||
it("keeps actor scoping when escape is elevated-full but elevated is on", async () => {
|
||||
it("keeps actor scoping when sandbox cron elevated gate is full but elevated is on", async () => {
|
||||
resolveSandboxRuntimeStatusMock.mockReturnValue({
|
||||
sandboxed: true,
|
||||
agentId: "agent-123",
|
||||
@ -319,7 +319,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "elevated-full",
|
||||
elevated: "full",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -337,7 +337,7 @@ describe("cron tool", () => {
|
||||
expect(call.params).toEqual({ includeDisabled: false, actorAgentId: "agent-123" });
|
||||
});
|
||||
|
||||
it("skips actor scoping when escape is elevated-full and elevated is full", async () => {
|
||||
it("skips actor scoping when sandbox cron elevated gate is full and elevated is full", async () => {
|
||||
resolveSandboxRuntimeStatusMock.mockReturnValue({
|
||||
sandboxed: true,
|
||||
agentId: "agent-123",
|
||||
@ -345,7 +345,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "elevated-full",
|
||||
elevated: "full",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -392,7 +392,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -424,7 +424,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -529,7 +529,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "all",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -586,7 +586,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "off",
|
||||
},
|
||||
@ -615,7 +615,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
},
|
||||
@ -653,7 +653,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -690,7 +690,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "off",
|
||||
},
|
||||
@ -730,7 +730,7 @@ describe("cron tool", () => {
|
||||
resolveSandboxConfigForAgentMock.mockReturnValue({
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "last-only",
|
||||
},
|
||||
|
||||
@ -55,7 +55,7 @@ type CronSandboxAccess = {
|
||||
sessionKey?: string;
|
||||
policy: {
|
||||
visibility: "agent" | "all";
|
||||
escape: "off" | "elevated" | "elevated-full";
|
||||
elevated: "off" | "on" | "full";
|
||||
allowMainSessionJobs: boolean;
|
||||
delivery: "off" | "last-only" | "explicit";
|
||||
};
|
||||
@ -117,7 +117,7 @@ function resolveCronSandboxAccess(params: {
|
||||
sessionKey: undefined,
|
||||
policy: {
|
||||
visibility: "all",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
},
|
||||
@ -138,16 +138,12 @@ function resolveCronSandboxAccess(params: {
|
||||
const elevatedOn = elevatedLevel !== "off";
|
||||
const elevatedFull = elevatedLevel === "full";
|
||||
|
||||
const escapeAllowed =
|
||||
policy.escape === "elevated"
|
||||
? elevatedOn
|
||||
: policy.escape === "elevated-full"
|
||||
? elevatedFull
|
||||
: false;
|
||||
const elevatedAllowed =
|
||||
policy.elevated === "on" ? elevatedOn : policy.elevated === "full" ? elevatedFull : false;
|
||||
|
||||
return {
|
||||
sandboxed: runtime.sandboxed,
|
||||
restricted: runtime.sandboxed && !escapeAllowed,
|
||||
restricted: runtime.sandboxed && !elevatedAllowed,
|
||||
agentId: normalizedAgentId,
|
||||
sessionKey: rawSessionKey,
|
||||
policy,
|
||||
|
||||
@ -10,7 +10,7 @@ describe("sandbox cron config", () => {
|
||||
sandbox: {
|
||||
cron: {
|
||||
visibility: "agent",
|
||||
escape: "elevated",
|
||||
elevated: "on",
|
||||
allowMainSessionJobs: false,
|
||||
delivery: "last-only",
|
||||
},
|
||||
@ -22,7 +22,7 @@ describe("sandbox cron config", () => {
|
||||
sandbox: {
|
||||
cron: {
|
||||
visibility: "all",
|
||||
escape: "off",
|
||||
elevated: "off",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
},
|
||||
@ -48,7 +48,7 @@ describe("sandbox cron config", () => {
|
||||
sandbox: {
|
||||
cron: {
|
||||
visibility: "everyone",
|
||||
escape: "nope",
|
||||
elevated: "nope",
|
||||
delivery: "sometimes",
|
||||
},
|
||||
},
|
||||
@ -58,7 +58,7 @@ describe("sandbox cron config", () => {
|
||||
expect(res.ok).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts elevated-full escape and allowMainSessionJobs", async () => {
|
||||
it("accepts full elevated gate and allowMainSessionJobs", async () => {
|
||||
vi.resetModules();
|
||||
const { validateConfigObject } = await import("./config.js");
|
||||
const res = validateConfigObject({
|
||||
@ -67,7 +67,7 @@ describe("sandbox cron config", () => {
|
||||
sandbox: {
|
||||
cron: {
|
||||
visibility: "all",
|
||||
escape: "elevated-full",
|
||||
elevated: "full",
|
||||
allowMainSessionJobs: true,
|
||||
delivery: "explicit",
|
||||
},
|
||||
@ -78,7 +78,7 @@ describe("sandbox cron config", () => {
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
if (res.ok) {
|
||||
expect(res.config.agents?.defaults?.sandbox?.cron?.escape).toBe("elevated-full");
|
||||
expect(res.config.agents?.defaults?.sandbox?.cron?.elevated).toBe("full");
|
||||
expect(res.config.agents?.defaults?.sandbox?.cron?.allowMainSessionJobs).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
@ -75,7 +75,7 @@ export type SandboxPruneSettings = {
|
||||
};
|
||||
|
||||
export type SandboxCronVisibility = "agent" | "all";
|
||||
export type SandboxCronEscape = "off" | "elevated" | "elevated-full";
|
||||
export type SandboxCronElevated = "off" | "on" | "full";
|
||||
export type SandboxCronDelivery = "off" | "last-only" | "explicit";
|
||||
|
||||
export type SandboxCronSettings = {
|
||||
@ -86,12 +86,12 @@ export type SandboxCronSettings = {
|
||||
*/
|
||||
visibility?: SandboxCronVisibility;
|
||||
/**
|
||||
* Escape hatch for sandboxed cron access.
|
||||
* - "off": never escape
|
||||
* - "elevated": allow escape when session elevated != off
|
||||
* - "elevated-full": allow escape only when elevated=full
|
||||
* Elevated gate for sandboxed cron restrictions.
|
||||
* - "off": never bypass sandbox cron restrictions
|
||||
* - "on": bypass when the session elevated level is on/ask/full
|
||||
* - "full": bypass only when the session elevated level is full
|
||||
*/
|
||||
escape?: SandboxCronEscape;
|
||||
elevated?: SandboxCronElevated;
|
||||
/**
|
||||
* Allow main-session cron jobs from sandboxed sessions.
|
||||
* Default: false.
|
||||
|
||||
@ -161,9 +161,7 @@ export const AgentDefaultsSchema = z
|
||||
cron: z
|
||||
.object({
|
||||
visibility: z.union([z.literal("agent"), z.literal("all")]).optional(),
|
||||
escape: z
|
||||
.union([z.literal("off"), z.literal("elevated"), z.literal("elevated-full")])
|
||||
.optional(),
|
||||
elevated: z.union([z.literal("off"), z.literal("on"), z.literal("full")]).optional(),
|
||||
allowMainSessionJobs: z.boolean().optional(),
|
||||
delivery: z
|
||||
.union([z.literal("off"), z.literal("last-only"), z.literal("explicit")])
|
||||
|
||||
@ -237,9 +237,7 @@ export const AgentSandboxSchema = z
|
||||
cron: z
|
||||
.object({
|
||||
visibility: z.union([z.literal("agent"), z.literal("all")]).optional(),
|
||||
escape: z
|
||||
.union([z.literal("off"), z.literal("elevated"), z.literal("elevated-full")])
|
||||
.optional(),
|
||||
elevated: z.union([z.literal("off"), z.literal("on"), z.literal("full")]).optional(),
|
||||
allowMainSessionJobs: z.boolean().optional(),
|
||||
delivery: z
|
||||
.union([z.literal("off"), z.literal("last-only"), z.literal("explicit")])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user