From 23279417332c87017e707c29dad5ac7481c00b34 Mon Sep 17 00:00:00 2001 From: Itamar Zand <133867530+ItamarZand88@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:23:17 +0300 Subject: [PATCH] docs(sandbox): say the Azure binding lacks these, not the cloud The capability docs stated that Azure's data plane exposes no file transfer and takes no egress policy. Microsoft documents both as ADC data-plane capabilities, so what is absent is this binding's implementation of them. The distinction is not pedantic. Two of these strings are generated into the published schema and zod artifacts, so the claim reaches anyone reading the package, and it tells them a capability is impossible when it is unbuilt. The assertion message was the worst of them: whoever implements the Azure file operations will hit that failing test and be told the data plane cannot do what they just made it do. Assertions and behaviour are unchanged; the capability set still reports files and egressDeny false for Azure, which is correct for what a caller can reach today. --- crates/alien-core/src/resources/sandbox.rs | 10 +++++----- .../src/generated/schemas/sandboxCapabilities.json | 2 +- .../src/generated/zod/sandbox-capabilities-schema.ts | 2 +- packages/core/src/sandbox.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/alien-core/src/resources/sandbox.rs b/crates/alien-core/src/resources/sandbox.rs index 383202cd7..3f693c2d7 100644 --- a/crates/alien-core/src/resources/sandbox.rs +++ b/crates/alien-core/src/resources/sandbox.rs @@ -169,7 +169,7 @@ pub struct SandboxSessionPolicy { pub struct SandboxCapabilities { /// Files can be moved in and out of a session /// - /// Every backend but Azure, whose data plane exposes exec and lifecycle and no transfer. + /// Every backend but Azure, whose binding implements no transfer. pub files: bool, /// A later call can reach a session created by an earlier one pub reconnect: bool, @@ -862,9 +862,9 @@ mod tests { assert!(!gcp.enforced_limits); let azure = SandboxCapabilities::for_platform(Platform::Azure).expect("azure is supported"); - assert!(!azure.files, "the Azure data plane has no file transfer"); + assert!(!azure.files, "the Azure binding implements no file transfer"); assert!(gcp.files, "every other backend moves files"); - // The Azure data plane takes neither an egress policy nor a ceiling, so a declaration of + // The Azure binding renders neither an egress policy nor a ceiling, so a declaration of // either is refused rather than accepted and dropped. assert!(!azure.domain_egress_rules); assert!(!azure.egress_deny); @@ -911,7 +911,7 @@ mod tests { } /// No backend expresses a hostname allowlist: AWS and Kubernetes match CIDRs, and the Azure - /// data plane takes no egress policy at all. Accepting one anywhere would leave a stack + /// binding renders no egress policy at all. Accepting one anywhere would leave a stack /// reading as restricted while the sandbox reaches the whole internet. #[test] fn a_hostname_allowlist_is_refused_on_every_backend() { @@ -973,7 +973,7 @@ mod tests { let error = egress_only .validate_for_platform(Platform::Azure) - .expect_err("the Azure data plane takes no egress policy, so deny cannot be kept"); + .expect_err("the Azure binding renders no egress policy, so deny cannot be kept"); assert_eq!(error.code, "SANDBOX_CAPABILITY_UNSUPPORTED"); assert!( error.message.contains("egressDeny"), diff --git a/packages/core/src/generated/schemas/sandboxCapabilities.json b/packages/core/src/generated/schemas/sandboxCapabilities.json index d002e19d6..98a055f00 100644 --- a/packages/core/src/generated/schemas/sandboxCapabilities.json +++ b/packages/core/src/generated/schemas/sandboxCapabilities.json @@ -1 +1 @@ -{"type":"object","description":"What a platform's sandbox backend can actually do.\n\nPublished so portable code can branch before calling rather than discovering a gap through\nan error. Every field here corresponds to a capability that at least one platform lacks;\ncreate, exec and terminate are the guaranteed floor and are therefore not listed.","required":["files","reconnect","preview","suspendResume","snapshot","domainEgressRules","egressDeny","enforcedLimits","processLimit","sessionLifetime","supervisorPidNamespace"],"properties":{"domainEgressRules":{"type":"boolean","description":"Egress can be restricted to a hostname allowlist"},"egressDeny":{"type":"boolean","description":"Whether a declared `deny` is actually enforced, rather than accepted and dropped"},"enforcedLimits":{"type":"boolean","description":"The platform enforces the declared cpu, memory and disk ceilings"},"files":{"type":"boolean","description":"Files can be moved in and out of a session\n\nEvery backend but Azure, whose data plane exposes exec and lifecycle and no transfer."},"preview":{"type":"boolean","description":"An authenticated, port-scoped capability to reach a service inside the sandbox"},"processLimit":{"type":"boolean","description":"The platform can cap how many processes a session runs"},"reconnect":{"type":"boolean","description":"A later call can reach a session created by an earlier one"},"sessionLifetime":{"type":"boolean","description":"The platform terminates a session at a declared wall-clock deadline"},"snapshot":{"type":"boolean","description":"A session's full state can be captured and used to create another"},"supervisorPidNamespace":{"type":"boolean","description":"A command runs in its own PID namespace and cannot see or signal the agent's processes.\n\nOnly where an agent runs as root. Creating the namespace needs `CAP_SYS_ADMIN`, and the\nKubernetes sandbox pod drops every capability — which is also what denies `ptrace` by\nconstruction, so granting it there would remove a lock to add one."},"suspendResume":{"type":"boolean","description":"Session state can be suspended and resumed"}},"additionalProperties":false,"x-readme-ref-name":"SandboxCapabilities"} \ No newline at end of file +{"type":"object","description":"What a platform's sandbox backend can actually do.\n\nPublished so portable code can branch before calling rather than discovering a gap through\nan error. Every field here corresponds to a capability that at least one platform lacks;\ncreate, exec and terminate are the guaranteed floor and are therefore not listed.","required":["files","reconnect","preview","suspendResume","snapshot","domainEgressRules","egressDeny","enforcedLimits","processLimit","sessionLifetime","supervisorPidNamespace"],"properties":{"domainEgressRules":{"type":"boolean","description":"Egress can be restricted to a hostname allowlist"},"egressDeny":{"type":"boolean","description":"Whether a declared `deny` is actually enforced, rather than accepted and dropped"},"enforcedLimits":{"type":"boolean","description":"The platform enforces the declared cpu, memory and disk ceilings"},"files":{"type":"boolean","description":"Files can be moved in and out of a session\n\nEvery backend but Azure, whose binding implements no transfer."},"preview":{"type":"boolean","description":"An authenticated, port-scoped capability to reach a service inside the sandbox"},"processLimit":{"type":"boolean","description":"The platform can cap how many processes a session runs"},"reconnect":{"type":"boolean","description":"A later call can reach a session created by an earlier one"},"sessionLifetime":{"type":"boolean","description":"The platform terminates a session at a declared wall-clock deadline"},"snapshot":{"type":"boolean","description":"A session's full state can be captured and used to create another"},"supervisorPidNamespace":{"type":"boolean","description":"A command runs in its own PID namespace and cannot see or signal the agent's processes.\n\nOnly where an agent runs as root. Creating the namespace needs `CAP_SYS_ADMIN`, and the\nKubernetes sandbox pod drops every capability — which is also what denies `ptrace` by\nconstruction, so granting it there would remove a lock to add one."},"suspendResume":{"type":"boolean","description":"Session state can be suspended and resumed"}},"additionalProperties":false,"x-readme-ref-name":"SandboxCapabilities"} \ No newline at end of file diff --git a/packages/core/src/generated/zod/sandbox-capabilities-schema.ts b/packages/core/src/generated/zod/sandbox-capabilities-schema.ts index dd1bb47fc..fec2da979 100644 --- a/packages/core/src/generated/zod/sandbox-capabilities-schema.ts +++ b/packages/core/src/generated/zod/sandbox-capabilities-schema.ts @@ -12,7 +12,7 @@ export const SandboxCapabilitiesSchema = z.object({ "domainEgressRules": z.boolean().describe("Egress can be restricted to a hostname allowlist"), "egressDeny": z.boolean().describe("Whether a declared `deny` is actually enforced, rather than accepted and dropped"), "enforcedLimits": z.boolean().describe("The platform enforces the declared cpu, memory and disk ceilings"), -"files": z.boolean().describe("Files can be moved in and out of a session\n\nEvery backend but Azure, whose data plane exposes exec and lifecycle and no transfer."), +"files": z.boolean().describe("Files can be moved in and out of a session\n\nEvery backend but Azure, whose binding implements no transfer."), "preview": z.boolean().describe("An authenticated, port-scoped capability to reach a service inside the sandbox"), "processLimit": z.boolean().describe("The platform can cap how many processes a session runs"), "reconnect": z.boolean().describe("A later call can reach a session created by an earlier one"), diff --git a/packages/core/src/sandbox.ts b/packages/core/src/sandbox.ts index ecbb928d4..05a2945a9 100644 --- a/packages/core/src/sandbox.ts +++ b/packages/core/src/sandbox.ts @@ -33,8 +33,8 @@ export { SandboxSchema as SandboxConfigSchema } from "./generated/index.js" * * Capabilities are not uniform. Call `capabilities()` on the binding and branch, or handle the * typed error — an unsupported capability never silently succeeds. Notably GCP cannot - * reconnect to a session (its session id is scoped to one Cloud Run instance), Azure has no - * file transfer, and no platform supports a hostname egress allowlist. + * reconnect to a session (its session id is scoped to one Cloud Run instance), the Azure + * binding implements no file transfer, and no binding renders a hostname egress allowlist. * * Limits are enforced ceilings, not scheduling hints, and are validated when the stack is * planned. A platform that cannot enforce them rejects the sandbox rather than ignoring them.