@namzu/sandbox 18.1.1 → 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/README.md +35 -5
- package/dist/backends/docker/index.d.ts +46 -1
- package/dist/backends/docker/index.d.ts.map +1 -1
- package/dist/backends/docker/index.js +187 -51
- package/dist/backends/docker/index.js.map +1 -1
- package/dist/egress/index.d.ts +1 -0
- package/dist/egress/index.d.ts.map +1 -1
- package/dist/egress/index.js +1 -0
- package/dist/egress/index.js.map +1 -1
- package/dist/egress/profile-wiring.d.ts +40 -0
- package/dist/egress/profile-wiring.d.ts.map +1 -0
- package/dist/egress/profile-wiring.js +75 -0
- package/dist/egress/profile-wiring.js.map +1 -0
- package/dist/egress/profile.d.ts +153 -0
- package/dist/egress/profile.d.ts.map +1 -0
- package/dist/egress/profile.js +244 -0
- package/dist/egress/profile.js.map +1 -0
- package/dist/egress/proxy.d.ts +16 -0
- package/dist/egress/proxy.d.ts.map +1 -1
- package/dist/egress/proxy.js +37 -3
- package/dist/egress/proxy.js.map +1 -1
- package/dist/index.d.ts +19 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/seed/index.d.ts +165 -0
- package/dist/seed/index.d.ts.map +1 -0
- package/dist/seed/index.js +505 -0
- package/dist/seed/index.js.map +1 -0
- package/dist/testing/sandbox-conformance.d.ts +30 -1
- package/dist/testing/sandbox-conformance.d.ts.map +1 -1
- package/dist/testing/sandbox-conformance.js +18 -0
- package/dist/testing/sandbox-conformance.js.map +1 -1
- package/package.json +3 -3
- package/src/backends/docker/index.ts +246 -51
- package/src/egress/index.ts +1 -0
- package/src/egress/profile-wiring.ts +125 -0
- package/src/egress/profile.ts +380 -0
- package/src/egress/proxy.ts +53 -3
- package/src/index.ts +54 -5
- package/src/seed/index.ts +710 -0
- package/src/testing/sandbox-conformance.ts +52 -6
package/src/index.ts
CHANGED
|
@@ -92,6 +92,8 @@ import {
|
|
|
92
92
|
// local name and `ContainerBackendConfig.brokeredCredentials` needs one to
|
|
93
93
|
// point at. The public export is unchanged and stays type-only.
|
|
94
94
|
import type { BrokeredCredential } from './egress/index.js'
|
|
95
|
+
import { resolveProviderEgress } from './egress/profile-wiring.js'
|
|
96
|
+
import type { SandboxEgressProfile } from './egress/profile.js'
|
|
95
97
|
|
|
96
98
|
// Re-export the layout types so consumers of `@namzu/sandbox` can
|
|
97
99
|
// import them without also depending on `@namzu/sdk`. The canonical
|
|
@@ -1162,7 +1164,7 @@ export interface KubernetesBackendConfig {
|
|
|
1162
1164
|
* - `static` — fixed allowlist of hostnames at construction.
|
|
1163
1165
|
* - `resolver` — async closure returning the allowlist.
|
|
1164
1166
|
* Parameterless **on purpose**: the resolver is a closure that
|
|
1165
|
-
* captures whatever context the host has (tenantId,
|
|
1167
|
+
* captures whatever context the host has (tenantId, sessionId, turnId,
|
|
1166
1168
|
* auth token, etc.) at provider-construction time. Compass-
|
|
1167
1169
|
* platform's JWT-minting flow already works this way: the
|
|
1168
1170
|
* server knows the tenant when it issues the JWT, and the
|
|
@@ -1181,6 +1183,33 @@ export type {
|
|
|
1181
1183
|
EgressProxyOptions,
|
|
1182
1184
|
RunningEgressProxy,
|
|
1183
1185
|
} from './egress/index.js'
|
|
1186
|
+
export {
|
|
1187
|
+
defineEgressProfile,
|
|
1188
|
+
egressPortsForRules,
|
|
1189
|
+
egressProfileAllowsPort,
|
|
1190
|
+
kubernetesEgressFromProfile,
|
|
1191
|
+
SandboxEgressProfileError,
|
|
1192
|
+
} from './egress/profile.js'
|
|
1193
|
+
export type {
|
|
1194
|
+
KubernetesEgressProfileEnforcement,
|
|
1195
|
+
SandboxEgressHostRule,
|
|
1196
|
+
SandboxEgressProfile,
|
|
1197
|
+
SandboxEgressProfileErrorCode,
|
|
1198
|
+
} from './egress/profile.js'
|
|
1199
|
+
export {
|
|
1200
|
+
defineSandboxSeed,
|
|
1201
|
+
ensureSandboxSeed,
|
|
1202
|
+
sandboxSeedDigest,
|
|
1203
|
+
SandboxSeedError,
|
|
1204
|
+
} from './seed/index.js'
|
|
1205
|
+
export type {
|
|
1206
|
+
EnsureSandboxSeedOptions,
|
|
1207
|
+
SandboxSeed,
|
|
1208
|
+
SandboxSeedErrorCode,
|
|
1209
|
+
SandboxSeedReport,
|
|
1210
|
+
SandboxSeedRepository,
|
|
1211
|
+
SandboxSeedRepositoryReport,
|
|
1212
|
+
} from './seed/index.js'
|
|
1184
1213
|
|
|
1185
1214
|
export type EgressPolicy =
|
|
1186
1215
|
| { readonly kind: 'deny-all' }
|
|
@@ -1239,7 +1268,7 @@ export interface SandboxBackend {
|
|
|
1239
1268
|
* is in play.
|
|
1240
1269
|
*
|
|
1241
1270
|
* `layout` is **not** here — see the type-level note on
|
|
1242
|
-
* {@link SandboxBackend}. Identity-aware fields (tenantId /
|
|
1271
|
+
* {@link SandboxBackend}. Identity-aware fields (tenantId / sessionId / turnId /
|
|
1243
1272
|
* agentId) are deliberately NOT in this shape either; hosts that
|
|
1244
1273
|
* need per-tenant sandbox config bake the tenant into the closure
|
|
1245
1274
|
* that constructs the provider — see the `EgressPolicy` resolver
|
|
@@ -1294,6 +1323,18 @@ export type SandboxProviderConfig =
|
|
|
1294
1323
|
|
|
1295
1324
|
interface SandboxProviderConfigBase {
|
|
1296
1325
|
readonly defaultEgress?: EgressPolicy
|
|
1326
|
+
/**
|
|
1327
|
+
* A named, validated host allowlist with optional ports, instead of
|
|
1328
|
+
* `defaultEgress`. Validated here, synchronously, before any I/O, and
|
|
1329
|
+
* refused (`SandboxEgressProfileError`) where the backend cannot honour all
|
|
1330
|
+
* of it: beside `defaultEgress`; on the kubernetes backend, whose egress is
|
|
1331
|
+
* config-level (use `kubernetesEgressFromProfile` for `backend.egress`); on
|
|
1332
|
+
* the ACI standby pool; and ports on firecracker. On docker and runsc a
|
|
1333
|
+
* brokered credential for a host outside the profile is refused, and a live
|
|
1334
|
+
* `setNetworkPolicy` may only narrow within the profile. No hosts is
|
|
1335
|
+
* `deny-all`. See `docs/sdk/sandbox-egress-profiles.md`.
|
|
1336
|
+
*/
|
|
1337
|
+
readonly egressProfile?: SandboxEgressProfile
|
|
1297
1338
|
readonly defaultTimeoutMs?: number
|
|
1298
1339
|
readonly defaultMemoryLimitMb?: number
|
|
1299
1340
|
readonly defaultMaxProcesses?: number
|
|
@@ -1324,7 +1365,10 @@ interface SandboxProviderConfigBase {
|
|
|
1324
1365
|
* of a provider that confines nothing.
|
|
1325
1366
|
*/
|
|
1326
1367
|
export function createSandboxProvider(config: SandboxProviderConfig): SandboxProvider {
|
|
1327
|
-
|
|
1368
|
+
// Before the backend is built, so a profile the backend cannot honour is
|
|
1369
|
+
// refused with nothing constructed.
|
|
1370
|
+
const resolvedEgress = resolveProviderEgress(config)
|
|
1371
|
+
const backend = pickBackend(config, resolvedEgress.profile)
|
|
1328
1372
|
const id = `namzu-${backend.tier}-${backend.name}`
|
|
1329
1373
|
const name = `@namzu/sandbox: ${describeBackend(config.backend)}`
|
|
1330
1374
|
return {
|
|
@@ -1339,7 +1383,7 @@ export function createSandboxProvider(config: SandboxProviderConfig): SandboxPro
|
|
|
1339
1383
|
return await backend.create({
|
|
1340
1384
|
...(perCall?.signal !== undefined ? { signal: perCall.signal } : {}),
|
|
1341
1385
|
workingDirectory: perCall?.workingDirectory ?? '/workspace',
|
|
1342
|
-
...(
|
|
1386
|
+
...(resolvedEgress.egress !== undefined ? { egress: resolvedEgress.egress } : {}),
|
|
1343
1387
|
...(perCall?.timeoutMs !== undefined
|
|
1344
1388
|
? { timeoutMs: perCall.timeoutMs }
|
|
1345
1389
|
: config.defaultTimeoutMs !== undefined
|
|
@@ -1361,7 +1405,10 @@ export function createSandboxProvider(config: SandboxProviderConfig): SandboxPro
|
|
|
1361
1405
|
}
|
|
1362
1406
|
}
|
|
1363
1407
|
|
|
1364
|
-
function pickBackend(
|
|
1408
|
+
function pickBackend(
|
|
1409
|
+
config: SandboxProviderConfig,
|
|
1410
|
+
egressProfile: SandboxEgressProfile | undefined,
|
|
1411
|
+
): SandboxBackend {
|
|
1365
1412
|
const backend = config.backend
|
|
1366
1413
|
// Checked ahead of the `docker` default below: `ACIStandbyPoolBackendConfig`
|
|
1367
1414
|
// is a real arm of `SandboxProviderConfig` (see the discriminated union
|
|
@@ -1434,6 +1481,7 @@ function pickBackend(config: SandboxProviderConfig): SandboxBackend {
|
|
|
1434
1481
|
...(backend.writableRootfsPaths !== undefined
|
|
1435
1482
|
? { writableRootfsPaths: backend.writableRootfsPaths }
|
|
1436
1483
|
: {}),
|
|
1484
|
+
...(egressProfile !== undefined ? { egressProfile } : {}),
|
|
1437
1485
|
})
|
|
1438
1486
|
}
|
|
1439
1487
|
if (backend.tier === 'container' && backend.runtime === 'runsc') {
|
|
@@ -1468,6 +1516,7 @@ function pickBackend(config: SandboxProviderConfig): SandboxBackend {
|
|
|
1468
1516
|
...(backend.writableRootfsPaths !== undefined
|
|
1469
1517
|
? { writableRootfsPaths: backend.writableRootfsPaths }
|
|
1470
1518
|
: {}),
|
|
1519
|
+
...(egressProfile !== undefined ? { egressProfile } : {}),
|
|
1471
1520
|
})
|
|
1472
1521
|
}
|
|
1473
1522
|
// `microvm:self-hosted` targeting the OWNED Azure Firecracker
|