@sellable/install 0.1.357 → 0.1.358-phase111.20260720045223

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.
@@ -1,472 +0,0 @@
1
- import {
2
- chmodSync,
3
- existsSync,
4
- lstatSync,
5
- mkdirSync,
6
- readFileSync,
7
- realpathSync,
8
- writeFileSync,
9
- } from "node:fs";
10
- import { isAbsolute, join, relative, resolve } from "node:path";
11
- import { runBoundedChildProcess } from "./provisioning-adapter.mjs";
12
-
13
- const INPUT_KEYS = new Set([
14
- "profileId",
15
- "workerUid",
16
- "runtimeUid",
17
- "credentialReferences",
18
- "oauthPrivateReference",
19
- ]);
20
- const SAFE_ID = /^[A-Za-z0-9_-]{1,128}$/;
21
- const FINGERPRINT = /^[a-f0-9]{64}$/;
22
- const EXACT_EGRESS = [
23
- "https://app.sellable.dev",
24
- "https://slack.com",
25
- "https://api.openai.com",
26
- ];
27
-
28
- export const PINNED_CONTAINMENT_IMAGE =
29
- "public.ecr.aws/supabase/postgres@sha256:af083ef64d0408c8f098ee6f5c364a59b26f36fbc0f3a334a62c5c1d57362e9b";
30
-
31
- const CONTAINER_CHECK_KEYS = [
32
- "runtimeUid",
33
- "profileRead",
34
- "controlDenied",
35
- "credentialDenied",
36
- "oauthDenied",
37
- "siblingDenied",
38
- "hostDenied",
39
- "dockerDenied",
40
- "rootReadOnly",
41
- "noNewPrivileges",
42
- "capabilitiesDropped",
43
- "networkDisabled",
44
- ];
45
-
46
- function validPrivateReference(value, scheme) {
47
- return (
48
- value &&
49
- typeof value === "object" &&
50
- !Array.isArray(value) &&
51
- Object.keys(value).every((key) =>
52
- ["reference", "fingerprint", "purpose", "target", "owner"].includes(key)
53
- ) &&
54
- typeof value.reference === "string" &&
55
- value.reference.startsWith(`${scheme}://`) &&
56
- FINGERPRINT.test(value.fingerprint)
57
- );
58
- }
59
-
60
- export function buildContainmentContract(input) {
61
- if (!input || typeof input !== "object" || Array.isArray(input)) {
62
- return { ok: false, code: "invalid_input" };
63
- }
64
- if (Object.keys(input).some((key) => !INPUT_KEYS.has(key))) {
65
- return { ok: false, code: "unknown_field" };
66
- }
67
- if (
68
- !SAFE_ID.test(input.profileId) ||
69
- !Number.isSafeInteger(input.workerUid) ||
70
- input.workerUid < 1 ||
71
- !Number.isSafeInteger(input.runtimeUid) ||
72
- input.runtimeUid < 1 ||
73
- input.workerUid === input.runtimeUid ||
74
- !Array.isArray(input.credentialReferences) ||
75
- !input.credentialReferences.every(
76
- (reference) =>
77
- validPrivateReference(reference, "secret") &&
78
- ["service-credential", "worker-credential"].includes(reference.purpose)
79
- ) ||
80
- !validPrivateReference(input.oauthPrivateReference, "oauth-private")
81
- ) {
82
- return { ok: false, code: "invalid_input" };
83
- }
84
- const profileBase = `/var/lib/sellable-agents/${input.profileId}`;
85
- const manifest = {
86
- profileId: input.profileId,
87
- readOnlyRootFilesystem: true,
88
- noNewPrivileges: true,
89
- dockerSocket: false,
90
- capabilities: [],
91
- worker: {
92
- name: `sellable-worker-${input.profileId}`,
93
- uid: input.workerUid,
94
- },
95
- runtime: {
96
- name: `sellable-runtime-${input.profileId}`,
97
- uid: input.runtimeUid,
98
- },
99
- mounts: [
100
- {
101
- profileId: input.profileId,
102
- source: `${profileBase}/control`,
103
- target: "/control",
104
- readOnly: false,
105
- owner: "worker",
106
- },
107
- {
108
- profileId: input.profileId,
109
- source: `${profileBase}/profile`,
110
- target: "/profile",
111
- readOnly: false,
112
- owner: "runtime",
113
- },
114
- ],
115
- credentials: input.credentialReferences.map((reference) => ({
116
- purpose: reference.purpose,
117
- reference: reference.reference,
118
- fingerprint: reference.fingerprint,
119
- target: `/run/credentials/${reference.purpose}`,
120
- owner: "worker",
121
- })),
122
- oauthPrivateReference: {
123
- reference: input.oauthPrivateReference.reference,
124
- fingerprint: input.oauthPrivateReference.fingerprint,
125
- owner: "worker",
126
- },
127
- oauth: {
128
- privateExchangeOwner: "worker",
129
- healthStatus: "NOT_PROBED",
130
- auditStatus: "REQUIRED",
131
- broaderRolloutBlocked: true,
132
- },
133
- authority: {
134
- database: false,
135
- migrations: false,
136
- hostControl: false,
137
- },
138
- resources: { pids: 128, memoryMb: 1024, cpuQuota: 1 },
139
- egress: [...EXACT_EGRESS],
140
- };
141
- const validated = validateContainmentContract(manifest);
142
- return validated.ok ? { ok: true, manifest } : validated;
143
- }
144
-
145
- export function validateContainmentContract(manifest) {
146
- if (
147
- !manifest ||
148
- typeof manifest !== "object" ||
149
- !SAFE_ID.test(manifest.profileId)
150
- ) {
151
- return { ok: false, code: "invalid_manifest" };
152
- }
153
- if (
154
- manifest.readOnlyRootFilesystem !== true ||
155
- manifest.noNewPrivileges !== true ||
156
- manifest.dockerSocket !== false ||
157
- !Array.isArray(manifest.capabilities) ||
158
- manifest.capabilities.length !== 0
159
- ) {
160
- return { ok: false, code: "privilege_boundary_failed" };
161
- }
162
- if (
163
- !Number.isSafeInteger(manifest.worker?.uid) ||
164
- manifest.worker.uid < 1 ||
165
- !Number.isSafeInteger(manifest.runtime?.uid) ||
166
- manifest.runtime.uid < 1 ||
167
- manifest.worker.uid === manifest.runtime.uid
168
- ) {
169
- return { ok: false, code: "identity_boundary_failed" };
170
- }
171
- const profileBase = `/var/lib/sellable-agents/${manifest.profileId}/`;
172
- if (
173
- !Array.isArray(manifest.mounts) ||
174
- manifest.mounts.length !== 2 ||
175
- manifest.mounts.some(
176
- (mount) =>
177
- mount.profileId !== manifest.profileId ||
178
- typeof mount.source !== "string" ||
179
- !mount.source.startsWith(profileBase) ||
180
- !["/control", "/profile"].includes(mount.target) ||
181
- !["worker", "runtime"].includes(mount.owner) ||
182
- mount.source.includes("docker.sock")
183
- ) ||
184
- manifest.mounts.find((mount) => mount.target === "/control")?.owner !==
185
- "worker" ||
186
- manifest.mounts.find((mount) => mount.target === "/profile")?.owner !==
187
- "runtime"
188
- ) {
189
- return { ok: false, code: "mount_boundary_failed" };
190
- }
191
- if (
192
- !Array.isArray(manifest.credentials) ||
193
- !manifest.credentials.every(
194
- (reference) =>
195
- validPrivateReference(reference, "secret") &&
196
- typeof reference.target === "string" &&
197
- reference.target.startsWith("/run/credentials/") &&
198
- reference.owner === "worker"
199
- ) ||
200
- !validPrivateReference(manifest.oauthPrivateReference, "oauth-private") ||
201
- manifest.oauthPrivateReference.owner !== "worker"
202
- ) {
203
- return { ok: false, code: "secret_boundary_failed" };
204
- }
205
- if (
206
- manifest.oauth?.privateExchangeOwner !== "worker" ||
207
- manifest.oauth?.healthStatus !== "NOT_PROBED" ||
208
- manifest.oauth?.auditStatus !== "REQUIRED" ||
209
- manifest.oauth?.broaderRolloutBlocked !== true
210
- ) {
211
- return { ok: false, code: "oauth_readiness_boundary_failed" };
212
- }
213
- if (
214
- manifest.authority?.database !== false ||
215
- manifest.authority?.migrations !== false ||
216
- manifest.authority?.hostControl !== false
217
- ) {
218
- return { ok: false, code: "authority_boundary_failed" };
219
- }
220
- if (
221
- manifest.resources?.pids !== 128 ||
222
- manifest.resources?.memoryMb !== 1024 ||
223
- manifest.resources?.cpuQuota !== 1 ||
224
- JSON.stringify(manifest.egress) !== JSON.stringify(EXACT_EGRESS)
225
- ) {
226
- return { ok: false, code: "resource_or_egress_boundary_failed" };
227
- }
228
- if (
229
- /xox[bap]-|authorizationCode|authorization_code|accessToken|refreshToken/.test(
230
- JSON.stringify(manifest)
231
- )
232
- ) {
233
- return { ok: false, code: "raw_secret_material" };
234
- }
235
- return { ok: true, code: "contained" };
236
- }
237
-
238
- export function isContainmentEgressAllowed(manifest, value) {
239
- if (!validateContainmentContract(manifest).ok) return false;
240
- try {
241
- const url = new URL(value);
242
- if (url.protocol !== "https:" || url.username || url.password) return false;
243
- return manifest.egress.includes(url.origin);
244
- } catch {
245
- return false;
246
- }
247
- }
248
-
249
- function containedRelative(root, target) {
250
- const rel = relative(root, target);
251
- return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
252
- }
253
-
254
- export function materializeContainmentProfile(manifest, { root }) {
255
- if (!validateContainmentContract(manifest).ok) {
256
- return { ok: false, code: "invalid_manifest" };
257
- }
258
- try {
259
- if (!isAbsolute(root) || !existsSync(root) || lstatSync(root).isSymbolicLink()) {
260
- return { ok: false, code: "invalid_root" };
261
- }
262
- const realRoot = realpathSync(root);
263
- const profileRoot = join(realRoot, manifest.profileId);
264
- if (!containedRelative(realRoot, profileRoot)) {
265
- return { ok: false, code: "path_confinement_failed" };
266
- }
267
- mkdirSync(join(profileRoot, "control"), { recursive: true, mode: 0o700 });
268
- mkdirSync(join(profileRoot, "profile"), { recursive: true, mode: 0o750 });
269
- mkdirSync(join(profileRoot, "credentials"), { recursive: true, mode: 0o700 });
270
- writeFileSync(join(profileRoot, "profile", "probe.txt"), "sellable-agent-contained\n", {
271
- mode: 0o444,
272
- });
273
- chmodSync(join(profileRoot, "profile", "probe.txt"), 0o444);
274
- writeFileSync(
275
- join(profileRoot, "containment.json"),
276
- `${JSON.stringify(manifest, null, 2)}\n`,
277
- { mode: 0o600 }
278
- );
279
- return { ok: true, profileRoot };
280
- } catch {
281
- return { ok: false, code: "materialization_failed" };
282
- }
283
- }
284
-
285
- export function buildContainerContainmentProbeSpec(
286
- manifest,
287
- { root, runtimeUid, runtimeGid }
288
- ) {
289
- const validation = validateContainmentContract(manifest);
290
- if (!validation.ok) return { ok: false, code: validation.code };
291
- try {
292
- if (
293
- !Number.isSafeInteger(runtimeUid) ||
294
- runtimeUid < 1 ||
295
- !Number.isSafeInteger(runtimeGid) ||
296
- runtimeGid < 1 ||
297
- !isAbsolute(root) ||
298
- String(root).includes(",") ||
299
- String(root).includes("\n")
300
- ) {
301
- return { ok: false, code: "invalid_probe_runtime" };
302
- }
303
- const realRoot = realpathSync(root);
304
- const materializedRoot = realpathSync(join(realRoot, manifest.profileId));
305
- const profileData = realpathSync(join(materializedRoot, "profile"));
306
- if (
307
- !containedRelative(realRoot, materializedRoot) ||
308
- !containedRelative(materializedRoot, profileData) ||
309
- lstatSync(profileData).isSymbolicLink() ||
310
- readFileSync(join(profileData, "probe.txt"), "utf8") !==
311
- "sellable-agent-contained\n"
312
- ) {
313
- return { ok: false, code: "invalid_materialized_profile" };
314
- }
315
- const script = [
316
- `test "$(id -u)" = "${runtimeUid}"`,
317
- 'test "$(cat /profile/probe.txt)" = "sellable-agent-contained"',
318
- 'test ! -r /control/probe.txt',
319
- 'test ! -r /run/credentials/service-credential',
320
- 'test ! -r /run/credentials/oauth-private',
321
- 'test ! -r /siblings/profile-2/probe.txt',
322
- 'test ! -r /host/probe.txt',
323
- 'test ! -S /var/run/docker.sock',
324
- 'if touch /sellable-root-write-probe 2>/dev/null; then exit 31; fi',
325
- "grep -Eq '^NoNewPrivs:[[:space:]]+1$' /proc/self/status",
326
- "grep -Eq '^CapEff:[[:space:]]+0+$' /proc/self/status",
327
- "test ! -e /sys/class/net/eth0",
328
- `printf '%s\\n' '${JSON.stringify({
329
- ok: true,
330
- checks: Object.fromEntries(CONTAINER_CHECK_KEYS.map((key) => [key, true])),
331
- })}'`,
332
- ].join("\n");
333
- const args = [
334
- "run",
335
- "--rm",
336
- "--label",
337
- "sellable.containment.probe=1",
338
- "--pull",
339
- "never",
340
- "--network",
341
- "none",
342
- "--read-only",
343
- "--cap-drop",
344
- "ALL",
345
- "--security-opt",
346
- "no-new-privileges",
347
- "--pids-limit",
348
- "128",
349
- "--memory",
350
- "1024m",
351
- "--cpus",
352
- "1",
353
- "--user",
354
- `${runtimeUid}:${runtimeGid}`,
355
- "--tmpfs",
356
- "/tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777",
357
- "--mount",
358
- `type=bind,src=${profileData},dst=/profile,readonly`,
359
- PINNED_CONTAINMENT_IMAGE,
360
- "sh",
361
- "-ceu",
362
- script,
363
- ];
364
- return {
365
- ok: true,
366
- command: "docker",
367
- image: PINNED_CONTAINMENT_IMAGE,
368
- args,
369
- shell: false,
370
- timeoutMs: 30_000,
371
- maxOutputBytes: 8 * 1024,
372
- };
373
- } catch {
374
- return { ok: false, code: "invalid_materialized_profile" };
375
- }
376
- }
377
-
378
- export async function runContainerContainmentProbe(manifest, runtime) {
379
- const spec = buildContainerContainmentProbeSpec(manifest, runtime);
380
- if (!spec.ok) return { ...spec, checks: {} };
381
- const output = await runBoundedChildProcess(spec);
382
- if (
383
- output.exitCode !== 0 ||
384
- output.timedOut ||
385
- output.outputLimitExceeded ||
386
- output.terminated
387
- ) {
388
- return { ok: false, code: "container_probe_failed", checks: {} };
389
- }
390
- try {
391
- const parsed = JSON.parse(output.stdout);
392
- if (
393
- !parsed ||
394
- parsed.ok !== true ||
395
- Object.keys(parsed).sort().join("\0") !== ["checks", "ok"].sort().join("\0") ||
396
- Object.keys(parsed.checks).sort().join("\0") !==
397
- [...CONTAINER_CHECK_KEYS].sort().join("\0") ||
398
- CONTAINER_CHECK_KEYS.some((key) => parsed.checks[key] !== true)
399
- ) {
400
- throw new Error("invalid probe result");
401
- }
402
- return { ok: true, code: "contained", checks: parsed.checks };
403
- } catch {
404
- return { ok: false, code: "container_probe_failed", checks: {} };
405
- }
406
- }
407
-
408
- function identityCanAccess(manifest, identity, target) {
409
- if (identity !== "worker" && identity !== "runtime") return false;
410
- if (target === "/") return false;
411
- if (target === "/var/run/docker.sock") return false;
412
- if (target.startsWith("/run/credentials/")) return identity === "worker";
413
- const mount = manifest.mounts.find(
414
- (candidate) => target === candidate.target || target.startsWith(`${candidate.target}/`)
415
- );
416
- return Boolean(mount && mount.owner === identity);
417
- }
418
-
419
- export function probeContainmentProfile(manifest, { root }) {
420
- const validation = validateContainmentContract(manifest);
421
- if (!validation.ok) return { ok: false, code: validation.code, checks: {} };
422
- try {
423
- const realRoot = realpathSync(root);
424
- const profileRoot = realpathSync(join(realRoot, manifest.profileId));
425
- const materializedManifest = JSON.parse(
426
- readFileSync(join(profileRoot, "containment.json"), "utf8")
427
- );
428
- if (JSON.stringify(materializedManifest) !== JSON.stringify(manifest)) {
429
- return { ok: false, code: "materialized_manifest_mismatch", checks: {} };
430
- }
431
- const checks = {
432
- runtimeProfile: identityCanAccess(manifest, "runtime", "/profile"),
433
- runtimeControlDenied: !identityCanAccess(manifest, "runtime", "/control"),
434
- runtimeCredentialDenied: !identityCanAccess(
435
- manifest,
436
- "runtime",
437
- "/run/credentials/service-credential"
438
- ),
439
- runtimeOauthDenied: !identityCanAccess(
440
- manifest,
441
- "runtime",
442
- "/run/credentials/oauth-private"
443
- ),
444
- siblingDenied: !identityCanAccess(manifest, "runtime", "/siblings/profile-2"),
445
- rootDenied: !identityCanAccess(manifest, "runtime", "/"),
446
- dockerDenied: !identityCanAccess(manifest, "runtime", "/var/run/docker.sock"),
447
- databaseDenied: manifest.authority.database === false,
448
- migrationDenied: manifest.authority.migrations === false,
449
- sellableAllowed: isContainmentEgressAllowed(
450
- manifest,
451
- "https://app.sellable.dev/api/v3/workspaces"
452
- ),
453
- slackAllowed: isContainmentEgressAllowed(
454
- manifest,
455
- "https://slack.com/api/auth.test"
456
- ),
457
- modelAllowed: isContainmentEgressAllowed(
458
- manifest,
459
- "https://api.openai.com/v1/responses"
460
- ),
461
- extraEndpointDenied: !isContainmentEgressAllowed(
462
- manifest,
463
- "https://evil.example/collect"
464
- ),
465
- };
466
- return Object.values(checks).every(Boolean)
467
- ? { ok: true, code: "contained", checks }
468
- : { ok: false, code: "probe_failed", checks };
469
- } catch {
470
- return { ok: false, code: "probe_failed", checks: {} };
471
- }
472
- }