agentgate-runtime-control 2.13.8

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 (75) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/LICENSE +21 -0
  3. package/README.md +534 -0
  4. package/SECURITY.md +19 -0
  5. package/bin/agentgate.js +303 -0
  6. package/docs/case-study-technical-validation.md +25 -0
  7. package/docs/case-study-template.md +37 -0
  8. package/docs/data-protection.md +49 -0
  9. package/docs/design-partner-checklist.md +32 -0
  10. package/docs/design-partner-kit.md +51 -0
  11. package/docs/design-partner-rollout.md +35 -0
  12. package/docs/design-partner.md +67 -0
  13. package/docs/external-security-review-test-pack.md +132 -0
  14. package/docs/external-security-review.md +33 -0
  15. package/docs/incident-response.md +54 -0
  16. package/docs/integration-matrix.md +17 -0
  17. package/docs/managed-postgres-acceptance-test.md +138 -0
  18. package/docs/marketing-plan.md +33 -0
  19. package/docs/observability-alerting.md +44 -0
  20. package/docs/outreach.md +26 -0
  21. package/docs/partner-intake-template.md +26 -0
  22. package/docs/performance-baseline.md +23 -0
  23. package/docs/performance.md +27 -0
  24. package/docs/pricing.md +53 -0
  25. package/docs/production-deployment.md +70 -0
  26. package/docs/production-quickstart.md +58 -0
  27. package/docs/production-readiness.md +29 -0
  28. package/docs/quickstart.md +115 -0
  29. package/docs/release-checklist.md +33 -0
  30. package/docs/security-hardening-release-report.md +69 -0
  31. package/docs/threat-model.md +47 -0
  32. package/docs/website-copy.md +44 -0
  33. package/examples/basic.mjs +14 -0
  34. package/examples/control-plane.mjs +17 -0
  35. package/examples/design-partner-refund.mjs +33 -0
  36. package/examples/design-partner-shadow.mjs +27 -0
  37. package/examples/mcp-gateway.mjs +26 -0
  38. package/examples/policy-bundle.mjs +18 -0
  39. package/examples/refund-agent.mjs +20 -0
  40. package/examples/runtime.mjs +12 -0
  41. package/package.json +49 -0
  42. package/schema/postgres.sql +17 -0
  43. package/src/admin-rbac.js +3 -0
  44. package/src/agentgate.js +85 -0
  45. package/src/approval.js +30 -0
  46. package/src/attack-lab.js +94 -0
  47. package/src/auth.js +27 -0
  48. package/src/behavior.js +146 -0
  49. package/src/control-plane.js +215 -0
  50. package/src/egress-guard.js +132 -0
  51. package/src/event-bus.js +10 -0
  52. package/src/identity.js +109 -0
  53. package/src/index.js +44 -0
  54. package/src/local-experience.js +46 -0
  55. package/src/mcp-gateway.js +383 -0
  56. package/src/mcp-scanner.js +45 -0
  57. package/src/middleware.js +17 -0
  58. package/src/multi-tenant.js +29 -0
  59. package/src/observability.js +395 -0
  60. package/src/oidc.js +38 -0
  61. package/src/persistent-store.js +56 -0
  62. package/src/policy-builder.js +74 -0
  63. package/src/policy-bundles.js +17 -0
  64. package/src/policy-engine.js +67 -0
  65. package/src/policy-packs.js +115 -0
  66. package/src/policy-registry.js +58 -0
  67. package/src/postgres-adapter.js +76 -0
  68. package/src/runtime.js +138 -0
  69. package/src/saas.js +67 -0
  70. package/src/security-report.js +42 -0
  71. package/src/security-validation.js +92 -0
  72. package/src/shadow-mode.js +47 -0
  73. package/src/telemetry.js +28 -0
  74. package/src/webhook-delivery.js +70 -0
  75. package/standalone.html +86 -0
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { createRequire } from 'node:module';
6
+ import { evaluate } from '../src/policy-engine.js';
7
+ import { createAgentGate } from '../src/agentgate.js';
8
+ import { createControlPlane } from '../src/control-plane.js';
9
+ import { runGatewayAttackLab, summarizeAttackResults } from '../src/attack-lab.js';
10
+ import { createMCPGateway } from '../src/mcp-gateway.js';
11
+ import { generateSecurityReport, renderSecurityReportHTML } from '../src/security-report.js';
12
+ import { createPolicyRegistry } from '../src/policy-registry.js';
13
+ import { TenantRegistry } from '../src/multi-tenant.js';
14
+ import { scanMCPTools, createToolTrustStore } from '../src/mcp-scanner.js';
15
+ import { guardEgress } from '../src/egress-guard.js';
16
+ import { validateAgentGateConfig, simulatePolicyMatrix, runDoctorChecks } from '../src/local-experience.js';
17
+ import { runSecurityValidation } from '../src/security-validation.js';
18
+ import { listPolicyPacks, getPolicyPack, getDefaultPolicyPack } from '../src/policy-packs.js';
19
+ import { analyzeShadowEvents } from '../src/shadow-mode.js';
20
+
21
+ const require = createRequire(import.meta.url);
22
+ const PACKAGE_VERSION = require('../package.json').version;
23
+
24
+ const [cmd, action='read', amount='0'] = process.argv.slice(2);
25
+ const showHelp = () => console.log(`AgentGate ${PACKAGE_VERSION} — Runtime Control Plane
26
+
27
+ Usage:
28
+ agentgate init
29
+ agentgate dev [--port <port>]
30
+ agentgate test <action> [amount]
31
+ agentgate attack
32
+ agentgate attack-ci
33
+ agentgate report
34
+ agentgate scan <tools.json> [--strict]
35
+ agentgate egress <response.json> [--strict]
36
+ agentgate policy <create|list|test|activate|rollback|diff> <name> ...
37
+ agentgate tenant <create|list|key|revoke|rotate> ...
38
+ agentgate --help
39
+ agentgate doctor
40
+ agentgate simulate
41
+ agentgate validate-security
42
+ agentgate pack <list|show|init|test> [pack-id]
43
+ agentgate shadow <events.json>
44
+ agentgate partner init [pack]
45
+ agentgate partner check <report.json>
46
+ agentgate demo refund
47
+ agentgate --help
48
+ agentgate --version`);
49
+ if (cmd === '--help' || cmd === '-h' || cmd === 'help') { showHelp(); process.exit(0); }
50
+ if (cmd === '--version' || cmd === '-v' || cmd === 'version') { console.log(PACKAGE_VERSION); process.exit(0); }
51
+
52
+ if (cmd === 'pack') {
53
+ const sub = process.argv[3] || 'list';
54
+ if (sub === 'list') console.log(JSON.stringify(listPolicyPacks(), null, 2));
55
+ else if (sub === 'show') {
56
+ const id = process.argv[4] || 'support-refund-safety';
57
+ const pack = getPolicyPack(id);
58
+ if (!pack) { console.error(`Unknown policy pack: ${id}`); process.exitCode = 1; }
59
+ else console.log(JSON.stringify(pack, null, 2));
60
+ } else if (sub === 'init') {
61
+ const id = process.argv[4] || 'support-refund-safety';
62
+ const pack = getPolicyPack(id);
63
+ if (!pack) { console.error(`Unknown policy pack: ${id}`); process.exitCode = 1; }
64
+ else {
65
+ const file = path.resolve(process.cwd(), 'agentgate.config.mjs');
66
+ const content = `import { createAgentGate, getPolicyPack } from 'agentgate-runtime-control';
67
+
68
+ const pack = getPolicyPack('${pack.id}');
69
+
70
+ export const agentgate = createAgentGate({
71
+ agent: 'SupportAgent',
72
+ mode: 'enforce',
73
+ policies: pack.policies
74
+ });
75
+
76
+ export { pack };
77
+ `;
78
+ try { await fs.access(file); console.error('agentgate.config.mjs already exists'); process.exitCode = 1; }
79
+ catch { await fs.writeFile(file, content, 'utf8'); console.log(`Created ${file} from ${pack.name} (enforce mode)`); }
80
+ }
81
+ } else if (sub === 'test') {
82
+ const id = process.argv[4] || 'support-refund-safety';
83
+ const pack = getPolicyPack(id);
84
+ if (!pack) { console.error(`Unknown policy pack: ${id}`); process.exitCode = 1; }
85
+ else {
86
+ const results = simulatePolicyMatrix({ policies: pack.policies, cases: pack.cases });
87
+ const passed = results.filter((x, i) => x.decision === pack.cases[i].expected).length;
88
+ console.log(JSON.stringify({ pack: pack.id, total: results.length, passed, failed: results.length - passed, results }, null, 2));
89
+ if (passed !== results.length) process.exitCode = 2;
90
+ }
91
+ } else { console.error('Usage: agentgate pack <list|show|init|test> [pack-id]'); process.exitCode = 1; }
92
+ } else if (cmd === 'demo' && process.argv[3] === 'refund') {
93
+ const pack = getDefaultPolicyPack();
94
+ const gate = createAgentGate({ agent: 'SupportAgent', mode: 'enforce', policies: pack.policies });
95
+ let executions = 0;
96
+ const refund = gate.protect(async input => { executions += 1; return { refunded: input.amount, customerId: input.customerId }; }, { tool: 'refund', action: 'refund' });
97
+ console.log(`\nAgentGate — ${pack.name} v${pack.version}`);
98
+ console.log('Policy: refund → ASK | > $5,000 → BLOCK | invalid amounts → BLOCK');
99
+ for (const [amount, label] of [[250, 'small-refund'], [1200, 'review-refund'], [5000.01, 'over-ceiling'], ['5000.01', 'invalid-string']]) {
100
+ try {
101
+ const result = await refund({ amount, customerId: 'demo_customer' }, { amount });
102
+ console.log(JSON.stringify({ case: label, amount, status: result.status, decision: result.agentgate?.decision, winningRule: result.agentgate?.winningRule, executionCount: executions }));
103
+ } catch (error) {
104
+ console.log(JSON.stringify({ case: label, amount, status: 'blocked', decision: error.agentgate?.decision, winningRule: error.agentgate?.winningRule, executionCount: executions }));
105
+ }
106
+ }
107
+ console.log(JSON.stringify({ proof: 'blocked actions did not execute', refundExecutions: executions }, null, 2));
108
+ } else if (cmd === 'doctor') {
109
+ const configPath = path.resolve(process.cwd(), 'agentgate.config.mjs');
110
+ let config = { mode: 'enforce', policies: { productionBlock: true, autoApproveAmount: 500, approvalAmount: 5000 }, authRequired: true };
111
+ try { const mod = await import(`file://${configPath}?doctor=${Date.now()}`); const gate = mod.agentgate || {}; config = { ...config, ...(mod.config || {}), ...(gate.config || {}), ...(gate.mode ? { mode: gate.mode } : {}), ...(gate.policies ? { policies: gate.policies } : {}) }; } catch {}
112
+ const report = runDoctorChecks({ config });
113
+ console.log(JSON.stringify(report, null, 2)); process.exitCode = report.ok ? 0 : 2;
114
+ } else if (cmd === 'simulate') {
115
+ const policy = { productionBlock: true, autoApproveAmount: 500, approvalAmount: 5000 };
116
+ console.log(JSON.stringify(simulatePolicyMatrix({ policies: policy }), null, 2));
117
+ } else if (cmd === 'partner') {
118
+ const sub = process.argv[3] || 'help';
119
+ if (sub === 'init') {
120
+ const packId = process.argv[4] || 'support-refund-safety';
121
+ const pack = getPolicyPack(packId);
122
+ if (!pack) { console.error(`Unknown policy pack: ${packId}`); process.exitCode = 1; }
123
+ else {
124
+ const dir = path.resolve(process.cwd(), 'design-partner');
125
+ await fs.mkdir(dir, { recursive: true });
126
+ const files = {
127
+ 'partner-intake.md': `# Design Partner Intake\n\n- Partner: \n- Agent: \n- Sensitive tool: \n- Environment: sandbox / replay / production\n- Identity/tenant model: \n- Existing authorization: \n- Side effects: \n- Contact: \n\n## Success criteria\n- BLOCK -> 0 handler execution\n- ASK -> 0 pre-approval execution\n- Approved ASK -> exactly 1 execution\n- Cross-tenant access -> 0 leaks\n- Egress secret leakage -> 0 undetected test cases\n- Audit mismatch -> 0\n`,
128
+ 'pilot-plan.md': `# Design Partner Pilot Plan\n\n## Phase 1 — Sandbox / Replay\nInstall the real AgentGate package and replay representative traffic.\n\n## Phase 2 — Shadow\nRecord proposed ALLOW/ASK/BLOCK decisions while existing execution continues. Review every mismatch.\n\n## Phase 3 — Enforce one tool\nEnable enforcement only after the shadow report is safe and the approval boundary has been tested.\n\n## Phase 4 — Evidence\nPreserve Run, winningRule, ruleTrace, execution outcome, egress findings, and Replay evidence.\n\n## Exit\nMove to production only when all acceptance criteria are green and the partner approves the evidence.\n`,
129
+ 'acceptance-scorecard.md': `# Design Partner Acceptance Scorecard\n\n| Gate | Target | Result |\n|---|---|---|\n| BLOCK side effects | 0 | |\n| ASK pre-approval execution | 0 | |\n| Approved execution | exactly 1 | |\n| Cross-tenant leaks | 0 | |\n| Undetected egress secrets | 0 | |\n| Audit mismatch | 0 | |\n| Restart/Replay | PASS | |\n| First protected tool | < 10 min target | |\n\nDo not mark the pilot production-ready while any critical gate is unresolved.\n`,
130
+ 'exit-report.md': `# Design Partner Exit Report\n\n## Outcome\n- Status: pending / ready / blocked\n- Policy Pack: ${pack.id}\n- Agent: \n- Sensitive tool: \n\n## Evidence\n- Shadow report: \n- Attack report: \n- Replay run IDs: \n- Restart verification: \n\n## Before / After\n| Metric | Before | AgentGate |\n|---|---:|---:|\n| Dangerous actions reaching handler | | |\n| Pre-approval executions | | |\n| Duplicate approvals | | |\n| Audit mismatches | | |\n| Undetected egress findings | | |\n\n## Limitations\n\n`
131
+ };
132
+ for (const [name, content] of Object.entries(files)) await fs.writeFile(path.join(dir, name), content, 'utf8');
133
+ console.log(`Created ${dir} for ${pack.name}`);
134
+ }
135
+ } else if (sub === 'check') {
136
+ const file = process.argv[4];
137
+ if (!file) { console.error('Usage: agentgate partner check <report.json>'); process.exitCode = 1; }
138
+ else {
139
+ const report = JSON.parse(await fs.readFile(path.resolve(file), 'utf8'));
140
+ const gates = {
141
+ blockSideEffectsZero: report.blockSideEffects === 0,
142
+ askPreApprovalZero: report.askPreApprovalExecutions === 0,
143
+ approvedExactlyOnce: report.approvedExecutions === 1,
144
+ crossTenantZero: report.crossTenantLeaks === 0,
145
+ egressUndetectedZero: report.undetectedEgressSecrets === 0,
146
+ auditMismatchZero: report.auditMismatches === 0,
147
+ replayAfterRestart: report.replayAfterRestart === true
148
+ };
149
+ const failed = Object.entries(gates).filter(([, ok]) => !ok).map(([name]) => name);
150
+ console.log(JSON.stringify({ ready: failed.length === 0, gates, failed }, null, 2));
151
+ process.exitCode = failed.length ? 2 : 0;
152
+ }
153
+ } else {
154
+ console.error('Usage: agentgate partner <init|check> ...'); process.exitCode = 1;
155
+ }
156
+ } else if (cmd === 'shadow') {
157
+ const file = process.argv[3];
158
+ if (!file) { console.error('Usage: agentgate shadow <events.json>'); process.exitCode = 1; }
159
+ else {
160
+ const input = JSON.parse(await fs.readFile(path.resolve(file), 'utf8'));
161
+ const events = Array.isArray(input) ? input : (input.events || []);
162
+ const report = analyzeShadowEvents(events);
163
+ console.log(JSON.stringify(report, null, 2));
164
+ if (!report.safeForEnforcement) process.exitCode = 2;
165
+ }
166
+ } else if (cmd === 'validate-security') {
167
+ const report = await runSecurityValidation();
168
+ console.log(JSON.stringify(report, null, 2)); process.exitCode = report.ok ? 0 : 2;
169
+ } else if (cmd === 'scan') {
170
+ const file = process.argv[3];
171
+ if (!file) { console.error('Usage: agentgate scan <tools.json> [--strict]'); process.exitCode=1; }
172
+ else { const input=JSON.parse(await fs.readFile(path.resolve(file),'utf8')); const result=scanMCPTools(Array.isArray(input)?input:(input.tools||[])); console.log(JSON.stringify(result,null,2)); if(process.argv.includes('--strict') && result.summary.high>0) process.exitCode=2; }
173
+ } else if (cmd === 'egress') {
174
+ const file = process.argv[3];
175
+ if (!file) { console.error('Usage: agentgate egress <response.json> [--strict]'); process.exitCode = 1; }
176
+ else {
177
+ const input = JSON.parse(await fs.readFile(path.resolve(file), 'utf8'));
178
+ const result = guardEgress(input);
179
+ console.log(JSON.stringify(result, null, 2));
180
+ if (process.argv.includes('--strict') && result.action === 'BLOCK') process.exitCode = 2;
181
+ }
182
+ } else if (cmd === 'attack-ci') {
183
+ const gateway = createMCPGateway({ mode:'enforce', policies:{productionBlock:true}, tools:[{name:'export_all',handler:async()=>({})},{name:'update_production',handler:async()=>({})},{name:'delete',handler:async()=>({})},{name:'refund',handler:async()=>({})},{name:'publish',handler:async()=>({})}] });
184
+ const results=await runGatewayAttackLab(gateway); const summary=summarizeAttackResults(results); console.log(JSON.stringify({summary,results},null,2)); process.exitCode=summary.failed?2:0;
185
+ } else if (cmd === 'test' || cmd === 'check') {
186
+ console.log(JSON.stringify(evaluate({ action, amount: Number(amount) }), null, 2));
187
+ } else if (cmd === 'attack') {
188
+ const gateway = createMCPGateway({
189
+ mode: 'enforce',
190
+ policies: { productionBlock: true },
191
+ tools: [
192
+ { name: 'export_all', handler: async () => ({ executed: true }) },
193
+ { name: 'update_production', handler: async () => ({ executed: true }) },
194
+ { name: 'delete', handler: async () => ({ executed: true }) },
195
+ { name: 'refund', handler: async args => ({ refunded: args.amount }) },
196
+ { name: 'publish', handler: async () => ({ executed: true }) }
197
+ ]
198
+ });
199
+ const results = await runGatewayAttackLab(gateway);
200
+ const summary = summarizeAttackResults(results);
201
+ console.log('\nAgentGate Attack Runner');
202
+ console.table(results.map(x => ({ test: x.name, decision: x.decision, risk: x.risk, passed: x.passed, runId: x.runId })));
203
+ console.log('Summary:', JSON.stringify(summary));
204
+ process.exitCode = summary.failed ? 2 : 0;
205
+ } else if (cmd === 'report') {
206
+ const gateway = createMCPGateway({
207
+ mode: 'enforce',
208
+ policies: { productionBlock: true },
209
+ tools: [
210
+ { name: 'export_all', handler: async () => ({ executed: true }) },
211
+ { name: 'update_production', handler: async () => ({ executed: true }) },
212
+ { name: 'delete', handler: async () => ({ executed: true }) },
213
+ { name: 'refund', handler: async args => ({ refunded: args.amount }) },
214
+ { name: 'publish', handler: async () => ({ executed: true }) }
215
+ ]
216
+ });
217
+ const attacks = await runGatewayAttackLab(gateway);
218
+ const report = generateSecurityReport({ attackResults: attacks, runs: gateway.runs(), policies: { productionBlock: true }, metadata: { agent: 'Attack Runner', environment: 'production' } });
219
+ const jsonPath = path.resolve(process.cwd(), 'agentgate-security-report.json');
220
+ const htmlPath = path.resolve(process.cwd(), 'agentgate-security-report.html');
221
+ await fs.writeFile(jsonPath, JSON.stringify(report, null, 2), 'utf8');
222
+ await fs.writeFile(htmlPath, renderSecurityReportHTML(report), 'utf8');
223
+ console.log(`Security report: ${report.summary.status}`);
224
+ console.log(`JSON: ${jsonPath}`);
225
+ console.log(`HTML: ${htmlPath}`);
226
+ process.exitCode = report.summary.failed ? 2 : 0;
227
+ } else if (cmd === 'policy') {
228
+ const sub = process.argv[3] || 'list';
229
+ const name = process.argv[4] || 'default';
230
+ const registry = createPolicyRegistry({ filePath: path.resolve(process.cwd(), '.agentgate/policies.json') });
231
+ if (sub === 'create') {
232
+ const policy = JSON.parse(process.argv[5] || '{}');
233
+ console.log(JSON.stringify(registry.create(name, policy), null, 2));
234
+ } else if (sub === 'list') {
235
+ console.log(JSON.stringify(registry.list(name), null, 2));
236
+ } else if (sub === 'diff') {
237
+ console.log(JSON.stringify(registry.diff(name, Number(process.argv[5]), Number(process.argv[6])), null, 2));
238
+ } else if (sub === 'test') {
239
+ const version = Number(process.argv[5]);
240
+ const cases = JSON.parse(process.argv[6] || '[]');
241
+ console.log(JSON.stringify(registry.test(name, version, cases), null, 2));
242
+ } else if (sub === 'activate' || sub === 'rollback') {
243
+ const version = Number(process.argv[5]);
244
+ const result = sub === 'activate' ? registry.activate(name, version) : registry.rollback(name, version);
245
+ console.log(JSON.stringify(result, null, 2));
246
+ } else {
247
+ console.error('Usage: agentgate policy <create|list|test|activate|rollback|diff> <name> ...');
248
+ process.exitCode = 1;
249
+ }
250
+ } else if (cmd === 'tenant') {
251
+ const sub = process.argv[3] || 'list';
252
+ const registry = new TenantRegistry({ filePath: path.resolve(process.cwd(), '.agentgate/tenants.json'), keyPath: path.resolve(process.cwd(), '.agentgate/api-keys.json') });
253
+ if (sub === 'create') console.log(JSON.stringify(registry.create(process.argv[4] || 'workspace'), null, 2));
254
+ else if (sub === 'list') console.log(JSON.stringify(registry.list(), null, 2));
255
+ else if (sub === 'key') {
256
+ const tenantId = process.argv[4]; const scopes = (process.argv[5] || 'runs:read').split(',');
257
+ console.log(JSON.stringify(registry.issueKey(tenantId, { scopes }), null, 2));
258
+ } else if (sub === 'revoke') console.log(JSON.stringify(registry.revoke(process.argv[4]), null, 2));
259
+ else if (sub === 'rotate') console.log(JSON.stringify(registry.rotate(process.argv[4]), null, 2));
260
+ else { console.error('Usage: agentgate tenant <create|list|key|revoke|rotate> ...'); process.exitCode = 1; }
261
+ } else if (cmd === 'init') {
262
+ const packIndex = process.argv.indexOf('--pack');
263
+ const packId = packIndex >= 0 ? process.argv[packIndex + 1] : null;
264
+ const pack = packId ? getPolicyPack(packId) : null;
265
+ if (packId && !pack) { console.error(`Unknown policy pack: ${packId}`); process.exitCode = 1; }
266
+ else {
267
+ const file = path.resolve(process.cwd(), 'agentgate.config.mjs');
268
+ const content = pack
269
+ ? `import { createAgentGate, getPolicyPack } from 'agentgate-runtime-control';\n\nconst pack = getPolicyPack('${pack.id}');\n\nexport const agentgate = createAgentGate({\n agent: 'SupportAgent',\n mode: 'observe',\n policies: pack.policies\n});\n\nexport { pack };\n`
270
+ : `import { createAgentGate } from 'agentgate-runtime-control';\n\nexport const agentgate = createAgentGate({\n agent: 'MyAgent',\n mode: 'enforce',\n policies: {\n productionBlock: true,\n autoApproveAmount: 500,\n approvalAmount: 5000\n }\n});\n`;
271
+ try { await fs.access(file); console.error('agentgate.config.mjs already exists'); process.exitCode = 1; }
272
+ catch { await fs.writeFile(file, content, 'utf8'); console.log(`Created ${file}${pack ? ` from ${pack.name} (enforce mode)` : ''}`); }
273
+ }
274
+ } else if (cmd === 'dev') {
275
+ const htmlPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../standalone.html');
276
+ const html = await fs.readFile(htmlPath, 'utf8');
277
+ const gate = createAgentGate({ agent: 'DemoAgent', mode: 'enforce', policies: { productionBlock: true } });
278
+ const gateway = gate.withMCP({ tools: [
279
+ { name: 'read', handler: async args => ({ ok: true, data: args, simulated: true, environment: 'demo' }) },
280
+ { name: 'refund', handler: async args => ({ refunded: args.amount, simulated: true, environment: 'demo' }) },
281
+ { name: 'delete', handler: async args => ({ deleted: args.id, simulated: true, environment: 'demo' }) },
282
+ { name: 'export_all', handler: async args => ({ simulated: true, environment: 'demo', action: 'export_all', args }) },
283
+ { name: 'update_production', handler: async args => ({ simulated: true, environment: 'demo', action: 'update_production', args }) },
284
+ { name: 'publish', handler: async args => ({ simulated: true, environment: 'demo', action: 'publish', args }) }
285
+ ]});
286
+ await gateway.handle({ jsonrpc:'2.0', id:1, method:'tools/call', params:{ name:'read', arguments:{ id:'demo_customer' }, agent:'DemoAgent', action:'read', environment:'development' }});
287
+ await gateway.handle({ jsonrpc:'2.0', id:2, method:'tools/call', params:{ name:'refund', arguments:{ amount:1200, customerId:'demo_customer' }, agent:'DemoAgent', action:'refund', environment:'development' }});
288
+ await gateway.handle({ jsonrpc:'2.0', id:3, method:'tools/call', params:{ name:'delete', arguments:{ id:'demo_customer' }, agent:'DemoAgent', action:'delete', environment:'production' }});
289
+ const portArgIndex = process.argv.indexOf('--port');
290
+ const port = Number(portArgIndex >= 0 ? process.argv[portArgIndex + 1] : process.env.PORT || 8787);
291
+ if (!Number.isInteger(port) || port < 1 || port > 65535) { console.error('Invalid port. Use --port <1-65535> or PORT=<port>.'); process.exitCode = 1; }
292
+ else {
293
+ const { server } = createControlPlane({ gateway, html, localDevSession: true });
294
+ server.on('error', error => {
295
+ if (error?.code === 'EADDRINUSE') console.error(`Port ${port} is already in use. Use agentgate dev --port <port> or PORT=<port>.`);
296
+ else console.error(`AgentGate dev server error: ${error?.message || error}`);
297
+ process.exitCode = 1;
298
+ });
299
+ server.listen(port, () => console.log(`AgentGate Control Plane: http://localhost:${port}`));
300
+ }
301
+ } else {
302
+ showHelp();
303
+ }
@@ -0,0 +1,25 @@
1
+ # AgentGate Technical Validation — 2.13.0
2
+
3
+ > This is a technical validation report, not a customer case study. It must not be presented as customer evidence.
4
+
5
+ > The 2.13.6 release retains this validated runtime baseline and adds first-client hardening; this document describes the historical 2.13.0 validation evidence.
6
+
7
+ ## Scope
8
+ AgentGate 2.13.0 was tested from an independent consumer project using a real npm tarball, without relying on the package source tree.
9
+
10
+ ## Results
11
+ - Design Partner workflow: 19/19 checks passed.
12
+ - Three Policy Packs were discoverable and contained policies/test cases.
13
+ - Shadow mode recorded proposed decisions and mismatch/readiness fields.
14
+ - ASK produced zero pre-approval executions; approved ASK executed exactly once.
15
+ - Live, Run and Replay evidence matched on `winningRule` and `ruleTrace`.
16
+ - Restart preserved blocked Run and Replay evidence.
17
+ - Cross-tenant access returned 403.
18
+ - Egress controls blocked raw credentials and applied configured redaction.
19
+ - 10,000 concurrent destructive attempts produced 10,000 BLOCK decisions and zero executions.
20
+
21
+ ## What this proves
22
+ The tested runtime control boundary can be demonstrated with deterministic evidence. It does not prove that AgentGate prevents every AI security failure, replaces IAM, or provides legal/compliance certification.
23
+
24
+ ## Customer case study policy
25
+ A customer case study must only be published after a real partner has completed Shadow → Enforce and approved publication of the relevant metrics and quotes.
@@ -0,0 +1,37 @@
1
+ # AgentGate Case Study Template
2
+
3
+ ## 1. Agent and workflow
4
+ - Agent:
5
+ - Sensitive tool:
6
+ - Environment:
7
+ - Existing authorization:
8
+
9
+ ## 2. Baseline
10
+ - Requests tested:
11
+ - Risky actions observed:
12
+ - Existing approval path:
13
+ - Existing audit evidence:
14
+
15
+ ## 3. AgentGate deployment
16
+ - Policy Pack:
17
+ - Mode: shadow / enforce
18
+ - Integration time:
19
+ - Policies changed during pilot:
20
+
21
+ ## 4. Results
22
+ | Metric | Before | With AgentGate |
23
+ |---|---:|---:|
24
+ | Dangerous actions reaching handler | | |
25
+ | Pre-approval executions | | |
26
+ | Duplicate approvals | | |
27
+ | Audit mismatches | | |
28
+ | Undetected egress findings | | |
29
+
30
+ ## 5. Evidence
31
+ - Replay run IDs:
32
+ - Winning rules:
33
+ - Attack scenarios:
34
+ - Partner-approved screenshots/logs:
35
+
36
+ ## 6. Limitations
37
+ Document what AgentGate did not protect and what remained under application/IAM/provider controls.
@@ -0,0 +1,49 @@
1
+ # Data Protection, Retention, Backup and Restore
2
+
3
+ ## Scope
4
+
5
+ AgentGate can persist runs, approvals, policy metadata and audit evidence. The application owner is responsible for classifying the data and choosing the retention period appropriate to the workload.
6
+
7
+ ## Retention
8
+
9
+ The in-process/local stores enforce bounded retention. Configure the production database retention separately; do not treat the local `maxRuns` limit as a compliance retention policy.
10
+
11
+ Recommended operational baseline for a pilot:
12
+
13
+ - Hot audit/run data: 30 days.
14
+ - Exported security evidence: retain according to the customer's compliance requirement.
15
+ - Approvals: retain with the associated audit record for the same period unless a stricter requirement applies.
16
+
17
+ These are deployment defaults, not legal advice; customers must set their own policy.
18
+
19
+ ## Encryption
20
+
21
+ - TLS for AgentGate-to-database and user-to-Control-Plane traffic.
22
+ - Encrypt database storage using the cloud/database provider's encryption-at-rest controls.
23
+ - Encrypt backups using provider-managed or customer-managed keys according to the customer's requirements.
24
+ - Never put API keys, bearer tokens, database credentials, or private keys into policy definitions, browser bundles, or exported audit files unless explicitly required and protected.
25
+
26
+ ## Backup
27
+
28
+ For PostgreSQL, enable automated provider backups and point-in-time recovery where available. For higher assurance, keep an independent backup/export according to the customer's RPO.
29
+
30
+ Minimum pilot procedure:
31
+
32
+ 1. Take/verify a database backup.
33
+ 2. Record backup timestamp and database schema version.
34
+ 3. Restore into an isolated database.
35
+ 4. Run tenant-isolation, replay, approval, and audit-read tests.
36
+ 5. Record restore duration.
37
+
38
+ ## Restore acceptance targets
39
+
40
+ The deployment owner should explicitly choose:
41
+
42
+ - RPO: maximum acceptable data loss.
43
+ - RTO: maximum acceptable recovery time.
44
+
45
+ AgentGate does not claim a universal RPO/RTO because those values depend on the customer's database and infrastructure.
46
+
47
+ ## Deletion
48
+
49
+ Customer data deletion must be performed at the database layer according to the tenant/data-retention policy. Verify that backups and exported evidence follow the same contractual deletion requirements.
@@ -0,0 +1,32 @@
1
+ # Design Partner Checklist
2
+
3
+ ## Before integration
4
+ - [ ] One real agent selected
5
+ - [ ] One sensitive tool selected
6
+ - [ ] Tool side effects documented
7
+ - [ ] Identity/tenant model documented
8
+ - [ ] Sandbox or replay data available
9
+ - [ ] Success criteria agreed
10
+
11
+ ## Shadow phase
12
+ - [ ] AgentGate installed from a real package
13
+ - [ ] Policy Pack selected
14
+ - [ ] Decisions recorded
15
+ - [ ] Actual outcomes captured
16
+ - [ ] Would-block executions reviewed
17
+ - [ ] False positives reviewed
18
+ - [ ] False negatives reviewed
19
+
20
+ ## Enforcement phase
21
+ - [ ] Low-risk tool passed shadow review
22
+ - [ ] Sensitive tool has explicit approval boundary
23
+ - [ ] BLOCK execution = 0 in test
24
+ - [ ] ASK pre-approval execution = 0 in test
25
+ - [ ] Approved execution = 1 in test
26
+ - [ ] Replay survives restart
27
+
28
+ ## Exit criteria
29
+ - [ ] Partner accepts production use
30
+ - [ ] Second workflow requested or demonstrated
31
+ - [ ] Evidence can support a case study
32
+ - [ ] No unresolved critical audit mismatch
@@ -0,0 +1,51 @@
1
+ # AgentGate Design Partner Kit
2
+
3
+ This kit is the controlled operating package for a 3–5 partner pilot. It is not a general security or compliance program.
4
+
5
+ ## 1. Select one workflow
6
+
7
+ Start with one agent and one side-effecting tool. Recommended first workflow: Support Refund Safety.
8
+
9
+ - Agent: support/operations agent
10
+ - Sensitive tool: `refund`
11
+ - Initial environment: sandbox or replay
12
+ - Policy Pack: `support-refund-safety`
13
+
14
+ ## 2. Run the five-step pilot
15
+
16
+ 1. **Intake** — document the agent, tool, side effects, identity/tenant model, and existing authorization.
17
+ 2. **Sandbox / replay** — install AgentGate from the real package and replay representative traffic.
18
+ 3. **Shadow** — record proposed decisions and compare them with actual execution. Do not enforce until mismatches are reviewed.
19
+ 4. **Enforce** — enable one sensitive tool only after the acceptance gates pass.
20
+ 5. **Evidence / exit** — preserve Run, winningRule, ruleTrace, execution result, egress findings, and Replay evidence; complete the exit report.
21
+
22
+ ## 3. Acceptance gates
23
+
24
+ - `BLOCK -> handler execution = 0`
25
+ - `ASK -> pre-approval execution = 0`
26
+ - approved `ASK -> exactly 1 execution`
27
+ - cross-tenant access -> `0` leaks
28
+ - undetected egress secret findings -> `0`
29
+ - audit mismatch -> `0`
30
+ - restart/replay -> PASS
31
+ - first protected tool -> target under 10 minutes
32
+
33
+ ## 4. Partner evidence package
34
+
35
+ Every pilot should produce:
36
+
37
+ - policy pack and test cases
38
+ - shadow report
39
+ - attack results
40
+ - enforcement results
41
+ - approval evidence
42
+ - replay run IDs
43
+ - restart verification
44
+ - before/after metrics
45
+ - limitations and unresolved controls
46
+
47
+ ## 5. Exit decision
48
+
49
+ A pilot is **ready** only when every critical gate is green and the partner explicitly accepts the evidence. Otherwise keep the tool in shadow mode and resolve the failing gate.
50
+
51
+ AgentGate does not claim to prevent every prompt-injection technique and does not replace application authorization, IAM, network isolation, or provider controls.
@@ -0,0 +1,35 @@
1
+ # AgentGate Design Partner Rollout
2
+
3
+ This is the controlled path from a tested AgentGate build to a production candidate.
4
+ It is intentionally narrower than a general AI-security launch.
5
+
6
+ ## Ten-stage rollout
7
+
8
+ 1. **Freeze a tested baseline** — start from a release that passed an external consumer-project test.
9
+ 2. **Fast first protection** — install, initialize, simulate, attack, and protect one tool without building a control plane first.
10
+ 3. **Policy Pack** — start with one job-specific pack and declared test cases.
11
+ 4. **Shadow Mode** — record what AgentGate would ALLOW/ASK/BLOCK while the existing tool still executes.
12
+ 5. **Design Partner** — use 3–5 partners, one agent and one sensitive tool per partner initially.
13
+ 6. **Enforce** — move one validated sensitive tool from shadow to enforcement.
14
+ 7. **Evidence** — require request, decision, winning rule, rule trace, execution outcome, and replay evidence.
15
+ 8. **Case Study** — measure before/after outcomes using partner-approved data.
16
+ 9. **Productize** — extract repeated policy patterns, integrations, and onboarding friction into the product.
17
+ 10. **Commercialize** — only after repeatable protection and onboarding evidence exists.
18
+
19
+ ## Partner acceptance gates
20
+
21
+ - `BLOCK -> handler execution = 0`
22
+ - `ASK -> pre-approval execution = 0`
23
+ - Approved `ASK -> exactly 1 execution`
24
+ - Cross-tenant access -> `0` leaks
25
+ - Egress secret leakage -> `0` undetected test cases
26
+ - Audit mismatch -> `0`
27
+ - Restart/replay -> evidence remains available
28
+ - Time to first protected tool -> target under 10 minutes
29
+
30
+ ## Rollout sequence
31
+
32
+ `replay/sandbox -> shadow -> low-risk enforce -> sensitive-tool enforce`
33
+
34
+ Do not start with sensitive production data. Review the partner's tool contract,
35
+ identity model, and existing authorization before enforcement.
@@ -0,0 +1,67 @@
1
+ # AgentGate Design Partner Program
2
+
3
+ AgentGate is introduced to a design partner around one measurable runtime boundary, not as a general-purpose AI security replacement.
4
+
5
+ ## First use case: Support Refund Safety
6
+
7
+ Start with one side-effecting tool such as `refund`.
8
+
9
+ ```text
10
+ Agent request
11
+ ↓
12
+ AgentGate
13
+ ↓
14
+ ALLOW / ASK / BLOCK
15
+ ↓
16
+ Tool execution
17
+ ↓
18
+ Audit + Replay evidence
19
+ ```
20
+
21
+ The default Support Refund Safety Pack uses:
22
+
23
+ - refunds → `ASK`
24
+ - `> $5,000` → `BLOCK`
25
+ - the pack's `autoApproveAmount` remains available for policy evolution, but this conservative pack does not bypass the runtime's destructive-action approval boundary
26
+ - invalid amount types → fail closed through the runtime policy engine
27
+ - `export_all` → `BLOCK`
28
+
29
+ The pack is a starting point, not a compliance guarantee. Review thresholds and tool semantics before enforcement.
30
+
31
+ ## 10-minute first protection
32
+
33
+ ```bash
34
+ npm install agentgate-runtime-control
35
+ npx agentgate pack list
36
+ npx agentgate pack init support-refund-safety
37
+ npx agentgate simulate
38
+ npx agentgate attack
39
+ ```
40
+
41
+ For a focused demonstration:
42
+
43
+ ```bash
44
+ npx agentgate demo refund
45
+ ```
46
+
47
+ The generated configuration starts in `enforce` mode for the packaged safety default. If a team wants Shadow/Observe, it must explicitly set `mode: 'observe'` and treat that configuration as non-enforcing.
48
+
49
+ ## Rollout
50
+
51
+ 1. Use sandbox or replay traffic.
52
+ 2. Start in `observe` mode.
53
+ 3. Compare AgentGate's proposed decisions with actual tool behavior.
54
+ 4. Run normal and adversarial cases.
55
+ 5. Move one tool to `enforce` only after review.
56
+ 6. Preserve replayable evidence for every sensitive decision.
57
+
58
+ ## Acceptance criteria
59
+
60
+ - `BLOCK → handler execution = 0`
61
+ - `ASK → pre-approval execution = 0`
62
+ - approved action executes exactly once
63
+ - cross-tenant access = 0
64
+ - egress secret leakage = 0
65
+ - audit mismatch = 0
66
+
67
+ AgentGate does not claim to prevent every prompt-injection technique and does not replace application authorization, IAM, network isolation, or provider controls.