capgate 0.0.1 → 0.0.2

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/cli.js CHANGED
@@ -10,7 +10,7 @@
10
10
  // This is deliberately minimal. Anything fancier (watch mode, multi-target,
11
11
  // YAML output) belongs behind a feature flag, not here.
12
12
  import { readFileSync } from 'node:fs';
13
- import { compile, lowerToBwrap, CompilationError } from './policy/index.js';
13
+ import { compile, lowerToBwrap, lowerToDocker, CompilationError } from './policy/index.js';
14
14
  function parseArgs(argv) {
15
15
  const args = {
16
16
  command: undefined,
@@ -35,19 +35,19 @@ function parseArgs(argv) {
35
35
  }
36
36
  return args;
37
37
  }
38
- const USAGE = `capgate — compile MCP manifests into sandbox policies
39
-
40
- Usage:
41
- capgate compile <manifest.json|-> [--target bwrap] [--pretty]
42
-
43
- Options:
44
- --target <name> Adapter to lower to. Default: bwrap. Supported: bwrap.
45
- --pretty Indent JSON output with 2 spaces.
46
- -h, --help Show this message.
47
-
48
- Examples:
49
- capgate compile manifests/filesystem.json --pretty
50
- cat manifest.json | capgate compile - --target bwrap
38
+ const USAGE = `capgate — compile MCP manifests into sandbox policies
39
+
40
+ Usage:
41
+ capgate compile <manifest.json|-> [--target bwrap] [--pretty]
42
+
43
+ Options:
44
+ --target <name> Adapter to lower to. Default: bwrap. Supported: bwrap, docker.
45
+ --pretty Indent JSON output with 2 spaces.
46
+ -h, --help Show this message.
47
+
48
+ Examples:
49
+ capgate compile manifests/filesystem.json --pretty
50
+ cat manifest.json | capgate compile - --target bwrap
51
51
  `;
52
52
  function readInput(path) {
53
53
  if (path === '-')
@@ -83,8 +83,11 @@ function main() {
83
83
  case 'bwrap':
84
84
  output = lowerToBwrap(policy);
85
85
  break;
86
+ case 'docker':
87
+ output = lowerToDocker(policy);
88
+ break;
86
89
  default:
87
- process.stderr.write(`capgate: unsupported --target "${args.target}" (supported: bwrap)\n`);
90
+ process.stderr.write(`capgate: unsupported --target "${args.target}" (supported: bwrap, docker)\n`);
88
91
  process.exit(2);
89
92
  }
90
93
  const indent = args.pretty ? 2 : 0;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { NormalizedPolicy } from '../ir.js';
2
+ import type { EgressRule } from './bwrap.js';
3
+ export interface DockerArtifact {
4
+ /** argv, ready for execFile("docker", ["run", ...argv, image, ...cmd]). */
5
+ argv: string[];
6
+ /** Network egress rules. Empty = no net allowed (host SHOULD use --network none). */
7
+ egress: EgressRule[];
8
+ /** Env vars the host must inject (names only; values resolved out-of-band). */
9
+ envInjections: string[];
10
+ /** Declared assertions — emitted as metadata, not enforced here. */
11
+ assertions: {
12
+ id: string;
13
+ description: string;
14
+ }[];
15
+ /** Human-readable diagnostics for audit logs / PR review. */
16
+ notes: string[];
17
+ }
18
+ export interface DockerOptions {
19
+ /**
20
+ * Whether to emit `--read-only` on the root filesystem. Default true.
21
+ * Disable only if your image cannot run with a read-only rootfs (rare).
22
+ */
23
+ readOnlyRootfs?: boolean;
24
+ /**
25
+ * Optional user to run as inside the container, e.g. "1000:1000". Default
26
+ * unset (image-defined). Recommended in production; left unset here so the
27
+ * adapter's output is portable across images.
28
+ */
29
+ user?: string;
30
+ }
31
+ export declare function lowerToDocker(policy: NormalizedPolicy, opts?: DockerOptions): DockerArtifact;
32
+ //# sourceMappingURL=docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../src/policy/adapters/docker.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qFAAqF;IACrF,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,GAAE,aAAkB,GAAG,cAAc,CA+GhG"}
@@ -0,0 +1,143 @@
1
+ // Docker adapter: NormalizedPolicy → `docker run` argv + companion artifacts.
2
+ //
3
+ // Scope parallel to bwrap: emit flags, not images or commands. The host
4
+ // appends the image reference and entrypoint args. The host also chooses
5
+ // which network to attach to (or none) — this adapter only signals that an
6
+ // egress-aware network is required when policy.net is non-empty.
7
+ //
8
+ // What Docker handles natively:
9
+ // - filesystem bind mounts (--volume :ro / :rw)
10
+ // - network isolation (--network none)
11
+ // - env injection (--env)
12
+ // - capability scrub (--cap-drop=ALL, --security-opt=no-new-privileges)
13
+ //
14
+ // What Docker does NOT handle here:
15
+ // - host-level egress allowlisting → EgressRule[] (companion proxy)
16
+ // - seccomp customization beyond default → out of scope for v0.1
17
+ // - secret value resolution → caller pulls from a secret store
18
+ // - inner Chromium-style sandboxes → surfaced as a note; host decides whether
19
+ // to add SYS_ADMIN with a tailored seccomp profile or use a microVM adapter.
20
+ // This adapter refuses to silently elevate.
21
+ const SAFE_DEFAULTS = {
22
+ readOnlyRootfs: true,
23
+ };
24
+ export function lowerToDocker(policy, opts = {}) {
25
+ const argv = [];
26
+ const notes = [];
27
+ const readOnlyRootfs = opts.readOnlyRootfs ?? SAFE_DEFAULTS.readOnlyRootfs;
28
+ // ---------- baseline hardening ----------
29
+ argv.push('--rm');
30
+ argv.push('--cap-drop', 'ALL');
31
+ argv.push('--security-opt', 'no-new-privileges');
32
+ if (readOnlyRootfs)
33
+ argv.push('--read-only');
34
+ // Tmpfs for /tmp unless a declared fs root covers it (mirror of bwrap logic).
35
+ const tmpCovered = policy.fs.some((fs) => {
36
+ const host = dirForBind(fs.path);
37
+ return host === '/tmp' || host.startsWith('/tmp/');
38
+ });
39
+ if (!tmpCovered)
40
+ argv.push('--tmpfs', '/tmp');
41
+ if (opts.user)
42
+ argv.push('--user', opts.user);
43
+ // ---------- network ----------
44
+ // bwrap is binary-share. Docker has the same shape: --network none vs
45
+ // attach-to-an-egress-aware-network. We emit the deny case directly and
46
+ // signal the allow case via a note — choosing the network name is host policy.
47
+ if (policy.net.length === 0) {
48
+ argv.push('--network', 'none');
49
+ }
50
+ else {
51
+ notes.push(`net: ${policy.net.length} endpoint(s) declared — host MUST attach the container to a network whose egress honors egress[]; do NOT use --network host`);
52
+ }
53
+ // ---------- fs binds ----------
54
+ for (const fs of policy.fs) {
55
+ const hostPath = dirForBind(fs.path);
56
+ const writable = fs.actions.includes('write') || fs.actions.includes('create') || fs.actions.includes('delete');
57
+ argv.push('--volume', `${hostPath}:${hostPath}:${writable ? 'rw' : 'ro'}`);
58
+ if (fs.isGlob) {
59
+ notes.push(`fs: "${fs.path}" lowered to volume mount "${hostPath}" — Docker mounts directories, not globs. Fine-grained glob enforcement is the server's job.`);
60
+ }
61
+ if (hostPath === '/tmp') {
62
+ notes.push('fs: mounting host /tmp exposes all user tmpfiles to the container; prefer a scoped subdirectory like /tmp/<server-name>.');
63
+ }
64
+ }
65
+ // ---------- clock ----------
66
+ if (policy.clock === 'tzdata') {
67
+ argv.push('--volume', '/usr/share/zoneinfo:/usr/share/zoneinfo:ro');
68
+ argv.push('--volume', '/etc/localtime:/etc/localtime:ro');
69
+ }
70
+ // ---------- exec binaries ----------
71
+ // No mounts to add — the image is responsible for shipping the binary.
72
+ // We surface the declaration so a reviewer can verify the image actually
73
+ // contains it (catches image/manifest drift).
74
+ for (const e of policy.exec) {
75
+ notes.push(`exec: ${e.binary} (must be present in the chosen image)`);
76
+ }
77
+ // ---------- env (declared first so ipc handlers can push injections) ----------
78
+ const envInjections = [];
79
+ for (const e of policy.env)
80
+ envInjections.push(e.name);
81
+ // ---------- ipc ----------
82
+ for (const i of policy.ipc) {
83
+ if (i.endpoint === 'x11') {
84
+ argv.push('--volume', '/tmp/.X11-unix:/tmp/.X11-unix:ro');
85
+ envInjections.push('DISPLAY');
86
+ }
87
+ else if (i.endpoint.startsWith('unix:')) {
88
+ const sock = i.endpoint.slice('unix:'.length);
89
+ argv.push('--volume', `${sock}:${sock}`);
90
+ }
91
+ else if (i.endpoint === 'dbus:session') {
92
+ notes.push('ipc: dbus:session declared — host must mount DBUS_SESSION_BUS_ADDRESS socket');
93
+ }
94
+ else if (i.endpoint === 'dbus:system') {
95
+ argv.push('--volume', '/run/dbus/system_bus_socket:/run/dbus/system_bus_socket');
96
+ }
97
+ else {
98
+ notes.push(`ipc: unrecognized endpoint "${i.endpoint}" — no mount emitted`);
99
+ }
100
+ }
101
+ // ---------- nestedSandbox ----------
102
+ // Chromium and friends fight container isolation similarly to namespaces.
103
+ // We surface the conflict explicitly rather than auto-adding SYS_ADMIN or
104
+ // --privileged. The host knows whether it's running a trusted image.
105
+ if (policy.nestedSandbox) {
106
+ notes.push('nestedSandbox: declared — Docker default seccomp + dropped capabilities may break inner sandboxes (e.g. Chromium). Host MUST decide between (a) granting SYS_ADMIN + a tailored seccomp profile, or (b) using a microVM adapter (Firecracker) instead. capgate refuses to choose for you.');
107
+ }
108
+ // ---------- env injections (emit names; values are caller's job) ----------
109
+ for (const name of envInjections) {
110
+ argv.push('--env', name);
111
+ }
112
+ // ---------- egress ----------
113
+ const egress = policy.net.map((n) => ({
114
+ host: n.host,
115
+ port: n.port,
116
+ blockPrivate: n.blockPrivate,
117
+ }));
118
+ return {
119
+ argv,
120
+ egress,
121
+ envInjections,
122
+ assertions: policy.assertions.map((a) => ({ id: a.id, description: a.description })),
123
+ notes,
124
+ };
125
+ }
126
+ /**
127
+ * Return the directory portion Docker should bind. Mirrors bwrap's logic
128
+ * exactly so the two adapters agree on host-path scope. Kept duplicated (not
129
+ * shared) intentionally: if one adapter ever needs different glob semantics,
130
+ * we want that divergence to be a deliberate edit, not a shared-helper surprise.
131
+ */
132
+ function dirForBind(path) {
133
+ const stripped = path.replace(/\/\*\*?$/, '').replace(/\/\*$/, '');
134
+ if (stripped.endsWith('/'))
135
+ return stripped.slice(0, -1) || '/';
136
+ const lastSlash = stripped.lastIndexOf('/');
137
+ const tail = stripped.slice(lastSlash + 1);
138
+ if (tail.includes('.') && !tail.startsWith('.')) {
139
+ return stripped.slice(0, lastSlash) || '/';
140
+ }
141
+ return stripped || '/';
142
+ }
143
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../../../src/policy/adapters/docker.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,6 @@ export { compile, parseManifest, normalize } from './compiler.js';
6
6
  export type { RawServerManifest, RawToolManifest } from './compiler.js';
7
7
  export { lowerToBwrap } from './adapters/bwrap.js';
8
8
  export type { BwrapArtifact, BwrapOptions, EgressRule } from './adapters/bwrap.js';
9
+ export { lowerToDocker } from './adapters/docker.js';
10
+ export type { DockerArtifact, DockerOptions } from './adapters/docker.js';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
@@ -4,4 +4,5 @@ export { CompilationError, isEnforceable } from './ir.js';
4
4
  export { parseCapability, GRAMMAR_VERSION } from './grammar.js';
5
5
  export { compile, parseManifest, normalize } from './compiler.js';
6
6
  export { lowerToBwrap } from './adapters/bwrap.js';
7
+ export { lowerToDocker } from './adapters/docker.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+BAA+B;AAsB/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+BAA+B;AAsB/B,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,64 +1,65 @@
1
- {
2
- "name": "capgate",
3
- "version": "0.0.1",
4
- "description": "Compile MCP tool manifests into sandbox policies (bwrap, egress rules, and more).",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "bin": {
9
- "capgate": "dist/cli.js"
10
- },
11
- "exports": {
12
- ".": {
13
- "types": "./dist/index.d.ts",
14
- "import": "./dist/index.js",
15
- "default": "./dist/index.js"
16
- }
17
- },
18
- "files": [
19
- "dist/",
20
- "LICENSE",
21
- "README.md"
22
- ],
23
- "scripts": {
24
- "build": "tsc",
25
- "clean": "node -e \"import('node:fs').then(fs => fs.rmSync('dist', { recursive: true, force: true }))\"",
26
- "prebuild": "npm run clean",
27
- "test": "vitest run",
28
- "test:watch": "vitest",
29
- "test:update-goldens": "cross-env UPDATE_GOLDEN=1 vitest run",
30
- "prepublishOnly": "npm run build && npm test"
31
- },
32
- "keywords": [
33
- "mcp",
34
- "model-context-protocol",
35
- "policy",
36
- "sandbox",
37
- "capability",
38
- "bwrap",
39
- "bubblewrap",
40
- "typescript"
41
- ],
42
- "author": {
43
- "name": "Raju KC",
44
- "email": "kc.razu@gmail.com"
45
- },
46
- "repository": {
47
- "type": "git",
48
- "url": "git+https://github.com/razukc/capgate.git"
49
- },
50
- "homepage": "https://github.com/razukc/capgate#readme",
51
- "bugs": {
52
- "url": "https://github.com/razukc/capgate/issues"
53
- },
54
- "license": "MIT",
55
- "engines": {
56
- "node": ">=18.0.0"
57
- },
58
- "devDependencies": {
59
- "@types/node": "^20.10.0",
60
- "cross-env": "^10.1.0",
61
- "typescript": "^5.3.3",
62
- "vitest": "^3.2.4"
63
- }
1
+ {
2
+ "name": "capgate",
3
+ "version": "0.0.2",
4
+ "description": "Compile MCP tool manifests into sandbox policies (bwrap, egress rules, and more).",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "capgate": "dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist/",
20
+ "LICENSE",
21
+ "NOTICE",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "clean": "node -e \"import('node:fs').then(fs => fs.rmSync('dist', { recursive: true, force: true }))\"",
27
+ "prebuild": "npm run clean",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:update-goldens": "cross-env UPDATE_GOLDEN=1 vitest run",
31
+ "prepublishOnly": "npm run build && npm test"
32
+ },
33
+ "keywords": [
34
+ "mcp",
35
+ "model-context-protocol",
36
+ "policy",
37
+ "sandbox",
38
+ "capability",
39
+ "bwrap",
40
+ "bubblewrap",
41
+ "typescript"
42
+ ],
43
+ "author": {
44
+ "name": "Raju KC",
45
+ "email": "kc.razu@gmail.com"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/razukc/capgate.git"
50
+ },
51
+ "homepage": "https://github.com/razukc/capgate#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/razukc/capgate/issues"
54
+ },
55
+ "license": "Apache-2.0",
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^20.10.0",
61
+ "cross-env": "^10.1.0",
62
+ "typescript": "^5.3.3",
63
+ "vitest": "^3.2.4"
64
+ }
64
65
  }