mrplex 0.0.1
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/LICENSE +21 -0
- package/README.md +284 -0
- package/dist/cli/config.d.ts +28 -0
- package/dist/cli/config.js +48 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +13 -0
- package/dist/cli/exit-codes.js +39 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/format.d.ts +22 -0
- package/dist/cli/format.js +148 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/main.d.ts +16 -0
- package/dist/cli/main.js +1518 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/client/kernel-client.d.ts +97 -0
- package/dist/client/kernel-client.js +14 -0
- package/dist/client/kernel-client.js.map +1 -0
- package/dist/client/local.d.ts +26 -0
- package/dist/client/local.js +103 -0
- package/dist/client/local.js.map +1 -0
- package/dist/client/remote-mcp.d.ts +35 -0
- package/dist/client/remote-mcp.js +174 -0
- package/dist/client/remote-mcp.js.map +1 -0
- package/dist/embed/backfill.d.ts +24 -0
- package/dist/embed/backfill.js +33 -0
- package/dist/embed/backfill.js.map +1 -0
- package/dist/embed/chunker.d.ts +31 -0
- package/dist/embed/chunker.js +121 -0
- package/dist/embed/chunker.js.map +1 -0
- package/dist/embed/cmd-hook.d.ts +21 -0
- package/dist/embed/cmd-hook.js +100 -0
- package/dist/embed/cmd-hook.js.map +1 -0
- package/dist/embed/config.d.ts +61 -0
- package/dist/embed/config.js +109 -0
- package/dist/embed/config.js.map +1 -0
- package/dist/embed/hook.d.ts +38 -0
- package/dist/embed/hook.js +56 -0
- package/dist/embed/hook.js.map +1 -0
- package/dist/embed/http-hook.d.ts +13 -0
- package/dist/embed/http-hook.js +39 -0
- package/dist/embed/http-hook.js.map +1 -0
- package/dist/embed/worker.d.ts +62 -0
- package/dist/embed/worker.js +228 -0
- package/dist/embed/worker.js.map +1 -0
- package/dist/fixtures/hwe/characters/albion-ever.md +12 -0
- package/dist/fixtures/hwe/characters/cent.md +11 -0
- package/dist/fixtures/hwe/concepts/cent-demiurge-resonance.md +10 -0
- package/dist/fixtures/hwe/concepts/phase-looper.md +10 -0
- package/dist/fixtures/hwe/entities/demiurge.md +11 -0
- package/dist/fixtures/hwe/entities/monad.md +11 -0
- package/dist/fixtures/hwe/moc/globocorp-network.md +19 -0
- package/dist/fixtures/hwe/organizations/globocorp.md +11 -0
- package/dist/fixtures/hwe/readme.md +24 -0
- package/dist/fixtures/starship/crew/aria-okonkwo.md +14 -0
- package/dist/fixtures/starship/crew/bexley-orr.md +14 -0
- package/dist/fixtures/starship/crew/dax-thorne.md +14 -0
- package/dist/fixtures/starship/crew/isolde-marsh.md +16 -0
- package/dist/fixtures/starship/crew/kestrel-vance.md +15 -0
- package/dist/fixtures/starship/crew/quill-vasquez.md +14 -0
- package/dist/fixtures/starship/crew/soren-halloway.md +16 -0
- package/dist/fixtures/starship/encounters/the-drift-choir.md +14 -0
- package/dist/fixtures/starship/encounters/the-hollow-signal.md +16 -0
- package/dist/fixtures/starship/encounters/the-wandering-buoy.md +14 -0
- package/dist/fixtures/starship/equipment/coolant-loop-b.md +13 -0
- package/dist/fixtures/starship/equipment/emergency-ration-bars.md +12 -0
- package/dist/fixtures/starship/equipment/long-range-sensors.md +13 -0
- package/dist/fixtures/starship/equipment/plasma-manifold-3.md +15 -0
- package/dist/fixtures/starship/equipment/shuttle-corvid.md +13 -0
- package/dist/fixtures/starship/logs/marsh-4419-1.md +13 -0
- package/dist/fixtures/starship/logs/okonkwo-4415-1.md +13 -0
- package/dist/fixtures/starship/logs/orr-4413-1.md +13 -0
- package/dist/fixtures/starship/logs/orr-4420-1.md +12 -0
- package/dist/fixtures/starship/logs/thorne-4413-2.md +13 -0
- package/dist/fixtures/starship/logs/vance-4419-2.md +13 -0
- package/dist/fixtures/starship/misc/the-galley-ficus.md +11 -0
- package/dist/fixtures/starship/missions/the-cinder-run.md +17 -0
- package/dist/fixtures/starship/missions/the-drift-choir.md +17 -0
- package/dist/fixtures/starship/missions/the-hollow-signal.md +17 -0
- package/dist/fixtures/starship/missions/the-silent-beacon.md +17 -0
- package/dist/fixtures/starship/moc/crew.md +19 -0
- package/dist/fixtures/starship/moc/encounters.md +14 -0
- package/dist/fixtures/starship/moc/missions.md +15 -0
- package/dist/fixtures/starship/readme.md +60 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/auth/glob.d.ts +46 -0
- package/dist/kernel/auth/glob.js +112 -0
- package/dist/kernel/auth/glob.js.map +1 -0
- package/dist/kernel/auth/scope.d.ts +53 -0
- package/dist/kernel/auth/scope.js +83 -0
- package/dist/kernel/auth/scope.js.map +1 -0
- package/dist/kernel/casefold.d.ts +37 -0
- package/dist/kernel/casefold.js +44 -0
- package/dist/kernel/casefold.js.map +1 -0
- package/dist/kernel/constants.d.ts +21 -0
- package/dist/kernel/constants.js +22 -0
- package/dist/kernel/constants.js.map +1 -0
- package/dist/kernel/context.d.ts +70 -0
- package/dist/kernel/context.js +114 -0
- package/dist/kernel/context.js.map +1 -0
- package/dist/kernel/deletion.d.ts +50 -0
- package/dist/kernel/deletion.js +83 -0
- package/dist/kernel/deletion.js.map +1 -0
- package/dist/kernel/diff.d.ts +36 -0
- package/dist/kernel/diff.js +61 -0
- package/dist/kernel/diff.js.map +1 -0
- package/dist/kernel/errors.d.ts +37 -0
- package/dist/kernel/errors.js +55 -0
- package/dist/kernel/errors.js.map +1 -0
- package/dist/kernel/frontmatter-input.d.ts +32 -0
- package/dist/kernel/frontmatter-input.js +85 -0
- package/dist/kernel/frontmatter-input.js.map +1 -0
- package/dist/kernel/graph.d.ts +34 -0
- package/dist/kernel/graph.js +559 -0
- package/dist/kernel/graph.js.map +1 -0
- package/dist/kernel/history.d.ts +74 -0
- package/dist/kernel/history.js +143 -0
- package/dist/kernel/history.js.map +1 -0
- package/dist/kernel/kernel.d.ts +162 -0
- package/dist/kernel/kernel.js +675 -0
- package/dist/kernel/kernel.js.map +1 -0
- package/dist/kernel/path-config.d.ts +101 -0
- package/dist/kernel/path-config.js +171 -0
- package/dist/kernel/path-config.js.map +1 -0
- package/dist/kernel/query/ast.d.ts +24 -0
- package/dist/kernel/query/ast.js +52 -0
- package/dist/kernel/query/ast.js.map +1 -0
- package/dist/kernel/query/cel-parse.d.ts +37 -0
- package/dist/kernel/query/cel-parse.js +88 -0
- package/dist/kernel/query/cel-parse.js.map +1 -0
- package/dist/kernel/query/degrees.d.ts +31 -0
- package/dist/kernel/query/degrees.js +135 -0
- package/dist/kernel/query/degrees.js.map +1 -0
- package/dist/kernel/query/graph-ast.d.ts +51 -0
- package/dist/kernel/query/graph-ast.js +139 -0
- package/dist/kernel/query/graph-ast.js.map +1 -0
- package/dist/kernel/query/query.d.ts +56 -0
- package/dist/kernel/query/query.js +276 -0
- package/dist/kernel/query/query.js.map +1 -0
- package/dist/kernel/validation.d.ts +64 -0
- package/dist/kernel/validation.js +183 -0
- package/dist/kernel/validation.js.map +1 -0
- package/dist/kernel/version-id.d.ts +10 -0
- package/dist/kernel/version-id.js +21 -0
- package/dist/kernel/version-id.js.map +1 -0
- package/dist/kernel/wire.d.ts +148 -0
- package/dist/kernel/wire.js +6 -0
- package/dist/kernel/wire.js.map +1 -0
- package/dist/links/backfill.d.ts +28 -0
- package/dist/links/backfill.js +33 -0
- package/dist/links/backfill.js.map +1 -0
- package/dist/links/extract.d.ts +29 -0
- package/dist/links/extract.js +233 -0
- package/dist/links/extract.js.map +1 -0
- package/dist/links/link-config.d.ts +70 -0
- package/dist/links/link-config.js +107 -0
- package/dist/links/link-config.js.map +1 -0
- package/dist/links/maintain.d.ts +37 -0
- package/dist/links/maintain.js +91 -0
- package/dist/links/maintain.js.map +1 -0
- package/dist/links/repair.d.ts +46 -0
- package/dist/links/repair.js +96 -0
- package/dist/links/repair.js.map +1 -0
- package/dist/links/resolve.d.ts +41 -0
- package/dist/links/resolve.js +121 -0
- package/dist/links/resolve.js.map +1 -0
- package/dist/links/stale.d.ts +32 -0
- package/dist/links/stale.js +73 -0
- package/dist/links/stale.js.map +1 -0
- package/dist/markdown/content-hash.d.ts +34 -0
- package/dist/markdown/content-hash.js +46 -0
- package/dist/markdown/content-hash.js.map +1 -0
- package/dist/markdown/frontmatter.d.ts +69 -0
- package/dist/markdown/frontmatter.js +147 -0
- package/dist/markdown/frontmatter.js.map +1 -0
- package/dist/markdown/hash-backfill.d.ts +22 -0
- package/dist/markdown/hash-backfill.js +43 -0
- package/dist/markdown/hash-backfill.js.map +1 -0
- package/dist/mcp/query-syntax.d.ts +20 -0
- package/dist/mcp/query-syntax.js +194 -0
- package/dist/mcp/query-syntax.js.map +1 -0
- package/dist/mcp/render.d.ts +31 -0
- package/dist/mcp/render.js +110 -0
- package/dist/mcp/render.js.map +1 -0
- package/dist/mcp/server.d.ts +60 -0
- package/dist/mcp/server.js +170 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +93 -0
- package/dist/mcp/tools.js +1218 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/rest/conditional.d.ts +37 -0
- package/dist/rest/conditional.js +58 -0
- package/dist/rest/conditional.js.map +1 -0
- package/dist/rest/negotiate.d.ts +33 -0
- package/dist/rest/negotiate.js +54 -0
- package/dist/rest/negotiate.js.map +1 -0
- package/dist/rest/routes.d.ts +37 -0
- package/dist/rest/routes.js +744 -0
- package/dist/rest/routes.js.map +1 -0
- package/dist/seed/fixture-seed.d.ts +35 -0
- package/dist/seed/fixture-seed.js +75 -0
- package/dist/seed/fixture-seed.js.map +1 -0
- package/dist/seed/starship-config.d.ts +3 -0
- package/dist/seed/starship-config.js +5 -0
- package/dist/seed/starship-config.js.map +1 -0
- package/dist/server/headers.d.ts +36 -0
- package/dist/server/headers.js +30 -0
- package/dist/server/headers.js.map +1 -0
- package/dist/server/http-error.d.ts +53 -0
- package/dist/server/http-error.js +104 -0
- package/dist/server/http-error.js.map +1 -0
- package/dist/server/serve.d.ts +56 -0
- package/dist/server/serve.js +135 -0
- package/dist/server/serve.js.map +1 -0
- package/dist/shell/audit.d.ts +32 -0
- package/dist/shell/audit.js +28 -0
- package/dist/shell/audit.js.map +1 -0
- package/dist/shell/guard.d.ts +50 -0
- package/dist/shell/guard.js +176 -0
- package/dist/shell/guard.js.map +1 -0
- package/dist/shell/keys.d.ts +36 -0
- package/dist/shell/keys.js +64 -0
- package/dist/shell/keys.js.map +1 -0
- package/dist/shell/login.d.ts +56 -0
- package/dist/shell/login.js +130 -0
- package/dist/shell/login.js.map +1 -0
- package/dist/shell/oidc.d.ts +62 -0
- package/dist/shell/oidc.js +102 -0
- package/dist/shell/oidc.js.map +1 -0
- package/dist/shell/policy.d.ts +100 -0
- package/dist/shell/policy.js +232 -0
- package/dist/shell/policy.js.map +1 -0
- package/dist/shell/proxy-policy.d.ts +34 -0
- package/dist/shell/proxy-policy.js +120 -0
- package/dist/shell/proxy-policy.js.map +1 -0
- package/dist/shell/proxy.d.ts +47 -0
- package/dist/shell/proxy.js +253 -0
- package/dist/shell/proxy.js.map +1 -0
- package/dist/shell/serve.d.ts +86 -0
- package/dist/shell/serve.js +0 -0
- package/dist/shell/serve.js.map +1 -0
- package/dist/shell/stdio.d.ts +55 -0
- package/dist/shell/stdio.js +63 -0
- package/dist/shell/stdio.js.map +1 -0
- package/dist/storage/registry.d.ts +20 -0
- package/dist/storage/registry.js +38 -0
- package/dist/storage/registry.js.map +1 -0
- package/dist/storage/search-plan.d.ts +93 -0
- package/dist/storage/search-plan.js +15 -0
- package/dist/storage/search-plan.js.map +1 -0
- package/dist/storage/types.d.ts +448 -0
- package/dist/storage/types.js +14 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/versions-since.d.ts +72 -0
- package/dist/storage/versions-since.js +92 -0
- package/dist/storage/versions-since.js.map +1 -0
- package/dist/storage-postgres/adapter.d.ts +17 -0
- package/dist/storage-postgres/adapter.js +782 -0
- package/dist/storage-postgres/adapter.js.map +1 -0
- package/dist/storage-postgres/compile-postgres.d.ts +22 -0
- package/dist/storage-postgres/compile-postgres.js +830 -0
- package/dist/storage-postgres/compile-postgres.js.map +1 -0
- package/dist/storage-postgres/errors.d.ts +34 -0
- package/dist/storage-postgres/errors.js +50 -0
- package/dist/storage-postgres/errors.js.map +1 -0
- package/dist/storage-postgres/migrations/0001_init.sql +113 -0
- package/dist/storage-postgres/migrations/0002_content_hash.sql +7 -0
- package/dist/storage-postgres/migrations/index.d.ts +22 -0
- package/dist/storage-postgres/migrations/index.js +70 -0
- package/dist/storage-postgres/migrations/index.js.map +1 -0
- package/dist/storage-sqlite/adapter.d.ts +2 -0
- package/dist/storage-sqlite/adapter.js +688 -0
- package/dist/storage-sqlite/adapter.js.map +1 -0
- package/dist/storage-sqlite/compile-filter.d.ts +41 -0
- package/dist/storage-sqlite/compile-filter.js +881 -0
- package/dist/storage-sqlite/compile-filter.js.map +1 -0
- package/dist/storage-sqlite/compile-sqlite.d.ts +19 -0
- package/dist/storage-sqlite/compile-sqlite.js +176 -0
- package/dist/storage-sqlite/compile-sqlite.js.map +1 -0
- package/dist/storage-sqlite/migrations/0001_init.sql +123 -0
- package/dist/storage-sqlite/migrations/0002_content_hash.sql +7 -0
- package/dist/storage-sqlite/migrations/index.d.ts +6 -0
- package/dist/storage-sqlite/migrations/index.js +41 -0
- package/dist/storage-sqlite/migrations/index.js.map +1 -0
- package/dist/storage-sqlite/vec.d.ts +40 -0
- package/dist/storage-sqlite/vec.js +62 -0
- package/dist/storage-sqlite/vec.js.map +1 -0
- package/dist/sync/cursor.d.ts +36 -0
- package/dist/sync/cursor.js +66 -0
- package/dist/sync/cursor.js.map +1 -0
- package/dist/sync/daemon.d.ts +40 -0
- package/dist/sync/daemon.js +202 -0
- package/dist/sync/daemon.js.map +1 -0
- package/dist/sync/feed.d.ts +38 -0
- package/dist/sync/feed.js +125 -0
- package/dist/sync/feed.js.map +1 -0
- package/dist/sync/fs-store.d.ts +8 -0
- package/dist/sync/fs-store.js +76 -0
- package/dist/sync/fs-store.js.map +1 -0
- package/dist/sync/intrinsics.d.ts +52 -0
- package/dist/sync/intrinsics.js +76 -0
- package/dist/sync/intrinsics.js.map +1 -0
- package/dist/sync/paths.d.ts +38 -0
- package/dist/sync/paths.js +56 -0
- package/dist/sync/paths.js.map +1 -0
- package/dist/sync/push.d.ts +48 -0
- package/dist/sync/push.js +328 -0
- package/dist/sync/push.js.map +1 -0
- package/dist/sync/reconcile.d.ts +54 -0
- package/dist/sync/reconcile.js +252 -0
- package/dist/sync/reconcile.js.map +1 -0
- package/dist/sync/run.d.ts +27 -0
- package/dist/sync/run.js +46 -0
- package/dist/sync/run.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route-aware REST policy classification for proxy mode — auth-shell plan §1
|
|
3
|
+
* "Serve mode: fronting proxy", WS4.
|
|
4
|
+
*
|
|
5
|
+
* The fronting proxy is mrplex-aware (not a generic reverse proxy): it parses
|
|
6
|
+
* the known REST routes to decide what an entitlement must permit. Crucially,
|
|
7
|
+
* on the REST surface the URL path is *authoritative* for writes — a
|
|
8
|
+
* `PUT /repos/notes/docs/drafts/x.md` names its target path directly, and a
|
|
9
|
+
* MOVE carries source (URL) + destination (`Destination` header). So the proxy
|
|
10
|
+
* can replay the guard's §8.2 rules (both-endpoints on move, sigil paths
|
|
11
|
+
* skipped, write ≠ read) WITHOUT a kernel handle — unlike the opaque MCP tool
|
|
12
|
+
* args, which is why MCP writes stay in embedded mode.
|
|
13
|
+
*
|
|
14
|
+
* This module is pure request classification — no I/O, no forwarding — so it is
|
|
15
|
+
* unit-testable and the proxy transport composes it.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Classify a REST request into its policy requirement. `pathname` is the raw
|
|
19
|
+
* URL path (no query); `destination` is the `Destination` header value, needed
|
|
20
|
+
* for MOVE both-endpoints. Percent-encoded segments are decoded per-segment.
|
|
21
|
+
*/
|
|
22
|
+
export function classifyRestRequest(method, pathname, destination) {
|
|
23
|
+
const segments = splitPath(pathname);
|
|
24
|
+
const m = method.toUpperCase();
|
|
25
|
+
// Root liveness ping, /query.
|
|
26
|
+
if (segments.length === 0)
|
|
27
|
+
return { kind: "read" };
|
|
28
|
+
if (segments[0] === "query")
|
|
29
|
+
return { kind: "read" };
|
|
30
|
+
if (segments[0] !== "repos")
|
|
31
|
+
return { kind: "unknown" };
|
|
32
|
+
// /repos (GET list, POST create)
|
|
33
|
+
if (segments.length === 1) {
|
|
34
|
+
if (m === "GET")
|
|
35
|
+
return { kind: "read" };
|
|
36
|
+
if (m === "POST")
|
|
37
|
+
return { kind: "destructive" }; // repos.create
|
|
38
|
+
return { kind: "unknown" };
|
|
39
|
+
}
|
|
40
|
+
const repo = segments[1];
|
|
41
|
+
// /repos/{repo} (GET, MOVE rename, DELETE)
|
|
42
|
+
if (segments.length === 2) {
|
|
43
|
+
if (m === "GET")
|
|
44
|
+
return { kind: "read" };
|
|
45
|
+
if (m === "MOVE" || m === "DELETE")
|
|
46
|
+
return { kind: "destructive" }; // rename / delete
|
|
47
|
+
return { kind: "unknown" };
|
|
48
|
+
}
|
|
49
|
+
// /repos/{repo}/config (PUT → set_path_config). There is no REST route for
|
|
50
|
+
// set_link_config — it's only reachable via the MCP repos_set_link_config
|
|
51
|
+
// tool, and the proxy refuses /mcp entirely, so no branch for it here.
|
|
52
|
+
if (segments.length === 3 && segments[2] === "config") {
|
|
53
|
+
if (m === "PUT")
|
|
54
|
+
return { kind: "destructive" };
|
|
55
|
+
return { kind: "unknown" };
|
|
56
|
+
}
|
|
57
|
+
// /repos/{repo}/versions | history | diff — all reads
|
|
58
|
+
if (segments.length >= 3 && ["versions", "history", "diff"].includes(segments[2])) {
|
|
59
|
+
return { kind: "read" };
|
|
60
|
+
}
|
|
61
|
+
// /repos/{repo}/docs/{...path}
|
|
62
|
+
if (segments.length >= 4 && segments[2] === "docs") {
|
|
63
|
+
const path = segments.slice(3).join("/");
|
|
64
|
+
if (m === "GET")
|
|
65
|
+
return { kind: "read" };
|
|
66
|
+
if (m === "PUT")
|
|
67
|
+
return { kind: "write", repo, paths: [path] }; // create or update
|
|
68
|
+
if (m === "DELETE")
|
|
69
|
+
return { kind: "write", repo, paths: [path] };
|
|
70
|
+
if (m === "MOVE") {
|
|
71
|
+
// Both endpoints: source (URL path) + destination. A cross-repo or
|
|
72
|
+
// malformed destination is caught downstream by the engine; for policy
|
|
73
|
+
// we require write on both the source and whatever dest we can parse.
|
|
74
|
+
const destPath = parseDocDestinationPath(destination, repo);
|
|
75
|
+
const paths = destPath === null ? [path] : [path, destPath];
|
|
76
|
+
return { kind: "write", repo, paths };
|
|
77
|
+
}
|
|
78
|
+
return { kind: "unknown" };
|
|
79
|
+
}
|
|
80
|
+
return { kind: "unknown" };
|
|
81
|
+
}
|
|
82
|
+
function splitPath(pathname) {
|
|
83
|
+
const raw = pathname.replace(/^\//, "").replace(/\/$/, "");
|
|
84
|
+
if (raw === "")
|
|
85
|
+
return [];
|
|
86
|
+
return raw.split("/").map((s) => {
|
|
87
|
+
try {
|
|
88
|
+
return decodeURIComponent(s);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return s;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Extract the destination document path from a `Destination` header of the form
|
|
97
|
+
* `/repos/{repo}/docs/{...path}` (mirrors the REST surface's own parser). Returns
|
|
98
|
+
* null when absent/unparseable; the engine remains the authority on validity.
|
|
99
|
+
*/
|
|
100
|
+
function parseDocDestinationPath(headerValue, repo) {
|
|
101
|
+
if (headerValue === undefined)
|
|
102
|
+
return null;
|
|
103
|
+
let pathname;
|
|
104
|
+
try {
|
|
105
|
+
pathname = new URL(headerValue, "http://x").pathname;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Not an absolute URL — treat as a bare path.
|
|
109
|
+
pathname = headerValue;
|
|
110
|
+
}
|
|
111
|
+
const decoded = splitPath(pathname);
|
|
112
|
+
if (decoded.length < 4)
|
|
113
|
+
return null;
|
|
114
|
+
if (decoded[0] !== "repos" || decoded[2] !== "docs")
|
|
115
|
+
return null;
|
|
116
|
+
if (decoded[1] !== repo)
|
|
117
|
+
return null; // cross-repo move — engine rejects; policy ignores dest
|
|
118
|
+
return decoded.slice(3).join("/");
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=proxy-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-policy.js","sourceRoot":"","sources":["../../src/shell/proxy-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fronting proxy — auth-shell plan §1 "Serve mode: fronting proxy", WS4.
|
|
3
|
+
*
|
|
4
|
+
* For deployments where the engine must run separately (polyglot/containerized
|
|
5
|
+
* topologies), `mrplex proxy --policy <file> --upstream <unix|url>` sits in
|
|
6
|
+
* front of a raw engine bound to a unix socket or loopback. Per request it:
|
|
7
|
+
* 1. authenticates the caller (bearer API key, like the HTTP front),
|
|
8
|
+
* 2. classifies the REST route and enforces write/destructive policy against
|
|
9
|
+
* the entitlement — route-aware, because the URL path is authoritative for
|
|
10
|
+
* writes (see proxy-policy.ts),
|
|
11
|
+
* 3. STRIPS any inbound `X-Mrplex-*` headers (mandatory — the engine trusts
|
|
12
|
+
* them unconditionally, so a client must never set its own identity),
|
|
13
|
+
* 4. INJECTS the entitlement's `X-Mrplex-Author` + `X-Mrplex-Scope`,
|
|
14
|
+
* 5. forwards to the upstream and streams the response back.
|
|
15
|
+
*
|
|
16
|
+
* Embedded serve is preferred (no second process, no header-trust surface);
|
|
17
|
+
* this exists for topologies that need engine/shell separation. MCP-over-proxy
|
|
18
|
+
* is read-only here: MCP tool args are opaque to path-level policy (docs_put
|
|
19
|
+
* carries a version id, not a source path), so writes over `/mcp` are refused
|
|
20
|
+
* with a pointer to embedded mode. REST writes are fully policed.
|
|
21
|
+
*/
|
|
22
|
+
import { type Server } from "node:http";
|
|
23
|
+
import type { AuditSink } from "./guard.js";
|
|
24
|
+
export type ProxyConfig = {
|
|
25
|
+
policyPath: string;
|
|
26
|
+
/** `unix:/path/to.sock` or `http://127.0.0.1:PORT` — the raw engine upstream. */
|
|
27
|
+
upstream: string;
|
|
28
|
+
host?: string;
|
|
29
|
+
port?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Audit-sink factory. When set, every authenticated request appends a record
|
|
32
|
+
* (principal, op derived from method+route, repo/path, outcome). Proxy mode
|
|
33
|
+
* bypasses the guard, so this is the accountability trail the guard would
|
|
34
|
+
* otherwise provide (auth-shell plan decision 8).
|
|
35
|
+
*/
|
|
36
|
+
auditSinkFor?: (principal: string) => AuditSink;
|
|
37
|
+
log?: (msg: string) => void;
|
|
38
|
+
};
|
|
39
|
+
export type ProxyHandle = {
|
|
40
|
+
server: Server;
|
|
41
|
+
port: number;
|
|
42
|
+
host: string;
|
|
43
|
+
baseUrl: string;
|
|
44
|
+
reloadPolicy: () => void;
|
|
45
|
+
close: () => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
export declare function startProxyServer(config: ProxyConfig): Promise<ProxyHandle>;
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fronting proxy — auth-shell plan §1 "Serve mode: fronting proxy", WS4.
|
|
3
|
+
*
|
|
4
|
+
* For deployments where the engine must run separately (polyglot/containerized
|
|
5
|
+
* topologies), `mrplex proxy --policy <file> --upstream <unix|url>` sits in
|
|
6
|
+
* front of a raw engine bound to a unix socket or loopback. Per request it:
|
|
7
|
+
* 1. authenticates the caller (bearer API key, like the HTTP front),
|
|
8
|
+
* 2. classifies the REST route and enforces write/destructive policy against
|
|
9
|
+
* the entitlement — route-aware, because the URL path is authoritative for
|
|
10
|
+
* writes (see proxy-policy.ts),
|
|
11
|
+
* 3. STRIPS any inbound `X-Mrplex-*` headers (mandatory — the engine trusts
|
|
12
|
+
* them unconditionally, so a client must never set its own identity),
|
|
13
|
+
* 4. INJECTS the entitlement's `X-Mrplex-Author` + `X-Mrplex-Scope`,
|
|
14
|
+
* 5. forwards to the upstream and streams the response back.
|
|
15
|
+
*
|
|
16
|
+
* Embedded serve is preferred (no second process, no header-trust surface);
|
|
17
|
+
* this exists for topologies that need engine/shell separation. MCP-over-proxy
|
|
18
|
+
* is read-only here: MCP tool args are opaque to path-level policy (docs_put
|
|
19
|
+
* carries a version id, not a source path), so writes over `/mcp` are refused
|
|
20
|
+
* with a pointer to embedded mode. REST writes are fully policed.
|
|
21
|
+
*/
|
|
22
|
+
import { createServer, request, } from "node:http";
|
|
23
|
+
import { claimsGrantRead, normalizeClaims } from "../kernel/auth/scope.js";
|
|
24
|
+
import { bearerToken, principalForKey } from "./keys.js";
|
|
25
|
+
import { compile, loadPolicyFile } from "./policy.js";
|
|
26
|
+
import { classifyRestRequest } from "./proxy-policy.js";
|
|
27
|
+
/**
|
|
28
|
+
* Request-body cap, mirroring the REST surface's `MAX_BODY_BYTES` (8 MB). The
|
|
29
|
+
* proxy is the enforcement point: it fronts an engine on a unix socket/loopback
|
|
30
|
+
* that can't be independently rate-limited, so a hostile client streaming
|
|
31
|
+
* unbounded bytes must be cut off here.
|
|
32
|
+
*/
|
|
33
|
+
const MAX_BODY_BYTES = 8 * 1024 * 1024;
|
|
34
|
+
function parseUpstream(spec) {
|
|
35
|
+
if (spec.startsWith("unix:")) {
|
|
36
|
+
return { kind: "unix", socketPath: spec.slice("unix:".length) };
|
|
37
|
+
}
|
|
38
|
+
const url = new URL(spec);
|
|
39
|
+
if (url.protocol !== "http:") {
|
|
40
|
+
throw new Error(`proxy upstream must be unix:<path> or http://<loopback> — got ${spec}`);
|
|
41
|
+
}
|
|
42
|
+
return { kind: "tcp", host: url.hostname, port: Number(url.port || 80) };
|
|
43
|
+
}
|
|
44
|
+
/** All inbound X-Mrplex-* headers are stripped before forwarding. */
|
|
45
|
+
function stripMrplexHeaders(headers) {
|
|
46
|
+
const out = {};
|
|
47
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
48
|
+
if (v === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
if (k.toLowerCase().startsWith("x-mrplex-"))
|
|
51
|
+
continue;
|
|
52
|
+
out[k] = v;
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
export async function startProxyServer(config) {
|
|
57
|
+
let policy = loadPolicyFile(config.policyPath);
|
|
58
|
+
const upstream = parseUpstream(config.upstream);
|
|
59
|
+
const log = config.log ?? ((m) => process.stderr.write(`${m}\n`));
|
|
60
|
+
let entitlementCache = new Map();
|
|
61
|
+
function entitlementFor(principalId) {
|
|
62
|
+
const cached = entitlementCache.get(principalId);
|
|
63
|
+
if (cached)
|
|
64
|
+
return cached;
|
|
65
|
+
const e = compile(policy, principalId);
|
|
66
|
+
entitlementCache.set(principalId, e);
|
|
67
|
+
return e;
|
|
68
|
+
}
|
|
69
|
+
function authenticate(req) {
|
|
70
|
+
const key = bearerToken(firstHeader(req.headers.authorization));
|
|
71
|
+
if (key === null)
|
|
72
|
+
return null;
|
|
73
|
+
const principalId = principalForKey(policy, key);
|
|
74
|
+
if (principalId === null)
|
|
75
|
+
return null;
|
|
76
|
+
return { principalId, entitlement: entitlementFor(principalId) };
|
|
77
|
+
}
|
|
78
|
+
const auditSinkFor = config.auditSinkFor;
|
|
79
|
+
const server = createServer((req, res) => {
|
|
80
|
+
void handle(req, res).catch((err) => writeError(res, 500, "internal_error", String(err)));
|
|
81
|
+
});
|
|
82
|
+
async function handle(req, res) {
|
|
83
|
+
const auth = authenticate(req);
|
|
84
|
+
if (auth === null) {
|
|
85
|
+
return writeError(res, 401, "unauthorized", "missing or invalid credential");
|
|
86
|
+
}
|
|
87
|
+
const { principalId, entitlement } = auth;
|
|
88
|
+
const audit = auditSinkFor?.(principalId);
|
|
89
|
+
const method = req.method ?? "GET";
|
|
90
|
+
const url = req.url ?? "/";
|
|
91
|
+
const pathname = new URL(url, "http://x").pathname;
|
|
92
|
+
// MCP-over-proxy is read-only (tool args are opaque to path policy). We
|
|
93
|
+
// can't tell a read tool from a write tool without parsing the JSON-RPC
|
|
94
|
+
// body, so /mcp is refused entirely in proxy mode — embedded serve is the
|
|
95
|
+
// supported path for authenticated MCP.
|
|
96
|
+
if (pathname === "/mcp" || pathname.startsWith("/mcp?") || pathname.startsWith("/mcp/")) {
|
|
97
|
+
audit?.({ op: "mcp", outcome: "forbidden" });
|
|
98
|
+
return writeError(res, 403, "forbidden", "MCP over the fronting proxy is not supported; use `mrplex serve --policy` (embedded) for authenticated MCP");
|
|
99
|
+
}
|
|
100
|
+
// Enforce REST route policy before forwarding.
|
|
101
|
+
const requirement = classifyRestRequest(method, pathname, firstHeader(req.headers.destination));
|
|
102
|
+
const op = opName(method, requirement);
|
|
103
|
+
const meta = auditMeta(requirement);
|
|
104
|
+
const denial = policyDenial(requirement, entitlement);
|
|
105
|
+
if (denial !== null) {
|
|
106
|
+
audit?.({ op, ...meta, outcome: "forbidden" });
|
|
107
|
+
return writeError(res, denial.status, denial.code, denial.reason);
|
|
108
|
+
}
|
|
109
|
+
// Strip inbound identity headers, inject the entitlement's. The engine
|
|
110
|
+
// trusts these unconditionally, which is exactly why the client's own
|
|
111
|
+
// X-Mrplex-* were stripped above.
|
|
112
|
+
const headers = stripMrplexHeaders(req.headers);
|
|
113
|
+
headers["x-mrplex-author"] = entitlement.author;
|
|
114
|
+
headers["x-mrplex-scope"] = JSON.stringify(entitlement.read);
|
|
115
|
+
forward(req, res, headers, (status) => {
|
|
116
|
+
// The shell allowed the call; the engine's status becomes the outcome's
|
|
117
|
+
// error tag when it's a 4xx/5xx (mirrors the guard's "ok, engine error").
|
|
118
|
+
audit?.({
|
|
119
|
+
op,
|
|
120
|
+
...meta,
|
|
121
|
+
outcome: "ok",
|
|
122
|
+
...(status >= 400 ? { error: `http_${status}` } : {}),
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function forward(req, res, headers, onResponse) {
|
|
127
|
+
const common = { method: req.method, path: req.url, headers };
|
|
128
|
+
const upstreamReq = upstream.kind === "unix"
|
|
129
|
+
? request({ socketPath: upstream.socketPath, ...common }, (upRes) => {
|
|
130
|
+
onResponse(upRes.statusCode ?? 502);
|
|
131
|
+
pipeResponse(upRes, res);
|
|
132
|
+
})
|
|
133
|
+
: request({ host: upstream.host, port: upstream.port, ...common }, (upRes) => {
|
|
134
|
+
onResponse(upRes.statusCode ?? 502);
|
|
135
|
+
pipeResponse(upRes, res);
|
|
136
|
+
});
|
|
137
|
+
upstreamReq.on("error", (err) => writeError(res, 502, "bad_gateway", err.message));
|
|
138
|
+
// Cap the streamed body — the proxy is the enforcement point in front of an
|
|
139
|
+
// otherwise-unprotected engine. Past the limit, destroy both ends and 413.
|
|
140
|
+
let total = 0;
|
|
141
|
+
req.on("data", (chunk) => {
|
|
142
|
+
total += chunk.length;
|
|
143
|
+
if (total > MAX_BODY_BYTES) {
|
|
144
|
+
req.destroy();
|
|
145
|
+
upstreamReq.destroy();
|
|
146
|
+
writeError(res, 413, "payload_too_large", `body exceeded ${MAX_BODY_BYTES} bytes`);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
req.pipe(upstreamReq);
|
|
150
|
+
}
|
|
151
|
+
const host = config.host ?? "127.0.0.1";
|
|
152
|
+
const port = config.port ?? 8321;
|
|
153
|
+
await new Promise((resolve, reject) => {
|
|
154
|
+
server.once("error", reject);
|
|
155
|
+
server.listen(port, host, () => {
|
|
156
|
+
server.removeListener("error", reject);
|
|
157
|
+
resolve();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
const boundPort = server.address().port;
|
|
161
|
+
const baseUrl = `http://${host.includes(":") ? `[${host}]` : host}:${boundPort}`;
|
|
162
|
+
log(`mrplex: proxy (authenticated) on ${baseUrl}`);
|
|
163
|
+
log(`mrplex: policy ${config.policyPath}`);
|
|
164
|
+
log(`mrplex: upstream ${config.upstream}`);
|
|
165
|
+
function reloadPolicy() {
|
|
166
|
+
try {
|
|
167
|
+
policy = loadPolicyFile(config.policyPath);
|
|
168
|
+
entitlementCache = new Map();
|
|
169
|
+
log(`mrplex: policy reloaded from ${config.policyPath}`);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
log(`mrplex: policy reload FAILED, keeping previous: ${err.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
let closed = false;
|
|
176
|
+
const close = async () => {
|
|
177
|
+
if (closed)
|
|
178
|
+
return;
|
|
179
|
+
closed = true;
|
|
180
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
181
|
+
};
|
|
182
|
+
return { server, port: boundPort, host, baseUrl, reloadPolicy, close };
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* A coarse op label for the audit log, derived from method + route class. The
|
|
186
|
+
* proxy doesn't parse bodies, so this is method-and-route granularity (e.g.
|
|
187
|
+
* `write`, `destructive`, `read`) rather than the exact kernel op name the
|
|
188
|
+
* embedded guard records — enough to answer "who did what where".
|
|
189
|
+
*/
|
|
190
|
+
function opName(method, requirement) {
|
|
191
|
+
return `${method.toUpperCase()} ${requirement.kind}`;
|
|
192
|
+
}
|
|
193
|
+
/** repo/path fields for the audit record, when the route carries them. */
|
|
194
|
+
function auditMeta(requirement) {
|
|
195
|
+
if (requirement.kind === "write") {
|
|
196
|
+
return { repo: requirement.repo, path: requirement.paths.join(" -> ") };
|
|
197
|
+
}
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
/** Null = allowed. Otherwise the HTTP denial to write. */
|
|
201
|
+
function policyDenial(requirement, entitlement) {
|
|
202
|
+
switch (requirement.kind) {
|
|
203
|
+
case "read":
|
|
204
|
+
return null; // read scope is enforced downstream via injected X-Mrplex-Scope
|
|
205
|
+
case "destructive":
|
|
206
|
+
return entitlement.destructive
|
|
207
|
+
? null
|
|
208
|
+
: { status: 403, code: "forbidden", reason: "destructive op not permitted" };
|
|
209
|
+
case "write":
|
|
210
|
+
return writeAllowed(entitlement, requirement.repo, requirement.paths)
|
|
211
|
+
? null
|
|
212
|
+
: { status: 403, code: "forbidden", reason: "write outside permitted scope" };
|
|
213
|
+
case "unknown":
|
|
214
|
+
// A route we don't model must not be forwarded blind — it could be an
|
|
215
|
+
// unpoliced write. Refuse; add the route to the classifier if it's real.
|
|
216
|
+
return { status: 403, code: "forbidden", reason: "route not recognized by the proxy" };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* True iff the entitlement's write scope covers EVERY path (both-endpoints on a
|
|
221
|
+
* move). Reuses the guard's exact matcher semantics. Sigil paths are the
|
|
222
|
+
* engine's to police (validatePath), so they pass at the policy layer.
|
|
223
|
+
*/
|
|
224
|
+
function writeAllowed(entitlement, repo, paths) {
|
|
225
|
+
const matchers = normalizeClaims(entitlement.write);
|
|
226
|
+
return paths.every((p) => isSystemPath(p) || claimsGrantRead(matchers, repo, p));
|
|
227
|
+
}
|
|
228
|
+
function isSystemPath(path) {
|
|
229
|
+
return path.split("/").some((seg) => seg.startsWith(":"));
|
|
230
|
+
}
|
|
231
|
+
function firstHeader(v) {
|
|
232
|
+
if (v === undefined)
|
|
233
|
+
return undefined;
|
|
234
|
+
return Array.isArray(v) ? v[0] : v;
|
|
235
|
+
}
|
|
236
|
+
function pipeResponse(upRes, res) {
|
|
237
|
+
res.statusCode = upRes.statusCode ?? 502;
|
|
238
|
+
for (const [k, v] of Object.entries(upRes.headers)) {
|
|
239
|
+
if (v !== undefined)
|
|
240
|
+
res.setHeader(k, v);
|
|
241
|
+
}
|
|
242
|
+
upRes.pipe(res);
|
|
243
|
+
}
|
|
244
|
+
function writeError(res, status, code, reason) {
|
|
245
|
+
if (res.headersSent) {
|
|
246
|
+
res.end();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
res.statusCode = status;
|
|
250
|
+
res.setHeader("Content-Type", "application/json");
|
|
251
|
+
res.end(JSON.stringify({ code, data: { reason } }));
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/shell/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded serve — the shell's primary mode (auth-shell plan §1 "Serve mode:
|
|
3
|
+
* embedded", WS3).
|
|
4
|
+
*
|
|
5
|
+
* One process: open the database, `createKernel`, and mount mrplex's own REST +
|
|
6
|
+
* MCP surfaces on top of PER-REQUEST guarded kernels. There is no engine
|
|
7
|
+
* listener at all — so there is no trusted-header problem and no second
|
|
8
|
+
* process. Each request:
|
|
9
|
+
* 1. carries a credential (today: an API key as `Authorization: Bearer`);
|
|
10
|
+
* 2. the shell resolves it to a principal, `compile()`s the entitlement
|
|
11
|
+
* (cached per principal, invalidated on policy reload),
|
|
12
|
+
* 3. `guardKernel()`s the shared kernel with that entitlement + an audit sink,
|
|
13
|
+
* 4. and the surface dispatches against the guarded kernel.
|
|
14
|
+
*
|
|
15
|
+
* The surfaces accept a `kernelForRequest` factory (WS0's generalization), so
|
|
16
|
+
* this file is pure composition: no surface code is forked, and all write /
|
|
17
|
+
* destructive / author policy lives in the guard.
|
|
18
|
+
*
|
|
19
|
+
* Policy is reloadable on SIGHUP: the loader swaps the in-memory policy and
|
|
20
|
+
* clears the entitlement cache, so a running server picks up a key revocation
|
|
21
|
+
* or grant change without a restart. The credential→principal→entitlement
|
|
22
|
+
* pipeline is otherwise identical to the stdio and (future) proxy fronts —
|
|
23
|
+
* they differ only in how the credential arrives.
|
|
24
|
+
*/
|
|
25
|
+
import { type Server } from "node:http";
|
|
26
|
+
import { type EmbedConfig } from "../embed/config.js";
|
|
27
|
+
import type { EmbedHook } from "../embed/hook.js";
|
|
28
|
+
import { type Worker } from "../embed/worker.js";
|
|
29
|
+
import { type Kernel } from "../kernel/kernel.js";
|
|
30
|
+
import { type PathConfig } from "../kernel/path-config.js";
|
|
31
|
+
import type { Storage } from "../storage/types.js";
|
|
32
|
+
import { type AuditSink } from "./guard.js";
|
|
33
|
+
import { type OidcVerifier } from "./oidc.js";
|
|
34
|
+
export type ShellServeConfig = {
|
|
35
|
+
database: string;
|
|
36
|
+
/** Path to the YAML policy file. Loaded at startup, reloaded on SIGHUP. */
|
|
37
|
+
policyPath: string;
|
|
38
|
+
host?: string;
|
|
39
|
+
port?: number;
|
|
40
|
+
serverPathConfig?: PathConfig;
|
|
41
|
+
embed?: EmbedConfig;
|
|
42
|
+
/** Audit-log path. When set, every authenticated call appends a JSONL line. */
|
|
43
|
+
auditPath?: string;
|
|
44
|
+
/** Factory for the audit sink — injectable for tests; defaults to file JSONL. */
|
|
45
|
+
auditSinkFor?: (principal: string) => AuditSink;
|
|
46
|
+
/**
|
|
47
|
+
* OIDC verifier for the JWT front. When set, a bearer that isn't a known API
|
|
48
|
+
* key is verified as a JWT and matched to a principal by its oidc binding.
|
|
49
|
+
*/
|
|
50
|
+
oidc?: OidcVerifier;
|
|
51
|
+
log?: (msg: string) => void;
|
|
52
|
+
};
|
|
53
|
+
export type ShellServeHandle = {
|
|
54
|
+
server: Server;
|
|
55
|
+
storage: Storage;
|
|
56
|
+
kernel: Kernel;
|
|
57
|
+
port: number;
|
|
58
|
+
host: string;
|
|
59
|
+
baseUrl: string;
|
|
60
|
+
embed: {
|
|
61
|
+
hook: EmbedHook;
|
|
62
|
+
worker: Worker;
|
|
63
|
+
} | null;
|
|
64
|
+
/** Re-read the policy file and clear the entitlement cache. Called on SIGHUP. */
|
|
65
|
+
reloadPolicy: () => void;
|
|
66
|
+
close: () => Promise<void>;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Peel an optional `/k/<token>/…` credential prefix off a request URL. Some MCP
|
|
70
|
+
* clients (ChatGPT connectors among them) can set a URL but not an
|
|
71
|
+
* `Authorization` header; this lets the bearer ride in the path instead. The
|
|
72
|
+
* `<token>` segment is the exact same credential the header carries (an API key
|
|
73
|
+
* or a JWT) — issuance, hashing, and revocation are unchanged.
|
|
74
|
+
*
|
|
75
|
+
* Returns the token plus the URL with the prefix removed (`/k/<t>/mcp` →
|
|
76
|
+
* `/mcp`, `/k/<t>` → `/`), or null when there's no prefix. The caller rewrites
|
|
77
|
+
* `req.url` to the stripped form BEFORE anything routes or logs on it, so the
|
|
78
|
+
* token lives only in the TLS bytes and the (secret-treated) Authorization
|
|
79
|
+
* header — never in a logged URL. NOTE: an upstream reverse proxy may still log
|
|
80
|
+
* the original path; see docs/archive/security.md.
|
|
81
|
+
*/
|
|
82
|
+
export declare function stripTokenPrefix(url: string): {
|
|
83
|
+
token: string;
|
|
84
|
+
url: string;
|
|
85
|
+
} | null;
|
|
86
|
+
export declare function startShellServer(config: ShellServeConfig): Promise<ShellServeHandle>;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/shell/serve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stdio launcher — auth-shell plan §1 "Launcher mode: stdio", WS4.
|
|
3
|
+
*
|
|
4
|
+
* `mrplex mcp-stdio` runs an in-process stdio MCP session over a GUARDED
|
|
5
|
+
* kernel. stdio has no HTTP layer, so the credential arrives one of three ways
|
|
6
|
+
* (the MCP spec's own guidance for stdio is credentials-from-environment):
|
|
7
|
+
*
|
|
8
|
+
* 1. `--principal <id>` — trust-by-spawn, no credential: the parent chose to
|
|
9
|
+
* spawn us (local dev, or a gateway that already authenticated).
|
|
10
|
+
* 2. `MRPLEX_SHELL_KEY` env / `--key` — an API key, verified against the
|
|
11
|
+
* policy file exactly as the HTTP front does.
|
|
12
|
+
* 3. `MRPLEX_SHELL_TOKEN` env / `--token` — an OAuth access token (WS5).
|
|
13
|
+
*
|
|
14
|
+
* All three converge on the same `credential → principal → compile() →
|
|
15
|
+
* guardKernel` pipeline; stdio is only special in how the credential arrives.
|
|
16
|
+
*/
|
|
17
|
+
import type { Kernel } from "../kernel/kernel.js";
|
|
18
|
+
import { type StdioMount } from "../mcp/server.js";
|
|
19
|
+
import { type AuditSink } from "./guard.js";
|
|
20
|
+
import { type OidcVerifier } from "./oidc.js";
|
|
21
|
+
import { type Policy } from "./policy.js";
|
|
22
|
+
export type StdioCredential = {
|
|
23
|
+
kind: "principal";
|
|
24
|
+
id: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "key";
|
|
27
|
+
key: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "token";
|
|
30
|
+
token: string;
|
|
31
|
+
};
|
|
32
|
+
/** A resolved stdio caller: which principal, plus a derived author for tokens. */
|
|
33
|
+
export type StdioResolution = {
|
|
34
|
+
principalId: string;
|
|
35
|
+
derivedAuthor?: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a stdio credential to a principal against the policy, or throw a
|
|
39
|
+
* clear error. `--principal` is trust-by-spawn (the id must exist, no secret
|
|
40
|
+
* checked); a key is verified by hash; a token is verified as a JWT (requires
|
|
41
|
+
* an OIDC verifier) and matched to a principal by its oidc binding.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveCredential(policy: Policy, cred: StdioCredential, oidc?: OidcVerifier): Promise<StdioResolution>;
|
|
44
|
+
/**
|
|
45
|
+
* Start a guarded stdio MCP session. Resolves the credential to a principal,
|
|
46
|
+
* compiles its entitlement, wraps the kernel in the guard (+ optional audit),
|
|
47
|
+
* and hands the guarded kernel to the shared stdio transport.
|
|
48
|
+
*/
|
|
49
|
+
export declare function startShellStdio(config: {
|
|
50
|
+
kernel: Kernel;
|
|
51
|
+
policy: Policy;
|
|
52
|
+
credential: StdioCredential;
|
|
53
|
+
oidc?: OidcVerifier;
|
|
54
|
+
auditSinkFor?: (principal: string) => AuditSink;
|
|
55
|
+
}): Promise<StdioMount>;
|