Build network policies for Vercel Sandbox around services instead of raw domains.
Instead of writing low-level domain rules like this:
const sandbox = await Sandbox.create({
networkPolicy: {
allow: {
"api.openai.com": [
{
transform: [
{
headers: {
Authorization: `Bearer ${apiKey}`,
},
},
],
},
],
},
},
});you can write this:
import { allow } from "sandbox-policy-builder";
const sandbox = await Sandbox.create({
networkPolicy: allow({
openai: { apiKey: process.env.OPENAI_API_KEY! },
claude: { apiKey: process.env.ANTHROPIC_API_KEY! },
github: { apiKey: process.env.GITHUB_TOKEN! },
}),
});The package expands service names into the domain-level NetworkPolicy shape required by @vercel/sandbox.
Vercel Sandbox credentials brokering is powerful, but the raw SDK API is domain-oriented.
That is precise, but repetitive in real apps:
codexandopenaiboth targetapi.openai.comclauderequiresx-api-keyandanthropic-versiongithuboften needs multiple related domainsaiGatewayis conceptually one service, not one header rule
This package gives you a small DSL that matches how people usually think about these integrations: service first, transport details second.
bun add sandbox-policy-builderOr:
npm install sandbox-policy-builderimport { allow } from "sandbox-policy-builder";
const sandbox = await Sandbox.create({
networkPolicy: allow({
openai: { apiKey: process.env.OPENAI_API_KEY! },
}),
});import { allow } from "sandbox-policy-builder";
const sandbox = await Sandbox.create({
networkPolicy: allow({
claude: { apiKey: process.env.ANTHROPIC_API_KEY! },
}),
});const sandbox = await Sandbox.create({
networkPolicy: allow({
github: { apiKey: process.env.GITHUB_TOKEN! },
}),
});This expands to GitHub-related domains including:
github.com*.github.comapi.github.com
const sandbox = await Sandbox.create({
networkPolicy: allow({
aiGateway: { apiKey: process.env.AI_GATEWAY_TOKEN! },
}),
});const sandbox = await Sandbox.create({
networkPolicy: allow({
openai: { apiKey: process.env.OPENAI_API_KEY! },
claude: { apiKey: process.env.ANTHROPIC_API_KEY! },
github: { apiKey: process.env.GITHUB_TOKEN! },
aiGateway: { apiKey: process.env.AI_GATEWAY_TOKEN! },
}),
});codexopenaigeminiclaudegithubaiGateway
Use listSupportedProducts() to inspect the current set:
import { listSupportedProducts } from "sandbox-policy-builder";
console.log(listSupportedProducts());Builds a Vercel Sandbox NetworkPolicy.
type AllowInput = Partial<{
codex: { apiKey: string };
openai: { apiKey: string };
gemini: { apiKey: string };
claude: { apiKey: string };
github: { apiKey: string };
aiGateway: { apiKey: string };
}>;Returns:
type NetworkPolicy =
| "allow-all"
| "deny-all"
| {
allow?: string[] | Record<string, NetworkPolicyRule[]>;
subnets?: {
allow?: string[];
deny?: string[];
};
};Returns the list of known product names.
Some products compile to the same underlying domain.
For example:
codex->api.openai.comopenai->api.openai.com
If two products generate different rules for the same domain, allow() throws.
This is intentional. Silent last-write-wins behavior would make credential brokering hard to reason about.
import { Sandbox } from "@vercel/sandbox";
import { allow } from "sandbox-policy-builder";
const sandbox = await Sandbox.create({
networkPolicy: allow({
github: { apiKey: process.env.GITHUB_TOKEN! },
aiGateway: { apiKey: process.env.AI_GATEWAY_TOKEN! },
}),
});If you need open network access during setup and want to lock the sandbox down afterward, allow() also works with updateNetworkPolicy():
await sandbox.updateNetworkPolicy(
allow({
openai: { apiKey: process.env.OPENAI_API_KEY! },
}),
);- This package does not change how Vercel Sandbox works. It only builds the
NetworkPolicyobject. - Product names are convenience abstractions over domains, headers, and credential brokering transforms.
- If a CLI requires a local env var just to start, you may still need a non-secret dummy value in the sandbox process. This package only handles network policy generation.