@integsec/agentic-pentest-proxy 0.3.4 → 0.3.6

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.
Files changed (47) hide show
  1. package/README.md +2 -0
  2. package/cloudflare/wrangler.jsonc +1 -1
  3. package/dist/bin/integsec-agentic-pentest-bridge.js +2 -2
  4. package/dist/bin/integsec-agentic-pentest-gateway.js +30 -2
  5. package/dist/bin/integsec-agentic-pentest-gateway.js.map +1 -1
  6. package/dist/bin/integsec-agentic-pentest-tui.js +5 -0
  7. package/dist/bin/integsec-agentic-pentest-tui.js.map +1 -1
  8. package/dist/src/audit/local.js +2 -2
  9. package/dist/src/audit/local.js.map +1 -1
  10. package/dist/src/config.js +1 -1
  11. package/dist/src/gateway/admin.html +3 -3
  12. package/dist/src/gateway/docs-home.html +20 -0
  13. package/dist/src/gateway/docs.d.ts +3 -0
  14. package/dist/src/gateway/docs.d.ts.map +1 -0
  15. package/dist/src/gateway/docs.html +12 -0
  16. package/dist/src/gateway/docs.js +94 -0
  17. package/dist/src/gateway/docs.js.map +1 -0
  18. package/dist/src/gateway/local-paths.d.ts +7 -0
  19. package/dist/src/gateway/local-paths.d.ts.map +1 -0
  20. package/dist/src/gateway/local-paths.js +30 -0
  21. package/dist/src/gateway/local-paths.js.map +1 -0
  22. package/dist/src/gateway/runtime.js +2 -2
  23. package/dist/src/gateway/server.d.ts.map +1 -1
  24. package/dist/src/gateway/server.js +24 -0
  25. package/dist/src/gateway/server.js.map +1 -1
  26. package/dist/src/gateway/state.d.ts +1 -1
  27. package/dist/src/index.d.ts +1 -1
  28. package/dist/src/index.js +1 -1
  29. package/docs/configuration.md +70 -0
  30. package/docs/development.md +17 -0
  31. package/docs/images/tui-in-scope.png +0 -0
  32. package/docs/images/tui-in-scope.svg +24 -0
  33. package/docs/images/tui-out-of-scope.png +0 -0
  34. package/docs/images/tui-out-of-scope.svg +25 -0
  35. package/docs/images/tui-policy-blocks.png +0 -0
  36. package/docs/images/tui-policy-blocks.svg +24 -0
  37. package/docs/integrations.md +74 -0
  38. package/docs/managed-gateway.md +4 -0
  39. package/docs/release-readiness-0.2.6.md +27 -0
  40. package/docs/security.md +33 -0
  41. package/docs/superpowers/plans/2026-03-26-mcp-scope-proxy.md +3051 -0
  42. package/docs/superpowers/plans/2026-03-28-tui-monitor.md +863 -0
  43. package/docs/superpowers/plans/2026-03-29-manifest-builder.md +3429 -0
  44. package/docs/superpowers/specs/2026-03-28-tui-monitor-design.md +138 -0
  45. package/docs/superpowers/specs/2026-03-29-manifest-builder-design.md +248 -0
  46. package/docs/tui.md +27 -0
  47. package/package.json +4 -2
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # IntegSec Agentic Pentest Proxy
2
2
 
3
+ **New to the gateway?** The [documentation site](https://agentic-proxy.pentestprepper.com/docs) shows the local and hosted paths side by side, including where test traffic comes from. The full guides below are also available there after team sign-in.
4
+
3
5
  An MCP proxy that checks tool calls against a pentest scope manifest before forwarding them to your MCP tools. It blocks calls it can identify as outside the targets, techniques, or time window you approved, and records decisions in a local audit log.
4
6
 
5
7
  **Requires Node.js 22 or newer.** The proxy supports stdio tools, SSE upstreams such as Burp Suite, and HTTP upstreams.
@@ -10,7 +10,7 @@
10
10
  "containers": [
11
11
  {
12
12
  "class_name": "PentestGatewayContainer",
13
- "image": "docker.io/integsec/agentic-pentest-mcp-proxy:0.3.4",
13
+ "image": "docker.io/integsec/agentic-pentest-mcp-proxy:0.3.6",
14
14
  "instance_type": "basic",
15
15
  "max_instances": 1
16
16
  }
@@ -12,9 +12,9 @@ const url = new URL(process.argv[2] ?? process.env.GATEWAY_URL ?? "http://127.0.
12
12
  if (!["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) || url.protocol !== "http:") {
13
13
  throw new Error("The local bridge only accepts a loopback HTTP gateway URL");
14
14
  }
15
- const upstream = new Client({ name: "agentic-pentest-bridge", version: "0.3.4" });
15
+ const upstream = new Client({ name: "agentic-pentest-bridge", version: "0.3.6" });
16
16
  await upstream.connect(new StreamableHTTPClientTransport(url));
17
- const bridge = new Server({ name: "agentic-pentest-local", version: "0.3.4" }, { capabilities: { tools: {} } });
17
+ const bridge = new Server({ name: "agentic-pentest-local", version: "0.3.6" }, { capabilities: { tools: {} } });
18
18
  bridge.setRequestHandler(ListToolsRequestSchema, async (request) => upstream.listTools(request.params));
19
19
  bridge.setRequestHandler(CallToolRequestSchema, async (request) => upstream.callTool(request.params));
20
20
  await bridge.connect(new StdioServerTransport());
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import "dotenv/config";
3
3
  import { randomBytes } from "node:crypto";
4
+ import { mkdirSync } from "node:fs";
4
5
  import { createGateway } from "../src/gateway/server.js";
6
+ import { defaultGatewayPaths, migrateLegacyGatewayState } from "../src/gateway/local-paths.js";
5
7
  if (process.argv.includes("--help") || process.argv.includes("-h")) {
6
8
  console.log(`IntegSec MCP Gateway
7
9
 
@@ -9,7 +11,8 @@ Manage MCP upstreams and engagement scopes in a browser, then connect an MCP cli
9
11
 
10
12
  Local mode: a temporary admin token is printed at startup. Set GATEWAY_ADMIN_TOKEN
11
13
  (at least 32 characters) if you need a stable token across restarts.
12
- Optional: GATEWAY_HOST (127.0.0.1), GATEWAY_PORT (9091), GATEWAY_STATE_PATH (./gateway/state.json).
14
+ Optional: GATEWAY_HOST (127.0.0.1), GATEWAY_PORT (9091), GATEWAY_STATE_PATH.
15
+ State and audit logs default to your operating system's per-user data directory.
13
16
  Hosted with Cloudflare Access: GATEWAY_PUBLIC_URL, GATEWAY_AUTH_MODE=cloudflare,
14
17
  CLOUDFLARE_TEAM_DOMAIN, CLOUDFLARE_ACCESS_AUD,
15
18
  GATEWAY_BOOTSTRAP_ADMIN_EMAILS (comma-separated).
@@ -23,10 +26,23 @@ Open: http://127.0.0.1:9091/admin
23
26
  const host = process.env.GATEWAY_HOST ?? "127.0.0.1";
24
27
  const local = !process.env.GATEWAY_PUBLIC_URL && (host === "127.0.0.1" || host === "::1");
25
28
  const generatedToken = local && !process.env.GATEWAY_ADMIN_TOKEN ? randomBytes(32).toString("hex") : undefined;
29
+ const defaults = defaultGatewayPaths();
30
+ const statePath = process.env.GATEWAY_STATE_PATH || defaults.statePath;
31
+ const auditDir = process.env.AUDIT_LOG_PATH || defaults.auditDir;
32
+ process.env.AUDIT_LOG_PATH = auditDir;
33
+ try {
34
+ if (!process.env.GATEWAY_STATE_PATH && migrateLegacyGatewayState(statePath)) {
35
+ console.error("[gateway] Copied existing local configuration into the per-user data directory.");
36
+ }
37
+ }
38
+ catch (error) {
39
+ console.error(`[gateway] Cannot move existing gateway data into your per-user directory: ${error instanceof Error ? error.message : String(error)}. Set GATEWAY_STATE_PATH to a writable location, then restart.`);
40
+ process.exit(1);
41
+ }
26
42
  const gateway = createGateway({
27
43
  host,
28
44
  port: Number(process.env.GATEWAY_PORT ?? "9091"),
29
- statePath: process.env.GATEWAY_STATE_PATH ?? "./gateway/state.json",
45
+ statePath,
30
46
  adminToken: generatedToken ?? process.env.GATEWAY_ADMIN_TOKEN ?? "",
31
47
  bootstrapAdminEmails: (process.env.GATEWAY_BOOTSTRAP_ADMIN_EMAILS ?? "").split(",").map((value) => value.trim()).filter(Boolean),
32
48
  publicUrl: process.env.GATEWAY_PUBLIC_URL,
@@ -40,9 +56,21 @@ const gateway = createGateway({
40
56
  auditWebhookUrl: process.env.AUDIT_WEBHOOK_URL,
41
57
  auditWebhookToken: process.env.AUDIT_WEBHOOK_TOKEN,
42
58
  });
59
+ if (local) {
60
+ try {
61
+ gateway.store.replace(gateway.store.snapshot());
62
+ mkdirSync(auditDir, { recursive: true, mode: 0o700 });
63
+ }
64
+ catch (error) {
65
+ console.error(`[gateway] Cannot save local gateway data: ${error instanceof Error ? error.message : String(error)}. Set GATEWAY_STATE_PATH and AUDIT_LOG_PATH to writable locations, then restart.`);
66
+ process.exit(1);
67
+ }
68
+ }
43
69
  await gateway.listen();
44
70
  console.error(`[gateway] Listening on ${process.env.GATEWAY_HOST ?? "127.0.0.1"}:${process.env.GATEWAY_PORT ?? "9091"}`);
45
71
  console.error("[gateway] Admin UI: /admin; MCP: /mcp");
72
+ if (local)
73
+ console.error("[gateway] Audit monitor: integsec-agentic-pentest-tui --gateway");
46
74
  if (generatedToken)
47
75
  console.error(`[gateway] Local admin token (paste into /admin): ${generatedToken}`);
48
76
  const stop = async () => { await gateway.close(); process.exit(0); };
@@ -1 +1 @@
1
- {"version":3,"file":"integsec-agentic-pentest-gateway.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integsec-agentic-pentest-gateway.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-gateway.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { render } from "ink";
4
4
  import { App } from "../src/tui/App.js";
5
+ import { defaultGatewayPaths } from "../src/gateway/local-paths.js";
5
6
  function parseArgs() {
6
7
  const args = process.argv.slice(2);
7
8
  let auditDir = process.env.AUDIT_LOG_PATH ?? "./audit";
@@ -11,6 +12,9 @@ function parseArgs() {
11
12
  auditDir = args[i + 1];
12
13
  i++;
13
14
  }
15
+ else if (args[i] === "--gateway") {
16
+ auditDir = process.env.AUDIT_LOG_PATH || defaultGatewayPaths().auditDir;
17
+ }
14
18
  else if (args[i] === "--engagement" && args[i + 1]) {
15
19
  engagementId = args[i + 1];
16
20
  i++;
@@ -24,6 +28,7 @@ Usage:
24
28
 
25
29
  Options:
26
30
  --audit-path <dir> Path to audit log directory (default: AUDIT_LOG_PATH or ./audit)
31
+ --gateway Watch the local gateway's per-user audit directory
27
32
  --engagement <id> Filter to a specific engagement ID
28
33
  -h, --help Show this help message
29
34
  `);
@@ -1 +1 @@
1
- {"version":3,"file":"integsec-agentic-pentest-tui.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-tui.tsx"],"names":[],"mappings":";;AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,SAAS,CAAC;IACvD,IAAI,YAAgC,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9C,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvB,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrD,YAAY,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUjB,CAAC,CAAC;YACG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAAC;AAC/C,MAAM,CAAC,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,GAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"integsec-agentic-pentest-tui.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-tui.tsx"],"names":[],"mappings":";;AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEpE,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,SAAS,CAAC;IACvD,IAAI,YAAgC,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9C,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvB,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC;YACnC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,mBAAmB,EAAE,CAAC,QAAQ,CAAC;QAC1E,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrD,YAAY,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;CAWjB,CAAC,CAAC;YACG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAAC;AAC/C,MAAM,CAAC,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,GAAI,CAAC,CAAC"}
@@ -35,7 +35,7 @@ export class LocalAuditLogger {
35
35
  return;
36
36
  }
37
37
  // Ensure the base directory exists
38
- fs.mkdirSync(this.basePath, { recursive: true });
38
+ fs.mkdirSync(this.basePath, { recursive: true, mode: 0o700 });
39
39
  for (const [engagementId, entries] of this.buffer.entries()) {
40
40
  if (entries.length === 0) {
41
41
  continue;
@@ -43,7 +43,7 @@ export class LocalAuditLogger {
43
43
  const filePath = path.join(this.basePath, `${engagementFileStem(engagementId)}.jsonl`);
44
44
  // Build the content to append: one JSON object per line, terminated with \n
45
45
  const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
46
- fs.appendFileSync(filePath, lines, "utf-8");
46
+ fs.appendFileSync(filePath, lines, { encoding: "utf-8", mode: 0o600 });
47
47
  }
48
48
  // Clear buffer after successful flush
49
49
  this.buffer.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/audit/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IACnB,QAAQ,CAAS;IACzB,6DAA6D;IACrD,MAAM,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEtD,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,mCAAmC;QACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvF,4EAA4E;YAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACtE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QACD,sCAAsC;QACtC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"}
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/audit/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IACnB,QAAQ,CAAS;IACzB,6DAA6D;IACrD,MAAM,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEtD,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,KAAiB;QACzB,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,mCAAmC;QACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvF,4EAA4E;YAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACtE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,sCAAsC;QACtC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"}
@@ -50,7 +50,7 @@ export function loadConfig() {
50
50
  techniqueMapPath: process.env.TECHNIQUE_MAP_PATH,
51
51
  dnsCacheTtl: parseInt(process.env.DNS_CACHE_TTL || "60", 10),
52
52
  logLevel: process.env.LOG_LEVEL || "INFO",
53
- proxyVersion: process.env.PROXY_VERSION || "0.3.4",
53
+ proxyVersion: process.env.PROXY_VERSION || "0.3.6",
54
54
  };
55
55
  }
56
56
  //# sourceMappingURL=config.js.map
@@ -6,7 +6,7 @@
6
6
  <style>
7
7
  :root{font:15px system-ui,sans-serif;color:#e8f0f2;background:#0b1218}*{box-sizing:border-box}body{margin:0}header{padding:22px 5vw;background:#10202b;border-bottom:1px solid #234052;display:flex;justify-content:space-between;align-items:center;gap:20px}h1{font-size:21px;margin:0}h2{font-size:18px;margin:0 0 14px}h3{font-size:15px;margin:16px 0 6px}p{color:#a8bdc8;line-height:1.45}main{max-width:1200px;margin:30px auto;padding:0 20px;display:grid;grid-template-columns:1fr 1fr;gap:20px}.card{background:#14222c;border:1px solid #294454;border-radius:13px;padding:24px}.wide{grid-column:1/-1}input,select,textarea,button{font:inherit}input:not([type=checkbox]),select,textarea{width:100%;background:#0b1720;color:#fff;border:1px solid #426073;border-radius:7px;padding:9px;margin:5px 0 12px}textarea{min-height:70px}label{display:block;color:#c1d0d8;font-weight:600;font-size:13px}button{border:0;border-radius:7px;background:#26bfa4;color:#081914;padding:9px 14px;font-weight:700;cursor:pointer;margin:4px 7px 4px 0}button.secondary{background:#304b5a;color:#e8f0f2}button[aria-pressed=true]{outline:2px solid #26bfa4}button.danger{background:#6d3541;color:#fff}button:disabled{opacity:.5;cursor:not-allowed}.grid{display:grid;grid-template-columns:1fr 1fr;gap:0 14px}.row{border-top:1px solid #294454;padding:12px 0;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.muted{font-size:12px;color:#93acb9}.choices{display:flex;flex-wrap:wrap;gap:8px 18px;margin:12px 0}.choices label{display:inline-flex;gap:7px;align-items:center;font-weight:400;font-size:14px}.choices input{width:auto;margin:0}.pill{display:inline-block;background:#234051;border-radius:20px;padding:3px 9px;font-size:12px;margin-left:8px}.actions{display:flex;flex-wrap:wrap;gap:3px}.help{background:#0d1e28;border-left:3px solid #26bfa4;padding:10px 14px;margin:12px 0}.review{white-space:pre-wrap;background:#0b1720;border:1px solid #426073;border-radius:7px;padding:14px;line-height:1.5}#status{padding:8px 5vw;color:#8ee7ce;min-height:35px}#status.error{color:#ff9e9e}code{color:#a6e7db}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:#0b1720;border:1px solid #426073;border-radius:7px;padding:12px}ol{color:#a8bdc8;line-height:1.6;padding-left:22px}li{margin:8px 0}summary{cursor:pointer;color:#e8f0f2;font-weight:700}[hidden]{display:none!important}a{color:#8ee7ce}@media(max-width:800px){main{display:block}.card{margin-bottom:20px}.grid{display:block}}
8
8
  </style>
9
- <header><h1>IntegSec MCP Gateway</h1><span id="identity" class="muted">Loading session…</span></header>
9
+ <header><h1>IntegSec MCP Gateway</h1><nav aria-label="Site"><a href="/docs">How it works &amp; docs</a> · <a href="https://github.com/IntegSec/agentic-pentest-proxy" rel="noopener noreferrer">GitHub repository ↗</a></nav><span id="identity" class="muted">Loading session…</span></header>
10
10
  <div id="status" role="status" aria-live="polite"></div>
11
11
  <main>
12
12
  <section id="token-card" class="card wide" hidden><h2>Local administrator access</h2><p>Paste the admin token printed in PowerShell when the gateway started. It stays in this browser tab only.</p><div class="grid"><label>Admin token<input id="token" type="password" autocomplete="off"></label><div><br><button id="connect">Connect</button></div></div></section>
@@ -15,7 +15,7 @@
15
15
  <section id="upstreams-card" class="card admin-only" hidden>
16
16
  <h2>MCP servers</h2>
17
17
  <p id="server-intro"></p>
18
- <p class="help">Target traffic comes from the machine running the MCP tool: the tester’s laptop or VPN for local Burp, or the remote tool provider for a hosted scanner. This gateway does not control a model’s separate web browsing.</p>
18
+ <p class="help">Target traffic comes from the machine running the MCP tool: the tester’s laptop or VPN for local Burp, or the remote tool provider for a hosted scanner. This gateway does not control a model’s separate web browsing. <a href="/docs#architecture">See the diagram</a>.</p>
19
19
  <div id="upstreams"></div>
20
20
  <div id="hosted-server-choice" hidden>
21
21
  <h3>Where does the tool run?</h3>
@@ -25,7 +25,7 @@
25
25
  <h3>Use Burp or another tool on a tester’s computer</h3>
26
26
  <p>The hosted gateway cannot reach software on a laptop. Run a separate local gateway on that computer:</p>
27
27
  <ol><li>On the same computer as Burp, enable Burp’s MCP extension. Install Node.js 22 or newer.</li><li>Copy these commands into PowerShell:<pre><code id="local-command">npm install -g @integsec/agentic-pentest-proxy
28
- integsec-agentic-pentest-gateway</code></pre><button id="copy-local-command" class="secondary">Copy commands</button><p>The gateway prints a temporary admin token in PowerShell. Keep it private.</p></li><li>Open <code>http://127.0.0.1:9091/admin</code> on that computer and paste the printed token. Click <strong>Add server (off)</strong> beside Burp, then <strong>Turn on</strong>.</li><li>Download your approved engagement policy JSON from this team dashboard. On the laptop, import it, review and approve it, then select it under My engagement. Cloud changes do not automatically update the laptop.</li><li>Connect the MCP client to the local gateway. See the <a href="https://github.com/IntegSec/agentic-pentest-proxy/blob/master/docs/managed-gateway.md#connect-mcp-clients" target="_blank" rel="noopener noreferrer">Claude, ChatGPT, and local model instructions</a>.</li></ol>
28
+ integsec-agentic-pentest-gateway</code></pre><button id="copy-local-command" class="secondary">Copy commands</button><p>The gateway prints a temporary admin token in PowerShell. Keep it private.</p></li><li>Open <code>http://127.0.0.1:9091/admin</code> on that computer and paste the printed token. Click <strong>Add server (off)</strong> beside Burp, then <strong>Turn on</strong>.</li><li>Download your approved engagement policy JSON from this team dashboard. On the laptop, import it, review and approve it, then select it under My engagement. Cloud changes do not automatically update the laptop.</li><li>Connect the MCP client to the local gateway. See the <a href="/docs/managed-gateway#connect-mcp-clients">Claude, ChatGPT, and local model instructions</a>.</li></ol>
29
29
  </div>
30
30
  <div id="local-presets" hidden><h3>Local presets</h3><p>Adding a preset creates an entry in this local gateway. Install its software separately; new entries start off.</p><div id="presets"></div></div>
31
31
  <div id="add-server-panel" hidden>
@@ -0,0 +1,20 @@
1
+ <p class="eyebrow">Start here</p>
2
+ <h1>Which gateway should I use?</h1>
3
+ <p class="lede">Look at where the MCP tool runs. If Burp or another tool runs on your laptop, use a local gateway. If the tool is a reachable HTTPS MCP service, use the Cloudflare gateway. You can connect both to the same AI app as separate MCP connections.</p>
4
+ <div class="two-col" aria-label="Choose a gateway">
5
+ <section class="card choice"><span class="badge">On my computer</span><h2>Local gateway</h2><p>Install the npm package on the tester’s computer. It can talk to Burp, local CLI tools, and local model chat software on that computer.</p><p><strong>Use it for:</strong> Burp testing, laptop tools, isolated work, and targets reached through the tester’s VPN.</p><a href="#local-start">Set up local →</a></section>
6
+ <section class="card choice hosted"><span class="badge">On the internet</span><h2>Cloudflare gateway</h2><p>This is the team’s shared, signed-in endpoint. It manages users, approved engagements, assignments, and audit records. It connects AI clients to reachable remote HTTPS MCP servers.</p><p><strong>Use it for:</strong> team-managed access and remote MCP tools that do not need to run on a tester’s laptop.</p><a href="#hosted-start">Set up hosted →</a></section>
7
+ </div>
8
+ <h2 id="architecture">How the pieces connect</h2>
9
+ <p>In both paths, the gateway checks the selected engagement before forwarding a tool call. The tool itself makes the request to the test target.</p>
10
+ <figure class="flow local"><h3>Local path: Burp or a laptop tool</h3><ol><li>AI app<span>Claude Desktop or a local model chat UI; ChatGPT needs a secure tunnel</span></li><li>Gateway on laptop<span>Installed from npm; local scope copy</span></li><li>Burp or local MCP tool<span>Running on that laptop</span></li><li>Authorized target<span>Traffic leaves through laptop or its VPN</span></li></ol><figcaption class="caption">The Cloudflare gateway is not in this tool path. A hosted engagement can be downloaded and imported locally, but updates do not sync automatically.</figcaption></figure>
11
+ <figure class="flow hosted"><h3>Hosted path: remote HTTPS MCP tool</h3><ol><li>AI app<span>ChatGPT or Claude connects to the team URL</span></li><li>Cloudflare Access<span>Signs in and checks who may connect</span></li><li>Cloudflare gateway<span>Checks per-user engagement and records decisions</span></li><li>Remote MCP tool<span>A reachable HTTPS service</span></li><li>Authorized target<span>Traffic leaves from the remote tool’s host</span></li></ol><figcaption class="caption">The hosted gateway cannot start Burp or reach a listener on a tester’s laptop. It does not give the remote tool a Cloudflare source IP for its target traffic.</figcaption></figure>
12
+ <div class="note"><strong>The practical rule:</strong> Connect your AI app to the gateway beside the tool. The laptop gateway is for laptop tools. The hosted gateway is for remote HTTPS tools and shared team administration. If you need both kinds of tools, add both connections.</div>
13
+ <h2 id="local-start">Start with Burp on your laptop</h2>
14
+ <ol class="steps"><li>Enable Burp’s official MCP extension. Install Node.js 22 or newer.</li><li>Run <code>npm install -g @integsec/agentic-pentest-proxy</code>, then <code>integsec-agentic-pentest-gateway</code> in a terminal on that same laptop. Your configuration is saved in your per-user data folder, regardless of where the terminal starts.</li><li>Open <code>http://127.0.0.1:9091/admin</code>. Paste the admin token printed in the terminal. Add the Burp preset and turn it on.</li><li>Import the approved engagement JSON, review and approve it locally, and select it under <strong>My engagement</strong>. This step is manual for now.</li><li>Connect Claude Desktop through the local bridge, ChatGPT through a secure tunnel, or a local model chat UI directly to the local MCP endpoint.</li></ol>
15
+ <a class="button-link" href="/docs/managed-gateway#connect-mcp-clients">Client connection steps</a><a class="button-link secondary" href="/docs/tui">Terminal dashboard guide</a>
16
+ <h2 id="hosted-start">Start with a team connection</h2>
17
+ <ol class="steps"><li>Sign in to the <a href="/admin">team dashboard</a> through Cloudflare Access.</li><li>An admin adds your exact email, approves an engagement, assigns it to you, and turns on a compatible remote HTTPS MCP server.</li><li>Choose that engagement under <strong>My engagement</strong>. Your choice applies to your own MCP calls.</li><li>Connect ChatGPT or Claude to <code>https://agentic-proxy.pentestprepper.com/mcp</code> through its supported team connector.</li></ol>
18
+ <a class="button-link" href="/docs/managed-gateway">Managed gateway guide</a><a class="button-link secondary" href="/admin">Open dashboard</a>
19
+ <h2 id="reference">All documentation</h2>
20
+ <p>The guides in the left navigation cover installation, clients, scopes, the TUI, security limits, and development. Older release and design records are in <strong>Older design notes</strong>; use current guides for present-day behavior. The <a href="https://github.com/IntegSec/agentic-pentest-proxy">GitHub repository</a> contains the source, issues, and release history.</p>
@@ -0,0 +1,3 @@
1
+ export declare function docsPage(pathname: string): string | undefined;
2
+ export declare function docsImage(pathname: string): Buffer | undefined;
3
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/gateway/docs.ts"],"names":[],"mappings":"AAiFA,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU7D;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK9D"}
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <meta charset="utf-8">
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <title>{{TITLE}} · IntegSec MCP Gateway</title>
6
+ <style>
7
+ :root{font:16px/1.6 system-ui,sans-serif;color:#e8f0f2;background:#0b1218}*{box-sizing:border-box}body{margin:0}a{color:#71e2ce}a:hover{text-decoration-thickness:2px}a:focus-visible,summary:focus-visible{outline:3px solid #71e2ce;outline-offset:3px}header{background:#10202b;border-bottom:1px solid #294454;padding:15px max(20px,calc((100vw - 1440px)/2));display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}header .brand{font-weight:800;font-size:18px;color:#fff;text-decoration:none}header nav{display:flex;gap:18px;flex-wrap:wrap}header nav a[aria-current=page]{color:#fff;text-decoration-thickness:3px}.layout{max-width:1440px;margin:auto;display:grid;grid-template-columns:235px minmax(0,1fr);gap:36px;padding:30px 20px 80px}aside{align-self:start;position:sticky;top:20px}aside nav{display:grid;gap:4px}aside a{display:block;padding:5px 9px;text-decoration:none;border-radius:6px}aside a:hover,aside a[aria-current=page]{background:#1e3c48;color:#fff}aside h2{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:#93acb9;margin:22px 9px 4px}aside details{margin-top:15px;border-top:1px solid #294454;padding-top:12px}aside summary{cursor:pointer;color:#c5d9e2;font-size:14px}aside details p{font-size:12px;color:#93acb9}main{min-width:0;max-width:1060px}h1{font-size:clamp(29px,4vw,45px);line-height:1.16;margin:0 0 14px}h2{font-size:24px;line-height:1.25;margin:40px 0 14px}h3{font-size:18px;line-height:1.3;margin:25px 0 10px}p{margin:0 0 16px;color:#bdcdd5}.lede{font-size:19px;max-width:850px}.eyebrow{color:#72e0cb;text-transform:uppercase;letter-spacing:.11em;font-size:12px;font-weight:800;margin-bottom:8px}.card,.flow,.note,.archive-note{background:#14222c;border:1px solid #294454;border-radius:12px;padding:20px}.card h2{font-size:22px;margin:0 0 12px}.card h3,.flow h3{margin-top:0}.card p:last-child,.note p:last-child{margin-bottom:0}.two-col{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.choice{border-top:3px solid #2bbfa6}.choice.hosted{border-color:#70aefa}.badge{display:inline-block;border-radius:30px;background:#20544f;color:#baf6e8;padding:2px 10px;font-size:12px;font-weight:800;margin-bottom:10px}.hosted .badge{background:#234968;color:#c9e4ff}.flow{margin:18px 0}.flow.local{border-left:4px solid #2bbfa6}.flow.hosted{border-left:4px solid #70aefa}.flow ol{padding:0;margin:12px 0;list-style:none;display:flex;align-items:stretch;gap:22px}.flow li{position:relative;flex:1;min-width:0;background:#0d1b25;border:1px solid #395466;border-radius:8px;padding:13px;font-weight:700}.flow li:not(:last-child)::after{content:'→';position:absolute;right:-20px;top:50%;transform:translateY(-50%);color:#82dbc9}.flow li span{display:block;color:#9db7c5;font-weight:400;font-size:13px;margin-top:4px}.flow .caption{font-size:14px;margin:0}.note{border-left:4px solid #eac06b;margin:18px 0}.note strong{color:#ffe5ae}.steps{padding-left:24px}.steps li{margin:12px 0;padding-left:4px}.button-link{display:inline-block;border-radius:7px;background:#27bfa4;color:#06201a;font-weight:800;padding:9px 13px;text-decoration:none;margin:4px 9px 4px 0}.button-link.secondary{background:#304b5a;color:#e8f0f2}.markdown{max-width:900px}.markdown h1{font-size:36px}.markdown h2{border-top:1px solid #294454;padding-top:22px}.markdown p,.markdown li{color:#bdcdd5}.markdown pre{background:#0b1923;border:1px solid #395466;border-radius:8px;padding:14px;overflow:auto}.markdown code{font-size:.9em;color:#a5eada;overflow-wrap:anywhere}.markdown pre code{overflow-wrap:normal}.markdown blockquote{border-left:3px solid #6ca4a5;padding-left:16px;margin-left:0}.markdown table{border-collapse:collapse;display:block;overflow-x:auto;width:max-content;max-width:100%;font-size:14px}.markdown th,.markdown td{border:1px solid #395466;padding:8px 10px;vertical-align:top}.markdown th{background:#1b3441}.markdown img{max-width:100%;height:auto;border:1px solid #395466;border-radius:9px}.markdown ul,.markdown ol{padding-left:23px}.archive-note{border-left:4px solid #eac06b;margin-bottom:20px}.skip{position:absolute;left:-999px}.skip:focus{left:16px;top:12px;z-index:9;background:#fff;color:#000;padding:8px}@media(max-width:900px){.layout{display:block}aside{position:static;margin-bottom:30px;border-bottom:1px solid #294454;padding-bottom:20px}aside nav{display:flex;flex-wrap:wrap;align-items:center}aside h2{width:100%;margin:12px 9px 0}aside details{width:100%}.flow ol{display:grid;gap:21px}.flow li:not(:last-child)::after{content:'↓';right:auto;left:50%;top:auto;bottom:-22px;transform:translateX(-50%)}}@media(max-width:650px){.two-col{grid-template-columns:1fr}header nav{gap:12px}.layout{padding:22px 16px 55px}}
8
+ </style>
9
+ <a class="skip" href="#main">Skip to documentation</a>
10
+ <header><a class="brand" href="/docs">IntegSec MCP Gateway</a><nav aria-label="Site"><a href="/admin">Dashboard</a><a href="/docs" aria-current="page">Documentation</a><a href="https://github.com/IntegSec/agentic-pentest-proxy" rel="noopener noreferrer">GitHub repository ↗</a></nav></header>
11
+ <div class="layout"><aside>{{NAV}}</aside><main id="main">{{CONTENT}}</main></div>
12
+ </html>
@@ -0,0 +1,94 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, join, posix, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import MarkdownIt from "markdown-it";
5
+ const DOCS = [
6
+ { slug: "readme", path: "README.md", label: "Project overview" },
7
+ { slug: "managed-gateway", path: "docs/managed-gateway.md", label: "Managed gateway" },
8
+ { slug: "configuration", path: "docs/configuration.md", label: "Configuration and scopes" },
9
+ { slug: "integrations", path: "docs/integrations.md", label: "Clients and Docker" },
10
+ { slug: "tui", path: "docs/tui.md", label: "Terminal dashboard" },
11
+ { slug: "security", path: "docs/security.md", label: "Security and limitations" },
12
+ { slug: "development", path: "docs/development.md", label: "Development" },
13
+ { slug: "archive/release-readiness-0.2.6", path: "docs/release-readiness-0.2.6.md", label: "v0.2.6 release review", archived: true },
14
+ { slug: "archive/mcp-scope-proxy-plan", path: "docs/superpowers/plans/2026-03-26-mcp-scope-proxy.md", label: "Scope proxy plan", archived: true },
15
+ { slug: "archive/tui-monitor-design", path: "docs/superpowers/specs/2026-03-28-tui-monitor-design.md", label: "TUI design", archived: true },
16
+ { slug: "archive/tui-monitor-plan", path: "docs/superpowers/plans/2026-03-28-tui-monitor.md", label: "TUI plan", archived: true },
17
+ { slug: "archive/manifest-builder-design", path: "docs/superpowers/specs/2026-03-29-manifest-builder-design.md", label: "Manifest builder design", archived: true },
18
+ { slug: "archive/manifest-builder-plan", path: "docs/superpowers/plans/2026-03-29-manifest-builder.md", label: "Manifest builder plan", archived: true },
19
+ ];
20
+ const sourceDir = dirname(fileURLToPath(import.meta.url));
21
+ const packageRoot = [resolve(sourceDir, "../../.."), resolve(sourceDir, "../..")].find((candidate) => existsSync(join(candidate, "README.md")))
22
+ ?? (() => { throw new Error("Gateway documentation files are missing"); })();
23
+ const shell = readFileSync(new URL("./docs.html", import.meta.url), "utf8");
24
+ const home = readFileSync(new URL("./docs-home.html", import.meta.url), "utf8");
25
+ const bySlug = new Map(DOCS.map((doc) => [doc.slug, doc]));
26
+ const byPath = new Map(DOCS.map((doc) => [doc.path, doc]));
27
+ const markdown = new MarkdownIt({ html: false, linkify: true });
28
+ function escapeHtml(value) {
29
+ return value.replace(/[&<>"']/g, (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]);
30
+ }
31
+ function linkFor(href, sourcePath) {
32
+ if (href.startsWith("#"))
33
+ return href;
34
+ if (/^(?:https?:|mailto:)/i.test(href))
35
+ return href;
36
+ const [target, fragment] = href.split("#", 2);
37
+ const normalized = posix.normalize(posix.join(posix.dirname(sourcePath), target));
38
+ const doc = byPath.get(normalized);
39
+ if (doc)
40
+ return `/docs/${doc.slug}${fragment ? `#${fragment}` : ""}`;
41
+ if (normalized.startsWith("docs/images/") && /^tui-[a-z-]+\.png$/.test(posix.basename(normalized))) {
42
+ return `/docs/assets/${posix.basename(normalized)}`;
43
+ }
44
+ if (/^(?:\.\.|\/)/.test(normalized) || !/^[\w./-]+$/.test(normalized))
45
+ return "#";
46
+ return `https://github.com/IntegSec/agentic-pentest-proxy/blob/master/${normalized}${fragment ? `#${fragment}` : ""}`;
47
+ }
48
+ const defaultLink = markdown.renderer.rules.link_open;
49
+ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
50
+ const href = tokens[index].attrGet("href");
51
+ if (href)
52
+ tokens[index].attrSet("href", linkFor(href, env.sourcePath));
53
+ return defaultLink ? defaultLink(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
54
+ };
55
+ const defaultImage = markdown.renderer.rules.image;
56
+ markdown.renderer.rules.image = (tokens, index, options, env, self) => {
57
+ const src = tokens[index].attrGet("src");
58
+ if (src)
59
+ tokens[index].attrSet("src", linkFor(src, env.sourcePath));
60
+ return defaultImage ? defaultImage(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
61
+ };
62
+ markdown.renderer.rules.heading_open = (tokens, index, options, env, self) => {
63
+ const heading = tokens[index + 1].content.toLowerCase().normalize("NFKD")
64
+ .replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
65
+ const count = env.headingCounts.get(heading) ?? 0;
66
+ env.headingCounts.set(heading, count + 1);
67
+ tokens[index].attrSet("id", count ? `${heading}-${count}` : heading);
68
+ return self.renderToken(tokens, index, options);
69
+ };
70
+ function navigation(active) {
71
+ const link = (slug, label) => `<a href="/docs${slug ? `/${slug}` : ""}"${active === slug ? ' aria-current="page"' : ""}>${escapeHtml(label)}</a>`;
72
+ return `<nav aria-label="Documentation sections">${link("", "Start here")}<h2>Guides</h2>${DOCS.filter((doc) => !doc.archived).map((doc) => link(doc.slug, doc.label)).join("")}<details><summary>Older design notes</summary><p>Historical records may describe earlier behavior.</p>${DOCS.filter((doc) => doc.archived).map((doc) => link(doc.slug, doc.label)).join("")}</details></nav>`;
73
+ }
74
+ export function docsPage(pathname) {
75
+ const slug = pathname === "/docs" || pathname === "/docs/" ? "" : pathname.startsWith("/docs/") ? pathname.slice(6) : undefined;
76
+ if (slug === undefined)
77
+ return undefined;
78
+ const doc = slug ? bySlug.get(slug) : undefined;
79
+ if (slug && !doc)
80
+ return undefined;
81
+ const title = doc?.label ?? "How the proxy works";
82
+ const content = doc
83
+ ? `${doc.archived ? '<p class="archive-note">Historical design note. Use the current guides for setup and behavior.</p>' : ""}<article class="markdown">${markdown.render(readFileSync(join(packageRoot, doc.path), "utf8"), { sourcePath: doc.path, headingCounts: new Map() })}</article>`
84
+ : home;
85
+ return shell.replaceAll("{{TITLE}}", escapeHtml(title)).replace("{{NAV}}", navigation(slug)).replace("{{CONTENT}}", content);
86
+ }
87
+ export function docsImage(pathname) {
88
+ const name = /^\/docs\/assets\/(tui-[a-z-]+\.png)$/.exec(pathname)?.[1];
89
+ if (!name)
90
+ return undefined;
91
+ const path = join(packageRoot, "docs", "images", name);
92
+ return existsSync(path) ? readFileSync(path) : undefined;
93
+ }
94
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../src/gateway/docs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function defaultGatewayPaths(env?: NodeJS.ProcessEnv, home?: string, platform?: NodeJS.Platform): {
2
+ statePath: string;
3
+ auditDir: string;
4
+ };
5
+ /** Preserve state created by earlier releases when first switching to the stable per-user path. */
6
+ export declare function migrateLegacyGatewayState(statePath: string, launchDir?: string): boolean;
7
+ //# sourceMappingURL=local-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-paths.d.ts","sourceRoot":"","sources":["../../../src/gateway/local-paths.ts"],"names":[],"mappings":"AAIA,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,IAAI,SAAY,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CASjL;AAED,mGAAmG;AACnG,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,SAAgB,GAAG,OAAO,CAO/F"}
@@ -0,0 +1,30 @@
1
+ import { constants, copyFileSync, existsSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, posix, resolve, win32 } from "node:path";
4
+ export function defaultGatewayPaths(env = process.env, home = homedir(), platform = process.platform) {
5
+ const paths = platform === "win32" ? win32 : posix;
6
+ const base = platform === "win32"
7
+ ? paths.isAbsolute(env.LOCALAPPDATA ?? "") ? env.LOCALAPPDATA : paths.join(home, "AppData", "Local")
8
+ : platform === "darwin"
9
+ ? paths.join(home, "Library", "Application Support")
10
+ : paths.isAbsolute(env.XDG_STATE_HOME ?? "") ? env.XDG_STATE_HOME : paths.join(home, ".local", "state");
11
+ const appDir = paths.join(base, "IntegSec", "agentic-pentest-proxy");
12
+ return { statePath: paths.join(appDir, "gateway", "state.json"), auditDir: paths.join(appDir, "audit") };
13
+ }
14
+ /** Preserve state created by earlier releases when first switching to the stable per-user path. */
15
+ export function migrateLegacyGatewayState(statePath, launchDir = process.cwd()) {
16
+ const legacy = resolve(launchDir, "gateway", "state.json");
17
+ if (resolve(statePath) === legacy || !existsSync(legacy) || existsSync(statePath))
18
+ return false;
19
+ mkdirSync(dirname(statePath), { recursive: true });
20
+ try {
21
+ copyFileSync(legacy, statePath, constants.COPYFILE_EXCL);
22
+ }
23
+ catch (error) {
24
+ if (error.code === "EEXIST")
25
+ return false;
26
+ throw error;
27
+ }
28
+ return true;
29
+ }
30
+ //# sourceMappingURL=local-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-paths.js","sourceRoot":"","sources":["../../../src/gateway/local-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,EAAE,EAAE,WAA4B,OAAO,CAAC,QAAQ;IACtI,MAAM,KAAK,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IACnD,MAAM,IAAI,GAAG,QAAQ,KAAK,OAAO;QAC/B,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC;QACrG,CAAC,CAAC,QAAQ,KAAK,QAAQ;YACrB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC;YACpD,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAe,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7G,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;IACrE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;AAC3G,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,yBAAyB,CAAC,SAAiB,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;IACpF,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IAChG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC;QAAC,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAAC,CAAC;IACjE,OAAO,KAAK,EAAE,CAAC;QAAC,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAAC,MAAM,KAAK,CAAC;IAAC,CAAC;IACpG,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -61,7 +61,7 @@ export class GatewayRuntime {
61
61
  const connection = (async () => {
62
62
  if (cached)
63
63
  await cached.client.close().catch(() => undefined);
64
- const client = new Client({ name: "agentic-pentest-gateway", version: "0.3.4" });
64
+ const client = new Client({ name: "agentic-pentest-gateway", version: "0.3.6" });
65
65
  const transport = upstream.transport === "stdio"
66
66
  ? new StdioClientTransport({ command: upstream.command, args: upstream.args, stderr: "pipe" })
67
67
  : upstream.transport === "sse"
@@ -93,7 +93,7 @@ export class GatewayRuntime {
93
93
  });
94
94
  }
95
95
  createServer(actor, email) {
96
- const server = new Server({ name: "agentic-pentest-gateway", version: "0.3.4" }, {
96
+ const server = new Server({ name: "agentic-pentest-gateway", version: "0.3.6" }, {
97
97
  capabilities: { tools: { listChanged: true }, resources: {}, prompts: {} }, instructions: INSTRUCTIONS,
98
98
  });
99
99
  const config = loadConfig();
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAQpF,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAA8F,MAAM,YAAY,CAAC;AAOtI,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc;;;;;;EAkPpD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AASpF,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAA8F,MAAM,YAAY,CAAC;AAOtI,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc;;;;;;EAkQpD"}
@@ -6,6 +6,7 @@ import { isIP } from "node:net";
6
6
  import { z } from "zod";
7
7
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
8
8
  import { GatewayAuth } from "./auth.js";
9
+ import { docsImage, docsPage } from "./docs.js";
9
10
  import { GatewayRuntime } from "./runtime.js";
10
11
  import { GatewayStore, activeScope, normalizeUserEmail, parseScope, parseUpstream, parseUser, validateForApproval } from "./state.js";
11
12
  const MAX_BODY = 1024 * 1024;
@@ -155,6 +156,25 @@ export function createGateway(options) {
155
156
  res.end(js);
156
157
  return;
157
158
  }
159
+ if (pathname === "/" && req.method === "GET") {
160
+ res.writeHead(302, { Location: "/docs", "Cache-Control": "no-store" });
161
+ res.end();
162
+ return;
163
+ }
164
+ if (pathname.startsWith("/docs") && req.method === "GET") {
165
+ const page = docsPage(pathname);
166
+ const image = page ? undefined : docsImage(pathname);
167
+ if (page || image) {
168
+ if (accessMode) {
169
+ const session = await authenticate(req, res);
170
+ if (!session)
171
+ return;
172
+ }
173
+ res.writeHead(200, { "Content-Type": page ? "text/html; charset=utf-8" : "image/png", "Cache-Control": "public, max-age=300", "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; img-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'", "X-Content-Type-Options": "nosniff", "Referrer-Policy": "no-referrer" });
174
+ res.end(page ?? image);
175
+ return;
176
+ }
177
+ }
158
178
  if (!pathname.startsWith("/api/")) {
159
179
  json(res, 404, { error: "not found" });
160
180
  return;
@@ -378,6 +398,10 @@ export function createGateway(options) {
378
398
  json(res, 404, { error: "not found" });
379
399
  }
380
400
  catch (error) {
401
+ if (["EACCES", "EPERM", "EROFS"].includes(error?.code ?? "")) {
402
+ json(res, 500, { error: "Gateway data folder is not writable. Restart with GATEWAY_STATE_PATH and AUDIT_LOG_PATH set to writable folders." });
403
+ return;
404
+ }
381
405
  const message = error instanceof Error ? error.message : "Request failed";
382
406
  json(res, error instanceof z.ZodError || error instanceof SyntaxError ? 400 : 409, { error: message });
383
407
  }