@capsulos/sdk 0.2.0 → 0.3.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/dist/capsule.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // The public face of a capsule. `Capsule.create()` asks the provider for a
2
2
  // machine and waits until capsulod answers; everything after that goes
3
3
  // straight to the daemon.
4
+ import { validateNetworkPolicy } from './network.js';
4
5
  import { DaemonClient } from './client.js';
5
6
  import { Ports } from './ports.js';
6
7
  import { PtySession } from './pty.js';
@@ -27,23 +28,38 @@ export class Capsule {
27
28
  }
28
29
  /** Throw a capsule: create it with the provider and wait until it is ready. */
29
30
  static async create(provider, spec, opts = {}) {
31
+ const network = validateNetworkPolicy(spec.network);
30
32
  const handle = await provider.create(spec, { timeoutMs: opts.createTimeoutMs, signal: opts.signal });
31
33
  const client = new DaemonClient(handle.connection, opts);
32
- const health = await waitReady(client, opts.readyTimeoutMs ?? 120_000, opts.signal);
33
- // Providers deliver the mount table through their boot hook. When that did
34
- // not happen (no hook, or the hook came without its payload), hand it over
35
- // directly. Either way, a mount that failed is an error here, not a
36
- // surprise later when a write lands in a plain directory.
37
- let results = health.mounts ?? [];
38
- const wanted = Object.keys(spec.mounts ?? {});
39
- const applied = new Set(results.map((r) => r.path));
40
- const hookMissed = !health.configured || wanted.some((p) => !applied.has(p));
41
- if (hookMissed && (spec.mounts || spec.metadata)) {
42
- results = await client.configure({ mounts: spec.mounts, metadata: spec.metadata });
34
+ try {
35
+ const health = await waitReady(client, opts.readyTimeoutMs ?? 120_000, opts.signal);
36
+ // Providers deliver mounts and network policy through their boot hook.
37
+ // When that did not happen (no hook, or the hook came without its
38
+ // payload, or the policy failed there), hand it over directly. Either
39
+ // way, a mount that failed or a policy that is not enforced is an error
40
+ // here, not a surprise later.
41
+ let results = health.mounts ?? [];
42
+ let status = health.network;
43
+ const wanted = Object.keys(spec.mounts ?? {});
44
+ const applied = new Set(results.map((r) => r.path));
45
+ const hookMissed = !health.configured || wanted.some((p) => !applied.has(p)) || (network && !status?.enforced);
46
+ if (hookMissed && (spec.mounts || spec.metadata || network)) {
47
+ ({ mounts: results, network: status } = await client.configure({ mounts: spec.mounts, metadata: spec.metadata, network }));
48
+ }
49
+ const failed = results.filter((r) => !r.ok);
50
+ if (failed.length) {
51
+ throw new CapsuleError(`mounts failed: ${failed.map((r) => `${r.path} (${r.driver}): ${r.error}`).join('; ')}`);
52
+ }
53
+ if (network && !status?.enforced) {
54
+ throw new CapsuleError(`network policy not enforced: ${status?.error ?? 'the daemon reported no policy (is it 0.3.0 or newer?)'}`);
55
+ }
43
56
  }
44
- const failed = results.filter((r) => !r.ok);
45
- if (failed.length) {
46
- throw new CapsuleError(`mounts failed: ${failed.map((r) => `${r.path} (${r.driver}): ${r.error}`).join('; ')}`);
57
+ catch (err) {
58
+ // A capsule that did not get its spec is not handed out: it goes, and
59
+ // the error says which one it was.
60
+ await provider.terminate(handle.id).catch(() => { });
61
+ const e = err instanceof CapsuleError ? err : new CapsuleError(err instanceof Error ? err.message : String(err));
62
+ throw new CapsuleError(`${e.message} (capsule ${handle.id} terminated)`, e.status, { capsuleId: handle.id });
47
63
  }
48
64
  return new Capsule(handle.id, provider, client, opts.readyTimeoutMs);
49
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"capsule.js","sourceRoot":"","sources":["../src/capsule.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,uEAAuE;AACvE,0BAA0B;AAC1B,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EACL,YAAY,GASb,MAAM,YAAY,CAAC;AAWpB,MAAM,OAAO,OAAO;IAQP;IACQ;IACA;IACA;IAVV,QAAQ,CAAW;IACnB,KAAK,CAAQ;IACb,GAAG,CAAM;IAClB,yFAAyF;IAChF,KAAK,CAAQ;IAEtB,YACW,EAAU,EACF,QAAkB,EAClB,MAAoB,EACpB,iBAAiB,OAAO;QAHhC,OAAE,GAAF,EAAE,CAAQ;QACF,aAAQ,GAAR,QAAQ,CAAU;QAClB,WAAM,GAAN,MAAM,CAAc;QACpB,mBAAc,GAAd,cAAc,CAAU;QAEzC,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;IAED,+EAA+E;IAC/E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAkB,EAAE,IAAiB,EAAE,OAAuB,EAAE;QAClF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACrG,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,IAAI,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpF,2EAA2E;QAC3E,2EAA2E;QAC3E,oEAAoE;QACpE,0DAA0D;QAC1D,IAAI,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,YAAY,CAAC,kBAAkB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClH,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACvE,CAAC;IAED,sGAAsG;IACtG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAkB,EAAE,EAAU,EAAE,OAAuB,EAAE;QAC5E,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxC,OAAO,IAAI,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACtF,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpE,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,MAAM;QACV,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtE,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,QAAQ;IACU;IAA7B,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IACrD,sGAAsG;IACtG,GAAG,CAAC,GAAW,EAAE,IAAkB;QACjC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,GAAG;IACe;IAA7B,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IACrD,yDAAyD;IACzD,IAAI,CAAC,IAAiB;QACpB,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;CACF;AAED,MAAM,OAAO,KAAK;IACa;IAA7B,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IACrD,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,KAAK,CAAC,IAAY,EAAE,IAAyB,EAAE,IAAwB;QACrE,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,IAAY;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,CAAC,IAAY;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;CACF;AAED,SAAS,WAAW,CAAC,QAAkB,EAAE,EAAU;IACjD,OAAO,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,IAAI,8BAA8B,EAAE,IAAI,CAAC,CAAC;AACpF,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAoB,EAAE,SAAiB,EAAE,MAAoB;IACpF,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,IAAI,OAAgB,CAAC;IACrB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;QACnC,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,IAAI,YAAY,CAAC,qCAAqC,CAAC,CAAC;QACnF,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,EAAE;gBAAE,OAAO,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,IAAI,YAAY,CAAC,0CAA0C,SAAS,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACvG,CAAC"}
1
+ {"version":3,"file":"capsule.js","sourceRoot":"","sources":["../src/capsule.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Connection, type ExecEvent, type ExecOptions, type ExecResult, type FileEntry, type Health, type MountResult, type MountSpec } from './types.js';
1
+ import { type Connection, type ExecEvent, type ExecOptions, type ExecResult, type FileEntry, type Health, type MountResult, type MountSpec, type NetworkPolicy, type NetworkStatus } from './types.js';
2
2
  export interface ClientOptions {
3
3
  fetch?: typeof fetch;
4
4
  requestTimeoutMs?: number;
@@ -10,11 +10,15 @@ export declare class DaemonClient {
10
10
  constructor(connection: Connection, opts?: ClientOptions);
11
11
  private request;
12
12
  health(): Promise<Health>;
13
- /** Apply the mount table when the provider's boot hook did not deliver it. */
13
+ /** Apply the mount table and network policy when the provider's boot hook did not deliver them. */
14
14
  configure(body: {
15
15
  mounts?: Record<string, MountSpec>;
16
16
  metadata?: Record<string, string>;
17
- }): Promise<MountResult[]>;
17
+ network?: NetworkPolicy;
18
+ }): Promise<{
19
+ mounts: MountResult[];
20
+ network?: NetworkStatus;
21
+ }>;
18
22
  /** Buffered or streamed depending on whether callbacks are given. */
19
23
  exec(cmd: string, opts?: ExecOptions): Promise<ExecResult>;
20
24
  readFile(path: string): Promise<Uint8Array>;
package/dist/client.js CHANGED
@@ -37,7 +37,7 @@ export class DaemonClient {
37
37
  const res = await this.request('/health', { timeoutMs: 10_000 });
38
38
  return (await res.json());
39
39
  }
40
- /** Apply the mount table when the provider's boot hook did not deliver it. */
40
+ /** Apply the mount table and network policy when the provider's boot hook did not deliver them. */
41
41
  async configure(body) {
42
42
  const res = await this.request('/configure', {
43
43
  method: 'POST',
@@ -45,7 +45,8 @@ export class DaemonClient {
45
45
  headers: { 'Content-Type': 'application/json' },
46
46
  timeoutMs: 60_000,
47
47
  });
48
- return (await res.json()).mounts ?? [];
48
+ const out = (await res.json());
49
+ return { mounts: out.mounts ?? [], network: out.network };
49
50
  }
50
51
  /** Buffered or streamed depending on whether callbacks are given. */
51
52
  async exec(cmd, opts = {}) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export type { CapsuleOptions } from './capsule.js';
5
5
  export { DaemonClient, parseSse } from './client.js';
6
6
  export type { ClientOptions } from './client.js';
7
7
  export * from './types.js';
8
+ export { validateNetworkPolicy } from './network.js';
package/dist/index.js CHANGED
@@ -3,4 +3,5 @@ export { Ports } from './ports.js';
3
3
  export { PtySession } from './pty.js';
4
4
  export { DaemonClient, parseSse } from './client.js';
5
5
  export * from './types.js';
6
+ export { validateNetworkPolicy } from './network.js';
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAErD,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAErD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type NetworkPolicy } from './types.js';
2
+ /**
3
+ * Check a network policy before a capsule is created with it (the daemon
4
+ * applies the same rules; failing here saves a launch). Returns the policy
5
+ * when it restricts something, undefined when it does not.
6
+ */
7
+ export declare function validateNetworkPolicy(policy: NetworkPolicy | undefined): NetworkPolicy | undefined;
@@ -0,0 +1,37 @@
1
+ import { CapsuleError } from './types.js';
2
+ /**
3
+ * Check a network policy before a capsule is created with it (the daemon
4
+ * applies the same rules; failing here saves a launch). Returns the policy
5
+ * when it restricts something, undefined when it does not.
6
+ */
7
+ export function validateNetworkPolicy(policy) {
8
+ if (!policy)
9
+ return undefined;
10
+ if (policy.internet !== 'allow' && policy.internet !== 'deny') {
11
+ throw new CapsuleError(`network.internet must be 'allow' or 'deny', got ${JSON.stringify(policy.internet)}`);
12
+ }
13
+ if (policy.internet === 'allow') {
14
+ if (policy.allow?.length)
15
+ throw new CapsuleError("network.allow needs network.internet: 'deny'");
16
+ return undefined;
17
+ }
18
+ for (const entry of policy.allow ?? []) {
19
+ if (!isAllowEntry(entry)) {
20
+ throw new CapsuleError(`bad network.allow entry ${JSON.stringify(entry)} (want host, *.domain or host:port)`);
21
+ }
22
+ }
23
+ return policy;
24
+ }
25
+ const HOST = /^(\*\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
26
+ function isAllowEntry(entry) {
27
+ if (typeof entry !== 'string')
28
+ return false;
29
+ const m = /^(.*?)(?::(\d{1,5}))?$/.exec(entry.trim());
30
+ if (!m)
31
+ return false;
32
+ const [, host, port] = m;
33
+ if (port !== undefined && (Number(port) < 1 || Number(port) > 65535))
34
+ return false;
35
+ return host !== undefined && HOST.test(host);
36
+ }
37
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAiC;IACrE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC9D,MAAM,IAAI,YAAY,CAAC,mDAAmD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM;YAAE,MAAM,IAAI,YAAY,CAAC,8CAA8C,CAAC,CAAC;QACjG,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,YAAY,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAChH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,IAAI,GAAG,2EAA2E,CAAC;AAEzF,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,CAAC,GAAG,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnF,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC"}
package/dist/types.d.ts CHANGED
@@ -100,6 +100,7 @@ export interface Health {
100
100
  /** True once the mount table was applied (by the boot hook or /configure). */
101
101
  configured: boolean;
102
102
  mounts?: MountResult[];
103
+ network?: NetworkStatus;
103
104
  /** The template's long-running process (CAPSULOD_START), when the template declares one. */
104
105
  service?: ServiceStatus;
105
106
  }
@@ -111,6 +112,33 @@ export interface ServiceStatus {
111
112
  lastExitCode?: number;
112
113
  startedAt?: string;
113
114
  }
115
+ /**
116
+ * What the capsule may reach. With `internet: 'deny'` the daemon runs an
117
+ * egress proxy limited to `allow` (HTTP_PROXY/HTTPS_PROXY point at it for
118
+ * every process) and blackholes the default route, so a process that ignores
119
+ * the proxy gets "network unreachable" rather than the internet. Needs
120
+ * CAP_NET_ADMIN in the capsule: Lambda templates built with
121
+ * `--capabilities all`; the Docker provider adds it. Creation fails if the
122
+ * policy cannot be enforced.
123
+ */
124
+ export interface NetworkPolicy {
125
+ /** 'allow' (default): unrestricted. 'deny': nothing leaves except `allow`. */
126
+ internet: 'allow' | 'deny';
127
+ /** Destinations still reachable with 'deny': 'host', '*.domain' (subdomains only) or 'host:port'. */
128
+ allow?: string[];
129
+ }
130
+ /** The daemon's view of the policy (`health().network`; absent without a policy). */
131
+ export interface NetworkStatus {
132
+ internet: 'allow' | 'deny';
133
+ allow?: string[];
134
+ /** True once the proxy runs and the routes are locked. */
135
+ enforced: boolean;
136
+ /** The egress proxy's address inside the capsule (127.0.0.1:3128). */
137
+ proxy?: string;
138
+ /** Connections refused so far. */
139
+ blocked: number;
140
+ error?: string;
141
+ }
114
142
  export interface IdlePolicy {
115
143
  /** Suspend after this long without traffic (seconds). */
116
144
  suspendAfterSeconds: number;
@@ -126,6 +154,8 @@ export interface CapsuleSpec {
126
154
  mounts?: Record<string, MountSpec>;
127
155
  /** Opaque per-capsule configuration delivered to the daemon at boot (never secrets). */
128
156
  metadata?: Record<string, string>;
157
+ /** Egress policy, enforced inside the capsule by the daemon (default: unrestricted). */
158
+ network?: NetworkPolicy;
129
159
  /** Idempotency key: creating twice with the same key returns the same capsule. */
130
160
  clientToken?: string;
131
161
  }
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,0EAA0E;AAC1E,kEAAkE;AAClE,gFAAgF;AA4LhF,MAAM,OAAO,YAAa,SAAQ,KAAK;IAM1B;IALX,sGAAsG;IAC7F,SAAS,CAAU;IAE5B,YACE,OAAe,EACN,MAAe,EACxB,OAA+B,EAAE;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAS;QAIxB,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACtD,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,0EAA0E;AAC1E,kEAAkE;AAClE,gFAAgF;AA4NhF,MAAM,OAAO,YAAa,SAAQ,KAAK;IAM1B;IALX,sGAAsG;IAC7F,SAAS,CAAU;IAE5B,YACE,OAAe,EACN,MAAe,EACxB,OAA+B,EAAE;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAS;QAIxB,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACtD,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capsulos/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Throw a capsule, get a computer. Sandboxes for AI agents on your own AWS account (Lambda MicroVMs) or on Docker.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
package/src/capsule.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // The public face of a capsule. `Capsule.create()` asks the provider for a
2
2
  // machine and waits until capsulod answers; everything after that goes
3
3
  // straight to the daemon.
4
+ import { validateNetworkPolicy } from './network.js';
4
5
  import { DaemonClient, type ClientOptions } from './client.js';
5
6
  import { Ports } from './ports.js';
6
7
  import { PtySession } from './pty.js';
@@ -46,23 +47,37 @@ export class Capsule {
46
47
 
47
48
  /** Throw a capsule: create it with the provider and wait until it is ready. */
48
49
  static async create(provider: Provider, spec: CapsuleSpec, opts: CapsuleOptions = {}): Promise<Capsule> {
50
+ const network = validateNetworkPolicy(spec.network);
49
51
  const handle = await provider.create(spec, { timeoutMs: opts.createTimeoutMs, signal: opts.signal });
50
52
  const client = new DaemonClient(handle.connection, opts);
51
- const health = await waitReady(client, opts.readyTimeoutMs ?? 120_000, opts.signal);
52
- // Providers deliver the mount table through their boot hook. When that did
53
- // not happen (no hook, or the hook came without its payload), hand it over
54
- // directly. Either way, a mount that failed is an error here, not a
55
- // surprise later when a write lands in a plain directory.
56
- let results = health.mounts ?? [];
57
- const wanted = Object.keys(spec.mounts ?? {});
58
- const applied = new Set(results.map((r) => r.path));
59
- const hookMissed = !health.configured || wanted.some((p) => !applied.has(p));
60
- if (hookMissed && (spec.mounts || spec.metadata)) {
61
- results = await client.configure({ mounts: spec.mounts, metadata: spec.metadata });
62
- }
63
- const failed = results.filter((r) => !r.ok);
64
- if (failed.length) {
65
- throw new CapsuleError(`mounts failed: ${failed.map((r) => `${r.path} (${r.driver}): ${r.error}`).join('; ')}`);
53
+ try {
54
+ const health = await waitReady(client, opts.readyTimeoutMs ?? 120_000, opts.signal);
55
+ // Providers deliver mounts and network policy through their boot hook.
56
+ // When that did not happen (no hook, or the hook came without its
57
+ // payload, or the policy failed there), hand it over directly. Either
58
+ // way, a mount that failed or a policy that is not enforced is an error
59
+ // here, not a surprise later.
60
+ let results = health.mounts ?? [];
61
+ let status = health.network;
62
+ const wanted = Object.keys(spec.mounts ?? {});
63
+ const applied = new Set(results.map((r) => r.path));
64
+ const hookMissed = !health.configured || wanted.some((p) => !applied.has(p)) || (network && !status?.enforced);
65
+ if (hookMissed && (spec.mounts || spec.metadata || network)) {
66
+ ({ mounts: results, network: status } = await client.configure({ mounts: spec.mounts, metadata: spec.metadata, network }));
67
+ }
68
+ const failed = results.filter((r) => !r.ok);
69
+ if (failed.length) {
70
+ throw new CapsuleError(`mounts failed: ${failed.map((r) => `${r.path} (${r.driver}): ${r.error}`).join('; ')}`);
71
+ }
72
+ if (network && !status?.enforced) {
73
+ throw new CapsuleError(`network policy not enforced: ${status?.error ?? 'the daemon reported no policy (is it 0.3.0 or newer?)'}`);
74
+ }
75
+ } catch (err) {
76
+ // A capsule that did not get its spec is not handed out: it goes, and
77
+ // the error says which one it was.
78
+ await provider.terminate(handle.id).catch(() => {});
79
+ const e = err instanceof CapsuleError ? err : new CapsuleError(err instanceof Error ? err.message : String(err));
80
+ throw new CapsuleError(`${e.message} (capsule ${handle.id} terminated)`, e.status, { capsuleId: handle.id });
66
81
  }
67
82
  return new Capsule(handle.id, provider, client, opts.readyTimeoutMs);
68
83
  }
package/src/client.ts CHANGED
@@ -10,6 +10,8 @@ import {
10
10
  type Health,
11
11
  type MountResult,
12
12
  type MountSpec,
13
+ type NetworkPolicy,
14
+ type NetworkStatus,
13
15
  } from './types.js';
14
16
 
15
17
  export interface ClientOptions {
@@ -57,15 +59,20 @@ export class DaemonClient {
57
59
  return (await res.json()) as Health;
58
60
  }
59
61
 
60
- /** Apply the mount table when the provider's boot hook did not deliver it. */
61
- async configure(body: { mounts?: Record<string, MountSpec>; metadata?: Record<string, string> }): Promise<MountResult[]> {
62
+ /** Apply the mount table and network policy when the provider's boot hook did not deliver them. */
63
+ async configure(body: {
64
+ mounts?: Record<string, MountSpec>;
65
+ metadata?: Record<string, string>;
66
+ network?: NetworkPolicy;
67
+ }): Promise<{ mounts: MountResult[]; network?: NetworkStatus }> {
62
68
  const res = await this.request('/configure', {
63
69
  method: 'POST',
64
70
  body: JSON.stringify(body),
65
71
  headers: { 'Content-Type': 'application/json' },
66
72
  timeoutMs: 60_000,
67
73
  });
68
- return ((await res.json()) as { mounts: MountResult[] }).mounts ?? [];
74
+ const out = (await res.json()) as { mounts?: MountResult[]; network?: NetworkStatus };
75
+ return { mounts: out.mounts ?? [], network: out.network };
69
76
  }
70
77
 
71
78
  /** Buffered or streamed depending on whether callbacks are given. */
package/src/index.ts CHANGED
@@ -5,3 +5,4 @@ export type { CapsuleOptions } from './capsule.js';
5
5
  export { DaemonClient, parseSse } from './client.js';
6
6
  export type { ClientOptions } from './client.js';
7
7
  export * from './types.js';
8
+ export { validateNetworkPolicy } from './network.js';
@@ -0,0 +1,101 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Capsule } from './capsule.js';
3
+ import { validateNetworkPolicy } from './network.js';
4
+ import type { CapsuleHandle, Provider } from './types.js';
5
+
6
+ describe('validateNetworkPolicy', () => {
7
+ it('accepts hosts, wildcards and host:port, and treats allow-all as no policy', () => {
8
+ expect(validateNetworkPolicy(undefined)).toBeUndefined();
9
+ expect(validateNetworkPolicy({ internet: 'allow' })).toBeUndefined();
10
+ const p = { internet: 'deny' as const, allow: ['api.anthropic.com', '*.npmjs.org', 'db.internal:5432', 'Host.IO'] };
11
+ expect(validateNetworkPolicy(p)).toBe(p);
12
+ expect(validateNetworkPolicy({ internet: 'deny' })).toBeDefined();
13
+ });
14
+
15
+ it('rejects what the daemon would reject, before launching anything', () => {
16
+ expect(() => validateNetworkPolicy({ internet: 'maybe' as 'allow' })).toThrow(/must be 'allow' or 'deny'/);
17
+ expect(() => validateNetworkPolicy({ internet: 'allow', allow: ['x.com'] })).toThrow(/needs network.internet: 'deny'/);
18
+ for (const bad of ['https://x.com', '*', 'a.*.com', 'x.com:99999', 'x.com/path', '', 'x com']) {
19
+ expect(() => validateNetworkPolicy({ internet: 'deny', allow: [bad] }), bad).toThrow(/bad network.allow entry/);
20
+ }
21
+ });
22
+ });
23
+
24
+ function fakeProvider(health: Record<string, unknown>, configure: Record<string, unknown> | Error) {
25
+ const calls: string[] = [];
26
+ const fetchStub: typeof fetch = async (input, init) => {
27
+ const path = new URL(String(input)).pathname;
28
+ calls.push(`${init?.method ?? 'GET'} ${path}`);
29
+ if (path === '/health') return new Response(JSON.stringify({ ok: true, ...health }), { status: 200 });
30
+ if (configure instanceof Error) return new Response(JSON.stringify({ error: configure.message }), { status: 400 });
31
+ return new Response(JSON.stringify(configure), { status: 200 });
32
+ };
33
+ const handle: CapsuleHandle = {
34
+ id: 'c1',
35
+ provider: 'fake',
36
+ state: 'running',
37
+ template: 't',
38
+ createdAt: new Date(),
39
+ connection: { baseUrl: 'http://capsule', headers: async () => ({}) },
40
+ };
41
+ const provider: Provider = {
42
+ name: 'fake',
43
+ async create() {
44
+ calls.push('create');
45
+ return handle;
46
+ },
47
+ async get() {
48
+ return null;
49
+ },
50
+ async list() {
51
+ return [];
52
+ },
53
+ async terminate(id) {
54
+ calls.push(`terminate ${id}`);
55
+ },
56
+ async connect() {
57
+ return handle.connection;
58
+ },
59
+ };
60
+ return { provider, calls, fetch: fetchStub };
61
+ }
62
+
63
+ describe('Capsule.create with a network policy', () => {
64
+ const spec = { template: 't', network: { internet: 'deny' as const, allow: ['api.anthropic.com'] } };
65
+
66
+ it('is satisfied when the boot hook already enforced it', async () => {
67
+ const { provider, calls, fetch } = fakeProvider({ configured: true, network: { internet: 'deny', enforced: true, blocked: 0 } }, {});
68
+ const capsule = await Capsule.create(provider, spec, { fetch });
69
+ expect(capsule.id).toBe('c1');
70
+ expect(calls).toEqual(['create', 'GET /health']);
71
+ });
72
+
73
+ it('hands the policy over through /configure when the hook did not apply it', async () => {
74
+ const { provider, calls, fetch } = fakeProvider(
75
+ { configured: false },
76
+ { ok: true, mounts: [], network: { internet: 'deny', enforced: true, blocked: 0 } },
77
+ );
78
+ await Capsule.create(provider, spec, { fetch });
79
+ expect(calls).toEqual(['create', 'GET /health', 'POST /configure']);
80
+ });
81
+
82
+ it('terminates the capsule and says why when the policy cannot be enforced', async () => {
83
+ const { provider, calls, fetch } = fakeProvider(
84
+ { configured: true, network: { internet: 'deny', enforced: false, blocked: 0, error: 'network policy needs CAP_NET_ADMIN' } },
85
+ new Error('network policy needs CAP_NET_ADMIN: build the template with --capabilities all'),
86
+ );
87
+ const err = (await Capsule.create(provider, spec, { fetch }).catch((e: unknown) => e)) as Error & { capsuleId?: string };
88
+ expect(err.message).toMatch(/CAP_NET_ADMIN/);
89
+ expect(err.message).toMatch(/capsule c1 terminated/);
90
+ expect(err.capsuleId).toBe('c1');
91
+ expect(calls.at(-1)).toBe('terminate c1');
92
+ });
93
+
94
+ it('rejects a bad policy before creating anything', async () => {
95
+ const { provider, calls, fetch } = fakeProvider({}, {});
96
+ await expect(Capsule.create(provider, { template: 't', network: { internet: 'deny', allow: ['*'] } }, { fetch })).rejects.toThrow(
97
+ /bad network.allow entry/,
98
+ );
99
+ expect(calls).toEqual([]);
100
+ });
101
+ });
package/src/network.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { CapsuleError, type NetworkPolicy } from './types.js';
2
+
3
+ /**
4
+ * Check a network policy before a capsule is created with it (the daemon
5
+ * applies the same rules; failing here saves a launch). Returns the policy
6
+ * when it restricts something, undefined when it does not.
7
+ */
8
+ export function validateNetworkPolicy(policy: NetworkPolicy | undefined): NetworkPolicy | undefined {
9
+ if (!policy) return undefined;
10
+ if (policy.internet !== 'allow' && policy.internet !== 'deny') {
11
+ throw new CapsuleError(`network.internet must be 'allow' or 'deny', got ${JSON.stringify(policy.internet)}`);
12
+ }
13
+ if (policy.internet === 'allow') {
14
+ if (policy.allow?.length) throw new CapsuleError("network.allow needs network.internet: 'deny'");
15
+ return undefined;
16
+ }
17
+ for (const entry of policy.allow ?? []) {
18
+ if (!isAllowEntry(entry)) {
19
+ throw new CapsuleError(`bad network.allow entry ${JSON.stringify(entry)} (want host, *.domain or host:port)`);
20
+ }
21
+ }
22
+ return policy;
23
+ }
24
+
25
+ const HOST = /^(\*\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
26
+
27
+ function isAllowEntry(entry: string): boolean {
28
+ if (typeof entry !== 'string') return false;
29
+ const m = /^(.*?)(?::(\d{1,5}))?$/.exec(entry.trim());
30
+ if (!m) return false;
31
+ const [, host, port] = m;
32
+ if (port !== undefined && (Number(port) < 1 || Number(port) > 65535)) return false;
33
+ return host !== undefined && HOST.test(host);
34
+ }
package/src/types.ts CHANGED
@@ -105,6 +105,7 @@ export interface Health {
105
105
  /** True once the mount table was applied (by the boot hook or /configure). */
106
106
  configured: boolean;
107
107
  mounts?: MountResult[];
108
+ network?: NetworkStatus;
108
109
  /** The template's long-running process (CAPSULOD_START), when the template declares one. */
109
110
  service?: ServiceStatus;
110
111
  }
@@ -118,6 +119,35 @@ export interface ServiceStatus {
118
119
  startedAt?: string;
119
120
  }
120
121
 
122
+ /**
123
+ * What the capsule may reach. With `internet: 'deny'` the daemon runs an
124
+ * egress proxy limited to `allow` (HTTP_PROXY/HTTPS_PROXY point at it for
125
+ * every process) and blackholes the default route, so a process that ignores
126
+ * the proxy gets "network unreachable" rather than the internet. Needs
127
+ * CAP_NET_ADMIN in the capsule: Lambda templates built with
128
+ * `--capabilities all`; the Docker provider adds it. Creation fails if the
129
+ * policy cannot be enforced.
130
+ */
131
+ export interface NetworkPolicy {
132
+ /** 'allow' (default): unrestricted. 'deny': nothing leaves except `allow`. */
133
+ internet: 'allow' | 'deny';
134
+ /** Destinations still reachable with 'deny': 'host', '*.domain' (subdomains only) or 'host:port'. */
135
+ allow?: string[];
136
+ }
137
+
138
+ /** The daemon's view of the policy (`health().network`; absent without a policy). */
139
+ export interface NetworkStatus {
140
+ internet: 'allow' | 'deny';
141
+ allow?: string[];
142
+ /** True once the proxy runs and the routes are locked. */
143
+ enforced: boolean;
144
+ /** The egress proxy's address inside the capsule (127.0.0.1:3128). */
145
+ proxy?: string;
146
+ /** Connections refused so far. */
147
+ blocked: number;
148
+ error?: string;
149
+ }
150
+
121
151
  export interface IdlePolicy {
122
152
  /** Suspend after this long without traffic (seconds). */
123
153
  suspendAfterSeconds: number;
@@ -134,6 +164,8 @@ export interface CapsuleSpec {
134
164
  mounts?: Record<string, MountSpec>;
135
165
  /** Opaque per-capsule configuration delivered to the daemon at boot (never secrets). */
136
166
  metadata?: Record<string, string>;
167
+ /** Egress policy, enforced inside the capsule by the daemon (default: unrestricted). */
168
+ network?: NetworkPolicy;
137
169
  /** Idempotency key: creating twice with the same key returns the same capsule. */
138
170
  clientToken?: string;
139
171
  }