opena2a-cli 0.5.5 → 0.5.7

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 (51) hide show
  1. package/dist/commands/atp-types.d.ts +70 -0
  2. package/dist/commands/atp-types.d.ts.map +1 -0
  3. package/dist/commands/atp-types.js +8 -0
  4. package/dist/commands/atp-types.js.map +1 -0
  5. package/dist/commands/claim.d.ts +42 -0
  6. package/dist/commands/claim.d.ts.map +1 -0
  7. package/dist/commands/claim.js +434 -0
  8. package/dist/commands/claim.js.map +1 -0
  9. package/dist/commands/demo.d.ts +21 -0
  10. package/dist/commands/demo.d.ts.map +1 -0
  11. package/dist/commands/demo.js +683 -0
  12. package/dist/commands/demo.js.map +1 -0
  13. package/dist/commands/detect.d.ts +58 -0
  14. package/dist/commands/detect.d.ts.map +1 -0
  15. package/dist/commands/detect.js +335 -0
  16. package/dist/commands/detect.js.map +1 -0
  17. package/dist/commands/gcp-sm-migration.d.ts +17 -0
  18. package/dist/commands/gcp-sm-migration.d.ts.map +1 -0
  19. package/dist/commands/gcp-sm-migration.js +295 -0
  20. package/dist/commands/gcp-sm-migration.js.map +1 -0
  21. package/dist/commands/identity.js +3 -1
  22. package/dist/commands/identity.js.map +1 -1
  23. package/dist/commands/init.js +4 -4
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/mcp-audit.d.ts +50 -0
  26. package/dist/commands/mcp-audit.d.ts.map +1 -0
  27. package/dist/commands/mcp-audit.js +501 -0
  28. package/dist/commands/mcp-audit.js.map +1 -0
  29. package/dist/commands/protect.d.ts.map +1 -1
  30. package/dist/commands/protect.js +10 -1
  31. package/dist/commands/protect.js.map +1 -1
  32. package/dist/commands/soul.js +3 -3
  33. package/dist/commands/soul.js.map +1 -1
  34. package/dist/commands/trust.d.ts +30 -0
  35. package/dist/commands/trust.d.ts.map +1 -0
  36. package/dist/commands/trust.js +261 -0
  37. package/dist/commands/trust.js.map +1 -0
  38. package/dist/guided/wizard.js +2 -2
  39. package/dist/guided/wizard.js.map +1 -1
  40. package/dist/index.js +119 -4
  41. package/dist/index.js.map +1 -1
  42. package/dist/natural/llm-fallback.js +1 -1
  43. package/dist/report/review-html.js +1 -1
  44. package/dist/router.d.ts.map +1 -1
  45. package/dist/router.js +70 -4
  46. package/dist/router.js.map +1 -1
  47. package/dist/semantic/command-index.json +3 -3
  48. package/dist/shield/init.d.ts.map +1 -1
  49. package/dist/shield/init.js +16 -1
  50. package/dist/shield/init.js.map +1 -1
  51. package/package.json +1 -1
@@ -0,0 +1,683 @@
1
+ "use strict";
2
+ /**
3
+ * opena2a demo -- Interactive demonstration of AIM capabilities.
4
+ *
5
+ * Runs a self-contained, narrated walkthrough showing the full AIM lifecycle
6
+ * in a temporary sandbox. No Docker or external services required.
7
+ *
8
+ * Scenarios:
9
+ * aim (default) -- Identity, policy, signing, credential migration
10
+ * dvaa -- Attack/defend loop against a vulnerable agent config
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.demo = demo;
47
+ const fs = __importStar(require("node:fs"));
48
+ const path = __importStar(require("node:path"));
49
+ const os = __importStar(require("node:os"));
50
+ const crypto = __importStar(require("node:crypto"));
51
+ const readline = __importStar(require("node:readline"));
52
+ const colors_js_1 = require("../util/colors.js");
53
+ const footer_js_1 = require("../util/footer.js");
54
+ // --- Helpers ---
55
+ const STEP_DELAY_MS = 300;
56
+ function sleep(ms) {
57
+ return new Promise((resolve) => setTimeout(resolve, ms));
58
+ }
59
+ async function waitForEnter(interactive) {
60
+ if (!interactive)
61
+ return;
62
+ const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
63
+ return new Promise((resolve) => {
64
+ process.stderr.write((0, colors_js_1.dim)(' [Press Enter to continue]') + '\n');
65
+ rl.once('line', () => {
66
+ rl.close();
67
+ resolve();
68
+ });
69
+ });
70
+ }
71
+ function printStepHeader(step) {
72
+ process.stdout.write('\n');
73
+ process.stdout.write((0, colors_js_1.bold)((0, colors_js_1.cyan)(`Step ${step.step}/${step.total}: ${step.title}`)) + '\n');
74
+ process.stdout.write((0, colors_js_1.dim)(` ${step.description}`) + '\n');
75
+ }
76
+ function generateDemoId() {
77
+ return 'aim_demo_' + crypto.randomBytes(6).toString('hex');
78
+ }
79
+ function generateKeyPair() {
80
+ const bytes = crypto.randomBytes(32);
81
+ const hash = crypto.createHash('sha256').update(bytes).digest('hex');
82
+ return {
83
+ publicKey: 'ed25519:' + hash.slice(0, 16) + '...',
84
+ privateKeyHex: hash,
85
+ };
86
+ }
87
+ function nowISO() {
88
+ return new Date().toISOString().replace('T', ' ').slice(0, 19);
89
+ }
90
+ // --- Sandbox setup ---
91
+ function createSandbox(dir) {
92
+ if (dir) {
93
+ fs.mkdirSync(dir, { recursive: true });
94
+ return dir;
95
+ }
96
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'opena2a-demo-'));
97
+ }
98
+ function cleanupSandbox(sandboxDir, keep) {
99
+ if (keep)
100
+ return;
101
+ try {
102
+ fs.rmSync(sandboxDir, { recursive: true, force: true });
103
+ }
104
+ catch {
105
+ // Best-effort cleanup
106
+ }
107
+ }
108
+ function writeSandboxFiles(sandboxDir) {
109
+ // package.json
110
+ fs.writeFileSync(path.join(sandboxDir, 'package.json'), JSON.stringify({
111
+ name: 'demo-ai-agent',
112
+ version: '1.0.0',
113
+ description: 'Sample AI agent for AIM demo',
114
+ main: 'index.js',
115
+ dependencies: { langchain: '^0.1.0', openai: '^4.0.0' },
116
+ }, null, 2));
117
+ // Fake .env with intentionally exposed credentials
118
+ fs.writeFileSync(path.join(sandboxDir, '.env'), [
119
+ '# Demo credentials (FAKE - for demonstration only)',
120
+ 'OPENAI_API_KEY=sk-FAKE-demo-key-1234567890abcdef',
121
+ 'DATABASE_URL=postgresql://admin:password123@localhost:5432/mydb',
122
+ '',
123
+ ].join('\n'));
124
+ // MCP config
125
+ const mcpDir = path.join(sandboxDir, '.cursor');
126
+ fs.mkdirSync(mcpDir, { recursive: true });
127
+ fs.writeFileSync(path.join(mcpDir, 'mcp.json'), JSON.stringify({
128
+ mcpServers: {
129
+ filesystem: {
130
+ command: 'npx',
131
+ args: ['-y', '@modelcontextprotocol/server-filesystem', '/'],
132
+ env: {},
133
+ },
134
+ database: {
135
+ command: 'npx',
136
+ args: ['-y', 'mcp-server-postgres'],
137
+ env: { DB_URL: 'postgresql://admin:password123@localhost:5432/mydb' },
138
+ },
139
+ },
140
+ }, null, 2));
141
+ // A simple config.js with embedded key
142
+ fs.writeFileSync(path.join(sandboxDir, 'config.js'), [
143
+ '// Agent configuration',
144
+ 'module.exports = {',
145
+ ' apiKey: "sk-FAKE-hardcoded-key-abcdef1234",',
146
+ ' model: "gpt-4",',
147
+ ' maxTokens: 4096,',
148
+ '};',
149
+ '',
150
+ ].join('\n'));
151
+ }
152
+ function writeDvaaFiles(sandboxDir) {
153
+ // package.json for vulnerable agent
154
+ fs.writeFileSync(path.join(sandboxDir, 'package.json'), JSON.stringify({
155
+ name: 'vulnerable-ai-agent',
156
+ version: '0.1.0',
157
+ description: 'Intentionally vulnerable AI agent for demo',
158
+ main: 'agent.js',
159
+ dependencies: { openai: '^4.0.0', express: '^4.18.0' },
160
+ }, null, 2));
161
+ // Hardcoded API key in config
162
+ fs.writeFileSync(path.join(sandboxDir, 'config.js'), [
163
+ '// DVAA agent config',
164
+ 'const config = {',
165
+ ' openaiKey: "sk-FAKE-vuln-key-deadbeef1234567890",',
166
+ ' adminToken: "ghp_FAKE_admin_token_1234567890abcdef",',
167
+ ' allowedTools: ["*"], // overprivileged',
168
+ ' trustAllInputs: true,',
169
+ '};',
170
+ 'module.exports = config;',
171
+ '',
172
+ ].join('\n'));
173
+ // Permissive MCP config
174
+ const mcpDir = path.join(sandboxDir, '.cursor');
175
+ fs.mkdirSync(mcpDir, { recursive: true });
176
+ fs.writeFileSync(path.join(mcpDir, 'mcp.json'), JSON.stringify({
177
+ mcpServers: {
178
+ filesystem: {
179
+ command: 'npx',
180
+ args: ['-y', '@modelcontextprotocol/server-filesystem', '/'],
181
+ env: {},
182
+ },
183
+ },
184
+ }, null, 2));
185
+ // .env with credentials
186
+ fs.writeFileSync(path.join(sandboxDir, '.env'), [
187
+ 'OPENAI_API_KEY=sk-FAKE-vuln-env-key-1234567890',
188
+ 'ADMIN_SECRET=FAKE-super-secret-admin-password',
189
+ '',
190
+ ].join('\n'));
191
+ // Overprivileged skill
192
+ fs.writeFileSync(path.join(sandboxDir, 'SKILL.md'), [
193
+ '---',
194
+ 'name: data-exporter',
195
+ 'tools: ["read-file", "write-file", "execute-shell", "network-external"]',
196
+ '---',
197
+ '',
198
+ '# Data Exporter Skill',
199
+ 'This skill can read, write, execute, and send data externally.',
200
+ '',
201
+ ].join('\n'));
202
+ }
203
+ // --- AIM Demo ---
204
+ async function runAimDemo(opts) {
205
+ const isCI = opts.ci ?? false;
206
+ const isInteractive = !isCI && (opts.interactive ?? false);
207
+ const keep = opts.keep ?? false;
208
+ const total = 8;
209
+ const auditLog = [];
210
+ const steps = [];
211
+ const sandboxDir = createSandbox(opts.dir);
212
+ const delayMs = isCI ? 0 : STEP_DELAY_MS;
213
+ try {
214
+ // Header
215
+ process.stdout.write('\n');
216
+ process.stdout.write((0, colors_js_1.bold)('AIM Agent Identity Management Demo') + '\n');
217
+ process.stdout.write((0, colors_js_1.dim)('='.repeat(38)) + '\n');
218
+ process.stdout.write((0, colors_js_1.dim)(' Self-contained walkthrough of the AIM lifecycle.') + '\n');
219
+ process.stdout.write((0, colors_js_1.dim)(' All operations run in a temporary sandbox.') + '\n');
220
+ // Step 1: Setup sandbox
221
+ printStepHeader({
222
+ step: 1, total,
223
+ title: 'Setting up sandbox',
224
+ description: 'Creating temporary project with sample agent configuration...',
225
+ });
226
+ await sleep(delayMs);
227
+ writeSandboxFiles(sandboxDir);
228
+ process.stdout.write((0, colors_js_1.green)(' Created sandbox at: ') + (0, colors_js_1.dim)(sandboxDir) + '\n');
229
+ process.stdout.write((0, colors_js_1.dim)(' Files: package.json, .env, .cursor/mcp.json, config.js') + '\n');
230
+ steps.push({ step: 1, title: 'Setting up sandbox', status: 'complete' });
231
+ await waitForEnter(isInteractive);
232
+ // Step 2: Security scan (before AIM)
233
+ printStepHeader({
234
+ step: 2, total,
235
+ title: 'Security scan (before AIM)',
236
+ description: 'Running security assessment of unprotected project...',
237
+ });
238
+ await sleep(delayMs);
239
+ const findingsBefore = { critical: 1, high: 2, medium: 1, low: 0 };
240
+ const scoreBefore = 22;
241
+ process.stdout.write('\n');
242
+ process.stdout.write(' Findings:\n');
243
+ process.stdout.write(' ' + (0, colors_js_1.red)('CRITICAL') + ' CRED-001 Hardcoded API key in .env\n');
244
+ process.stdout.write(' ' + (0, colors_js_1.yellow)('HIGH ') + ' CRED-002 Database password in connection string\n');
245
+ process.stdout.write(' ' + (0, colors_js_1.yellow)('HIGH ') + ' CRED-003 Hardcoded API key in config.js\n');
246
+ process.stdout.write(' ' + (0, colors_js_1.cyan)('MEDIUM ') + ' MCP-001 MCP server with root filesystem access\n');
247
+ process.stdout.write('\n');
248
+ process.stdout.write(' Result: ' + (0, colors_js_1.bold)((0, colors_js_1.red)('3 findings')) + ' (1 critical, 2 high)\n');
249
+ process.stdout.write(' Score: ' + (0, colors_js_1.bold)((0, colors_js_1.red)(String(scoreBefore) + '/100')) + '\n');
250
+ auditLog.push({ timestamp: nowISO(), action: 'scan.initial', target: 'project', outcome: 'complete' });
251
+ steps.push({ step: 2, title: 'Security scan (before AIM)', status: 'complete' });
252
+ await waitForEnter(isInteractive);
253
+ // Step 3: Create agent identity
254
+ printStepHeader({
255
+ step: 3, total,
256
+ title: 'Creating agent identity',
257
+ description: 'Generating Ed25519 keypair for demo-agent...',
258
+ });
259
+ await sleep(delayMs);
260
+ const agentId = generateDemoId();
261
+ const keyPair = generateKeyPair();
262
+ process.stdout.write('\n');
263
+ process.stdout.write(' Agent ID: ' + (0, colors_js_1.bold)(agentId) + '\n');
264
+ process.stdout.write(' Public Key: ' + (0, colors_js_1.dim)(keyPair.publicKey) + '\n');
265
+ process.stdout.write(' Algorithm: Ed25519\n');
266
+ // Write identity file to sandbox
267
+ const opena2aDir = path.join(sandboxDir, '.opena2a');
268
+ fs.mkdirSync(opena2aDir, { recursive: true });
269
+ fs.writeFileSync(path.join(opena2aDir, 'identity.json'), JSON.stringify({ agentId, publicKey: keyPair.publicKey, algorithm: 'Ed25519', createdAt: new Date().toISOString() }, null, 2));
270
+ auditLog.push({ timestamp: nowISO(), action: 'identity.create', target: 'demo-agent', outcome: 'allowed' });
271
+ steps.push({ step: 3, title: 'Creating agent identity', status: 'complete' });
272
+ await waitForEnter(isInteractive);
273
+ // Step 4: Apply capability policy
274
+ printStepHeader({
275
+ step: 4, total,
276
+ title: 'Applying capability policy',
277
+ description: 'Writing capability policy that restricts tool access...',
278
+ });
279
+ await sleep(delayMs);
280
+ const policy = {
281
+ version: 1,
282
+ agentId,
283
+ mode: 'enforce',
284
+ capabilities: {
285
+ allow: ['read-file', 'list-directory', 'search'],
286
+ deny: ['write-file', 'execute-shell', 'network-external'],
287
+ },
288
+ createdAt: new Date().toISOString(),
289
+ };
290
+ fs.writeFileSync(path.join(opena2aDir, 'policy.json'), JSON.stringify(policy, null, 2));
291
+ process.stdout.write('\n');
292
+ process.stdout.write(' Policy applied:\n');
293
+ process.stdout.write(' ' + (0, colors_js_1.green)('ALLOW') + ' read-file, list-directory, search\n');
294
+ process.stdout.write(' ' + (0, colors_js_1.red)('DENY ') + ' write-file, execute-shell, network-external\n');
295
+ process.stdout.write(' Mode: enforce\n');
296
+ auditLog.push({ timestamp: nowISO(), action: 'policy.apply', target: 'capability', outcome: 'allowed' });
297
+ steps.push({ step: 4, title: 'Applying capability policy', status: 'complete' });
298
+ await waitForEnter(isInteractive);
299
+ // Step 5: Sign configuration files
300
+ printStepHeader({
301
+ step: 5, total,
302
+ title: 'Signing configuration files',
303
+ description: 'Signing package.json and mcp config for tamper detection...',
304
+ });
305
+ await sleep(delayMs);
306
+ const filesToSign = ['package.json', '.cursor/mcp.json'];
307
+ const signatures = {};
308
+ for (const f of filesToSign) {
309
+ const content = fs.readFileSync(path.join(sandboxDir, f), 'utf-8');
310
+ const hash = crypto.createHash('sha256').update(content).digest('hex');
311
+ signatures[f] = hash;
312
+ }
313
+ const guardDir = path.join(opena2aDir, 'guard');
314
+ fs.mkdirSync(guardDir, { recursive: true });
315
+ fs.writeFileSync(path.join(guardDir, 'signatures.json'), JSON.stringify({ version: 1, signatures: Object.entries(signatures).map(([file, hash]) => ({ file, hash, signedAt: new Date().toISOString() })) }, null, 2));
316
+ process.stdout.write('\n');
317
+ for (const f of filesToSign) {
318
+ process.stdout.write(' Signed: ' + (0, colors_js_1.bold)(f) + ' ' + (0, colors_js_1.dim)('sha256:' + signatures[f].slice(0, 12) + '...') + '\n');
319
+ }
320
+ process.stdout.write(' Total: ' + (0, colors_js_1.bold)('2 files') + ' signed for tamper detection\n');
321
+ auditLog.push({ timestamp: nowISO(), action: 'config.sign', target: 'package.json', outcome: 'allowed' });
322
+ auditLog.push({ timestamp: nowISO(), action: 'config.sign', target: '.cursor/mcp.json', outcome: 'allowed' });
323
+ steps.push({ step: 5, title: 'Signing configuration files', status: 'complete' });
324
+ await waitForEnter(isInteractive);
325
+ // Step 6: Migrate credentials
326
+ printStepHeader({
327
+ step: 6, total,
328
+ title: 'Migrating credentials',
329
+ description: 'Moving hardcoded credentials to encrypted vault...',
330
+ });
331
+ await sleep(delayMs);
332
+ const vaultDir = path.join(opena2aDir, 'vault');
333
+ fs.mkdirSync(vaultDir, { recursive: true });
334
+ const migratedCreds = [
335
+ { name: 'OPENAI_API_KEY', source: '.env', status: 'migrated' },
336
+ { name: 'DATABASE_URL', source: '.env', status: 'migrated' },
337
+ { name: 'apiKey', source: 'config.js', status: 'migrated' },
338
+ ];
339
+ // Write a vault manifest
340
+ fs.writeFileSync(path.join(vaultDir, 'manifest.json'), JSON.stringify({ version: 1, entries: migratedCreds.map((c) => ({ name: c.name, source: c.source, migratedAt: new Date().toISOString() })) }, null, 2));
341
+ // Rewrite .env to use vault references
342
+ fs.writeFileSync(path.join(sandboxDir, '.env'), [
343
+ '# Credentials migrated to vault',
344
+ 'OPENAI_API_KEY=vault://opena2a/OPENAI_API_KEY',
345
+ 'DATABASE_URL=vault://opena2a/DATABASE_URL',
346
+ '',
347
+ ].join('\n'));
348
+ // Rewrite config.js to use env var
349
+ fs.writeFileSync(path.join(sandboxDir, 'config.js'), [
350
+ '// Agent configuration (credentials migrated to vault)',
351
+ 'module.exports = {',
352
+ ' apiKey: process.env.OPENAI_API_KEY,',
353
+ ' model: "gpt-4",',
354
+ ' maxTokens: 4096,',
355
+ '};',
356
+ '',
357
+ ].join('\n'));
358
+ process.stdout.write('\n');
359
+ for (const c of migratedCreds) {
360
+ process.stdout.write(' Migrated: ' + (0, colors_js_1.bold)(c.name) + ' from ' + (0, colors_js_1.dim)(c.source) + ' to vault\n');
361
+ }
362
+ process.stdout.write(' Total: ' + (0, colors_js_1.bold)('3 credentials') + ' moved to encrypted vault\n');
363
+ auditLog.push({ timestamp: nowISO(), action: 'credential.migrate', target: '.env', outcome: 'allowed' });
364
+ auditLog.push({ timestamp: nowISO(), action: 'credential.migrate', target: 'config.js', outcome: 'allowed' });
365
+ steps.push({ step: 6, title: 'Migrating credentials', status: 'complete' });
366
+ await waitForEnter(isInteractive);
367
+ // Step 7: Security scan (after AIM)
368
+ printStepHeader({
369
+ step: 7, total,
370
+ title: 'Security scan (after AIM)',
371
+ description: 'Running security assessment of protected project...',
372
+ });
373
+ await sleep(delayMs);
374
+ const findingsAfter = { critical: 0, high: 0, medium: 0, low: 1 };
375
+ const scoreAfter = 87;
376
+ process.stdout.write('\n');
377
+ process.stdout.write(' Findings:\n');
378
+ process.stdout.write(' ' + (0, colors_js_1.dim)('LOW ') + ' CONFIG-005 Consider enabling strict mode\n');
379
+ process.stdout.write('\n');
380
+ process.stdout.write(' Result: ' + (0, colors_js_1.green)('0 critical, 0 high') + '\n');
381
+ process.stdout.write(' Score: ' + (0, colors_js_1.bold)((0, colors_js_1.green)(String(scoreAfter) + '/100')) + ' ' + (0, colors_js_1.green)('(+' + String(scoreAfter - scoreBefore) + ' improvement)') + '\n');
382
+ auditLog.push({ timestamp: nowISO(), action: 'scan.final', target: 'project', outcome: 'complete' });
383
+ steps.push({ step: 7, title: 'Security scan (after AIM)', status: 'complete' });
384
+ await waitForEnter(isInteractive);
385
+ // Step 8: Audit log
386
+ printStepHeader({
387
+ step: 8, total,
388
+ title: 'Audit log',
389
+ description: 'Reviewing what happened...',
390
+ });
391
+ await sleep(delayMs);
392
+ process.stdout.write('\n');
393
+ for (const entry of auditLog) {
394
+ const action = entry.action.padEnd(20);
395
+ const target = entry.target.padEnd(20);
396
+ process.stdout.write(' ' + (0, colors_js_1.dim)(entry.timestamp) + ' ' + action + target + (0, colors_js_1.green)(entry.outcome) + '\n');
397
+ }
398
+ steps.push({ step: 8, title: 'Audit log', status: 'complete' });
399
+ // Summary
400
+ process.stdout.write('\n');
401
+ process.stdout.write((0, colors_js_1.bold)('Demo Complete') + '\n');
402
+ process.stdout.write((0, colors_js_1.dim)('='.repeat(16)) + '\n');
403
+ process.stdout.write('\n');
404
+ process.stdout.write(' Before AIM: ' + (0, colors_js_1.bold)((0, colors_js_1.red)(String(scoreBefore) + '/100')) + ' (3 findings, no identity, no governance)\n');
405
+ process.stdout.write(' After AIM: ' + (0, colors_js_1.bold)((0, colors_js_1.green)(String(scoreAfter) + '/100')) + ' (0 critical findings, identity active, policy enforced)\n');
406
+ process.stdout.write('\n');
407
+ process.stdout.write(' What happened:\n');
408
+ process.stdout.write(' 1. Created cryptographic agent identity (Ed25519)\n');
409
+ process.stdout.write(' 2. Applied least-privilege capability policy\n');
410
+ process.stdout.write(' 3. Signed config files for tamper detection\n');
411
+ process.stdout.write(' 4. Migrated hardcoded credentials to encrypted vault\n');
412
+ process.stdout.write('\n');
413
+ process.stdout.write(' Try it on your project:\n');
414
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a init') + ' Start security assessment\n');
415
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a protect') + ' Detect and migrate credentials\n');
416
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a identity create') + ' Create agent identity\n');
417
+ process.stdout.write('\n');
418
+ if (keep) {
419
+ process.stdout.write((0, colors_js_1.dim)(' Sandbox preserved at: ' + sandboxDir) + '\n');
420
+ }
421
+ else {
422
+ process.stdout.write((0, colors_js_1.dim)(' Sandbox cleaned up. No files were modified outside the demo.') + '\n');
423
+ }
424
+ return {
425
+ scenario: 'aim',
426
+ sandboxDir,
427
+ kept: keep,
428
+ steps,
429
+ scoreBefore,
430
+ scoreAfter,
431
+ findingsBefore,
432
+ findingsAfter,
433
+ auditLog,
434
+ };
435
+ }
436
+ finally {
437
+ cleanupSandbox(sandboxDir, keep);
438
+ }
439
+ }
440
+ // --- DVAA Demo ---
441
+ async function runDvaaDemo(opts) {
442
+ const isCI = opts.ci ?? false;
443
+ const isInteractive = !isCI && (opts.interactive ?? false);
444
+ const keep = opts.keep ?? false;
445
+ const total = 5;
446
+ const auditLog = [];
447
+ const steps = [];
448
+ const sandboxDir = createSandbox(opts.dir);
449
+ const delayMs = isCI ? 0 : STEP_DELAY_MS;
450
+ try {
451
+ // Header
452
+ process.stdout.write('\n');
453
+ process.stdout.write((0, colors_js_1.bold)('DVAA Attack/Defend Demo') + '\n');
454
+ process.stdout.write((0, colors_js_1.dim)('='.repeat(26)) + '\n');
455
+ process.stdout.write((0, colors_js_1.dim)(' Shows how AIM protects an agent from common attacks.') + '\n');
456
+ // Step 1: Set up vulnerable agent
457
+ printStepHeader({
458
+ step: 1, total,
459
+ title: 'Setting up vulnerable agent',
460
+ description: 'Creating a simulated vulnerable AI agent configuration...',
461
+ });
462
+ await sleep(delayMs);
463
+ writeDvaaFiles(sandboxDir);
464
+ process.stdout.write((0, colors_js_1.green)(' Created vulnerable agent sandbox at: ') + (0, colors_js_1.dim)(sandboxDir) + '\n');
465
+ process.stdout.write((0, colors_js_1.dim)(' Files: package.json, config.js, .env, .cursor/mcp.json, SKILL.md') + '\n');
466
+ steps.push({ step: 1, title: 'Setting up vulnerable agent', status: 'complete' });
467
+ await waitForEnter(isInteractive);
468
+ // Step 2: Security scan
469
+ printStepHeader({
470
+ step: 2, total,
471
+ title: 'Running security scan',
472
+ description: 'Scanning for vulnerabilities...',
473
+ });
474
+ await sleep(delayMs);
475
+ const scoreBefore = 18;
476
+ const findingsBefore = { critical: 1, high: 2, medium: 1, low: 0 };
477
+ process.stdout.write('\n');
478
+ process.stdout.write(' Findings:\n');
479
+ process.stdout.write(' ' + (0, colors_js_1.red)('CRITICAL') + ' CRED-001 Hardcoded API key in config.js\n');
480
+ process.stdout.write(' ' + (0, colors_js_1.yellow)('HIGH ') + ' MCP-003 MCP server with root filesystem access\n');
481
+ process.stdout.write(' ' + (0, colors_js_1.yellow)('HIGH ') + ' GOVERNANCE-001 No SOUL.md governance file\n');
482
+ process.stdout.write(' ' + (0, colors_js_1.cyan)('MEDIUM ') + ' SKILL-002 Overprivileged skill definitions\n');
483
+ process.stdout.write('\n');
484
+ process.stdout.write(' Score: ' + (0, colors_js_1.bold)((0, colors_js_1.red)(String(scoreBefore) + '/100')) + '\n');
485
+ auditLog.push({ timestamp: nowISO(), action: 'scan.initial', target: 'project', outcome: 'complete' });
486
+ steps.push({ step: 2, title: 'Running security scan', status: 'complete' });
487
+ await waitForEnter(isInteractive);
488
+ // Step 3: Apply AIM hardening
489
+ printStepHeader({
490
+ step: 3, total,
491
+ title: 'Applying AIM hardening',
492
+ description: 'Creating agent identity, governance, migrating credentials, signing config...',
493
+ });
494
+ await sleep(delayMs);
495
+ const agentId = generateDemoId();
496
+ const opena2aDir = path.join(sandboxDir, '.opena2a');
497
+ fs.mkdirSync(path.join(opena2aDir, 'guard'), { recursive: true });
498
+ fs.mkdirSync(path.join(opena2aDir, 'vault'), { recursive: true });
499
+ // Identity
500
+ process.stdout.write('\n');
501
+ process.stdout.write(' Creating agent identity... ' + (0, colors_js_1.green)('done') + '\n');
502
+ fs.writeFileSync(path.join(opena2aDir, 'identity.json'), JSON.stringify({ agentId, algorithm: 'Ed25519', createdAt: new Date().toISOString() }, null, 2));
503
+ auditLog.push({ timestamp: nowISO(), action: 'identity.create', target: agentId, outcome: 'allowed' });
504
+ // Governance
505
+ process.stdout.write(' Generating governance file... ' + (0, colors_js_1.green)('done') + '\n');
506
+ fs.writeFileSync(path.join(sandboxDir, 'SOUL.md'), [
507
+ '# Agent Governance',
508
+ '',
509
+ '## Identity',
510
+ 'This agent operates under AIM identity management.',
511
+ '',
512
+ '## Boundaries',
513
+ '- No external network access without explicit approval',
514
+ '- No shell command execution',
515
+ '- Read-only filesystem access by default',
516
+ '',
517
+ '## Data Handling',
518
+ '- No credential storage in plaintext',
519
+ '- All secrets accessed via vault references',
520
+ '',
521
+ ].join('\n'));
522
+ auditLog.push({ timestamp: nowISO(), action: 'governance.create', target: 'SOUL.md', outcome: 'allowed' });
523
+ // Credential migration
524
+ process.stdout.write(' Migrating credentials... ' + (0, colors_js_1.green)('done') + '\n');
525
+ fs.writeFileSync(path.join(sandboxDir, 'config.js'), [
526
+ '// DVAA agent config (hardened)',
527
+ 'const config = {',
528
+ ' openaiKey: process.env.OPENAI_API_KEY,',
529
+ ' adminToken: process.env.ADMIN_TOKEN,',
530
+ ' allowedTools: ["read-file", "search"],',
531
+ ' trustAllInputs: false,',
532
+ '};',
533
+ 'module.exports = config;',
534
+ '',
535
+ ].join('\n'));
536
+ fs.writeFileSync(path.join(sandboxDir, '.env'), [
537
+ '# Credentials migrated to vault',
538
+ 'OPENAI_API_KEY=vault://opena2a/OPENAI_API_KEY',
539
+ 'ADMIN_SECRET=vault://opena2a/ADMIN_SECRET',
540
+ '',
541
+ ].join('\n'));
542
+ auditLog.push({ timestamp: nowISO(), action: 'credential.migrate', target: 'config.js', outcome: 'allowed' });
543
+ // Signing
544
+ process.stdout.write(' Signing configuration... ' + (0, colors_js_1.green)('done') + '\n');
545
+ const configContent = fs.readFileSync(path.join(sandboxDir, 'config.js'), 'utf-8');
546
+ const configHash = crypto.createHash('sha256').update(configContent).digest('hex');
547
+ fs.writeFileSync(path.join(opena2aDir, 'guard', 'signatures.json'), JSON.stringify({ version: 1, signatures: [{ file: 'config.js', hash: configHash, signedAt: new Date().toISOString() }] }, null, 2));
548
+ auditLog.push({ timestamp: nowISO(), action: 'config.sign', target: 'config.js', outcome: 'allowed' });
549
+ // Policy
550
+ fs.writeFileSync(path.join(opena2aDir, 'policy.json'), JSON.stringify({
551
+ version: 1,
552
+ agentId,
553
+ mode: 'enforce',
554
+ capabilities: {
555
+ allow: ['read-file', 'search'],
556
+ deny: ['write-file', 'execute-shell', 'network-external', 'prompt-override'],
557
+ },
558
+ }, null, 2));
559
+ auditLog.push({ timestamp: nowISO(), action: 'policy.apply', target: 'capability', outcome: 'allowed' });
560
+ steps.push({ step: 3, title: 'Applying AIM hardening', status: 'complete' });
561
+ await waitForEnter(isInteractive);
562
+ // Step 4: Re-scan
563
+ printStepHeader({
564
+ step: 4, total,
565
+ title: 'Re-scanning after hardening',
566
+ description: 'Running security assessment of hardened project...',
567
+ });
568
+ await sleep(delayMs);
569
+ const scoreAfter = 91;
570
+ const findingsAfter = { critical: 0, high: 0, medium: 0, low: 1 };
571
+ process.stdout.write('\n');
572
+ process.stdout.write(' Findings:\n');
573
+ process.stdout.write(' ' + (0, colors_js_1.dim)('LOW ') + ' CONFIG-005 Consider enabling strict mode\n');
574
+ process.stdout.write('\n');
575
+ process.stdout.write(' Score: ' + (0, colors_js_1.bold)((0, colors_js_1.green)(String(scoreAfter) + '/100')) + ' ' + (0, colors_js_1.green)('(+' + String(scoreAfter - scoreBefore) + ' improvement)') + '\n');
576
+ auditLog.push({ timestamp: nowISO(), action: 'scan.final', target: 'project', outcome: 'complete' });
577
+ steps.push({ step: 4, title: 'Re-scanning after hardening', status: 'complete' });
578
+ await waitForEnter(isInteractive);
579
+ // Step 5: Attack simulation
580
+ printStepHeader({
581
+ step: 5, total,
582
+ title: 'Attack simulation',
583
+ description: 'Running adversarial probes against hardened configuration...',
584
+ });
585
+ await sleep(delayMs);
586
+ const attacks = [
587
+ { name: 'prompt-injection', result: 'BLOCKED', reason: 'capability policy denies prompt override' },
588
+ { name: 'credential-theft', result: 'BLOCKED', reason: 'credentials in vault, not in files' },
589
+ { name: 'config-tampering', result: 'BLOCKED', reason: 'signature verification detects change' },
590
+ { name: 'privilege-escalation', result: 'BLOCKED', reason: 'least-privilege policy enforced' },
591
+ ];
592
+ process.stdout.write('\n');
593
+ for (const attack of attacks) {
594
+ const nameCol = attack.name.padEnd(24);
595
+ process.stdout.write(' ' + nameCol + (0, colors_js_1.green)('BLOCKED') + ' (' + (0, colors_js_1.dim)(attack.reason) + ')\n');
596
+ auditLog.push({ timestamp: nowISO(), action: 'attack.' + attack.name, target: 'agent', outcome: 'blocked' });
597
+ }
598
+ process.stdout.write('\n');
599
+ process.stdout.write(' Result: ' + (0, colors_js_1.bold)((0, colors_js_1.green)('4/4 attacks blocked')) + '\n');
600
+ steps.push({ step: 5, title: 'Attack simulation', status: 'complete' });
601
+ // Summary
602
+ process.stdout.write('\n');
603
+ process.stdout.write((0, colors_js_1.bold)('Demo Complete') + '\n');
604
+ process.stdout.write((0, colors_js_1.dim)('='.repeat(16)) + '\n');
605
+ process.stdout.write('\n');
606
+ process.stdout.write(' Before hardening: ' + (0, colors_js_1.bold)((0, colors_js_1.red)(String(scoreBefore) + '/100')) + ' (4 findings, no identity, no governance)\n');
607
+ process.stdout.write(' After hardening: ' + (0, colors_js_1.bold)((0, colors_js_1.green)(String(scoreAfter) + '/100')) + ' (0 critical, identity active, policy enforced)\n');
608
+ process.stdout.write(' Attacks blocked: ' + (0, colors_js_1.bold)((0, colors_js_1.green)('4/4')) + '\n');
609
+ process.stdout.write('\n');
610
+ process.stdout.write(' What was applied:\n');
611
+ process.stdout.write(' 1. Created cryptographic agent identity\n');
612
+ process.stdout.write(' 2. Generated SOUL.md governance file\n');
613
+ process.stdout.write(' 3. Migrated credentials to encrypted vault\n');
614
+ process.stdout.write(' 4. Signed configuration for tamper detection\n');
615
+ process.stdout.write(' 5. Applied least-privilege capability policy\n');
616
+ process.stdout.write('\n');
617
+ process.stdout.write(' Try it on your project:\n');
618
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a init') + ' Start security assessment\n');
619
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a protect') + ' Detect and migrate credentials\n');
620
+ process.stdout.write((0, colors_js_1.cyan)(' opena2a harden-soul') + ' Generate governance file\n');
621
+ process.stdout.write('\n');
622
+ if (keep) {
623
+ process.stdout.write((0, colors_js_1.dim)(' Sandbox preserved at: ' + sandboxDir) + '\n');
624
+ }
625
+ else {
626
+ process.stdout.write((0, colors_js_1.dim)(' Sandbox cleaned up. No files were modified outside the demo.') + '\n');
627
+ }
628
+ return {
629
+ scenario: 'dvaa',
630
+ sandboxDir,
631
+ kept: keep,
632
+ steps,
633
+ scoreBefore,
634
+ scoreAfter,
635
+ findingsBefore,
636
+ findingsAfter,
637
+ auditLog,
638
+ };
639
+ }
640
+ finally {
641
+ cleanupSandbox(sandboxDir, keep);
642
+ }
643
+ }
644
+ // --- Entry point ---
645
+ async function demo(opts) {
646
+ const scenario = opts.scenario ?? 'aim';
647
+ const format = opts.format ?? 'text';
648
+ let result;
649
+ // In JSON mode, capture the demo silently and only output the JSON result
650
+ const originalWrite = process.stdout.write.bind(process.stdout);
651
+ if (format === 'json') {
652
+ process.stdout.write = (() => true);
653
+ }
654
+ try {
655
+ if (scenario === 'dvaa') {
656
+ result = await runDvaaDemo(opts);
657
+ }
658
+ else if (scenario === 'aim' || !scenario) {
659
+ result = await runAimDemo(opts);
660
+ }
661
+ else {
662
+ if (format === 'json')
663
+ process.stdout.write = originalWrite;
664
+ process.stderr.write(`Unknown demo scenario: ${scenario}\n`);
665
+ process.stderr.write('Available scenarios: aim (default), dvaa\n');
666
+ return 1;
667
+ }
668
+ }
669
+ catch (err) {
670
+ if (format === 'json')
671
+ process.stdout.write = originalWrite;
672
+ process.stderr.write(`Demo error: ${err instanceof Error ? err.message : String(err)}\n`);
673
+ return 1;
674
+ }
675
+ // Restore stdout and output JSON if needed
676
+ if (format === 'json') {
677
+ process.stdout.write = originalWrite;
678
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
679
+ }
680
+ (0, footer_js_1.printFooter)({ ci: opts.ci, json: format === 'json' });
681
+ return 0;
682
+ }
683
+ //# sourceMappingURL=demo.js.map