@ayurak/aribot-cli 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +406 -403
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -15
- package/dist/sdk.js +13 -58
- package/dist/theme.d.ts +15 -15
- package/dist/theme.js +123 -147
- package/package.json +2 -1
- package/src/cli.ts +11 -1
- package/src/index.ts +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
2
|
/**
|
|
4
3
|
* Aribot CLI - Economic, Regulatory & Security APIs for Modern Applications
|
|
5
4
|
*
|
|
@@ -19,30 +18,34 @@
|
|
|
19
18
|
* aribot export <diagram-id> # Export report
|
|
20
19
|
* aribot diagrams # List all diagrams
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
21
|
+
import { Command } from 'commander';
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import ora from 'ora';
|
|
24
|
+
import Conf from 'conf';
|
|
25
|
+
import inquirer from 'inquirer';
|
|
26
|
+
import FormData from 'form-data';
|
|
27
|
+
import fs from 'fs';
|
|
28
|
+
import path from 'path';
|
|
29
|
+
import { fileURLToPath } from 'url';
|
|
30
|
+
import { createRequire } from 'module';
|
|
31
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
32
|
+
const __dirname = path.dirname(__filename);
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
// Read version from package.json
|
|
35
|
+
const packageJson = require('../package.json');
|
|
36
|
+
const VERSION = packageJson.version;
|
|
37
|
+
const config = new Conf({ projectName: 'aribot-cli' });
|
|
35
38
|
const API_BASE = 'https://api.aribot.ayurak.com/aribot-api';
|
|
36
|
-
const program = new
|
|
39
|
+
const program = new Command();
|
|
37
40
|
program
|
|
38
41
|
.name('aribot')
|
|
39
42
|
.description('Aribot - Economic, Regulatory & Security APIs for Modern Applications')
|
|
40
|
-
.version(
|
|
43
|
+
.version(VERSION);
|
|
41
44
|
// Helper to get auth headers
|
|
42
45
|
function getHeaders() {
|
|
43
46
|
const apiKey = config.get('apiKey');
|
|
44
47
|
if (!apiKey) {
|
|
45
|
-
console.error(
|
|
48
|
+
console.error(chalk.red('Not authenticated. Run: aribot login'));
|
|
46
49
|
process.exit(1);
|
|
47
50
|
}
|
|
48
51
|
return {
|
|
@@ -85,22 +88,22 @@ program
|
|
|
85
88
|
.action(async (options) => {
|
|
86
89
|
// Welcome banner
|
|
87
90
|
console.log();
|
|
88
|
-
console.log(
|
|
89
|
-
console.log(
|
|
90
|
-
console.log(
|
|
91
|
+
console.log(chalk.cyan('='.repeat(50)));
|
|
92
|
+
console.log(chalk.cyan.bold(' ARIBOT CLI - Secure Authentication'));
|
|
93
|
+
console.log(chalk.cyan('='.repeat(50)));
|
|
91
94
|
console.log();
|
|
92
95
|
// Check existing auth
|
|
93
96
|
const existingKey = config.get('apiKey');
|
|
94
97
|
if (existingKey) {
|
|
95
|
-
console.log(
|
|
98
|
+
console.log(chalk.yellow('You are already logged in.'));
|
|
96
99
|
const email = config.get('userEmail');
|
|
97
100
|
const company = config.get('company');
|
|
98
101
|
if (email) {
|
|
99
|
-
console.log(` ${
|
|
100
|
-
console.log(` ${
|
|
102
|
+
console.log(` ${chalk.dim('Email:')} ${email}`);
|
|
103
|
+
console.log(` ${chalk.dim('Company:')} ${company || 'N/A'}`);
|
|
101
104
|
}
|
|
102
105
|
console.log();
|
|
103
|
-
const { reauth } = await
|
|
106
|
+
const { reauth } = await inquirer.prompt([{
|
|
104
107
|
type: 'confirm',
|
|
105
108
|
name: 'reauth',
|
|
106
109
|
message: 'Would you like to re-authenticate with a different key?',
|
|
@@ -113,28 +116,28 @@ program
|
|
|
113
116
|
if (options.openPortal) {
|
|
114
117
|
const open = (await import('open')).default;
|
|
115
118
|
const portalUrl = 'https://developer.ayurak.com';
|
|
116
|
-
console.log(
|
|
117
|
-
console.log(
|
|
119
|
+
console.log(chalk.cyan('Opening developer portal...'));
|
|
120
|
+
console.log(chalk.dim(portalUrl));
|
|
118
121
|
await open(portalUrl);
|
|
119
122
|
console.log();
|
|
120
|
-
console.log(
|
|
121
|
-
console.log(' ' +
|
|
123
|
+
console.log(chalk.dim('After creating your API key, run:'));
|
|
124
|
+
console.log(' ' + chalk.green('aribot login'));
|
|
122
125
|
return;
|
|
123
126
|
}
|
|
124
127
|
// Show instructions
|
|
125
|
-
console.log(
|
|
128
|
+
console.log(chalk.bold('To authenticate, you need an API key.'));
|
|
126
129
|
console.log();
|
|
127
|
-
console.log(
|
|
128
|
-
console.log(' ' +
|
|
130
|
+
console.log(chalk.dim('Get your API key from the developer portal:'));
|
|
131
|
+
console.log(' ' + chalk.cyan('https://developer.ayurak.com'));
|
|
129
132
|
console.log();
|
|
130
|
-
console.log(
|
|
133
|
+
console.log(chalk.dim('Or run: ' + chalk.green('aribot login --open-portal') + ' to open it'));
|
|
131
134
|
console.log();
|
|
132
135
|
// Get API key
|
|
133
136
|
let apiKey = options.key;
|
|
134
137
|
if (!apiKey) {
|
|
135
|
-
console.log(
|
|
136
|
-
console.log(
|
|
137
|
-
const response = await
|
|
138
|
+
console.log(chalk.bold('Enter your API key below'));
|
|
139
|
+
console.log(chalk.dim('(input is hidden for security)'));
|
|
140
|
+
const response = await inquirer.prompt([{
|
|
138
141
|
type: 'password',
|
|
139
142
|
name: 'apiKey',
|
|
140
143
|
message: 'API Key:',
|
|
@@ -143,19 +146,19 @@ program
|
|
|
143
146
|
apiKey = response.apiKey;
|
|
144
147
|
}
|
|
145
148
|
else {
|
|
146
|
-
console.log(
|
|
149
|
+
console.log(chalk.dim('Using provided API key...'));
|
|
147
150
|
}
|
|
148
151
|
// Validate format
|
|
149
152
|
apiKey = apiKey.trim();
|
|
150
153
|
if (apiKey.length < 20) {
|
|
151
154
|
console.log();
|
|
152
|
-
console.log(
|
|
153
|
-
console.log(
|
|
154
|
-
console.log(
|
|
155
|
+
console.log(chalk.red('Invalid API key format'));
|
|
156
|
+
console.log(chalk.dim('API keys should be at least 20 characters long.'));
|
|
157
|
+
console.log(chalk.dim('Get a valid key from: https://developer.ayurak.com'));
|
|
155
158
|
return;
|
|
156
159
|
}
|
|
157
160
|
console.log();
|
|
158
|
-
const spinner = (
|
|
161
|
+
const spinner = ora('Validating API key...').start();
|
|
159
162
|
try {
|
|
160
163
|
const fetch = (await import('node-fetch')).default;
|
|
161
164
|
const response = await fetch(`${API_BASE}/v1/developer/token/`, {
|
|
@@ -171,52 +174,52 @@ program
|
|
|
171
174
|
config.set('apiKey', apiKey);
|
|
172
175
|
config.set('userEmail', data.user?.email);
|
|
173
176
|
config.set('company', data.user?.company);
|
|
174
|
-
spinner.succeed(
|
|
177
|
+
spinner.succeed(chalk.green('Authentication successful!'));
|
|
175
178
|
console.log();
|
|
176
|
-
console.log(
|
|
177
|
-
console.log(` ${
|
|
178
|
-
console.log(` ${
|
|
179
|
-
console.log(` ${
|
|
179
|
+
console.log(chalk.bold('Account Details:'));
|
|
180
|
+
console.log(` ${chalk.cyan('Email:')} ${data.user?.email || 'N/A'}`);
|
|
181
|
+
console.log(` ${chalk.cyan('Company:')} ${data.user?.company || 'N/A'}`);
|
|
182
|
+
console.log(` ${chalk.cyan('Plan:')} ${data.plan || 'Standard'}`);
|
|
180
183
|
console.log();
|
|
181
|
-
console.log(
|
|
182
|
-
console.log(' ' +
|
|
183
|
-
console.log(' ' +
|
|
184
|
+
console.log(chalk.bold('Security:'));
|
|
185
|
+
console.log(' ' + chalk.green('API key stored in secure config'));
|
|
186
|
+
console.log(' ' + chalk.dim('Your key is encrypted and safe.'));
|
|
184
187
|
console.log();
|
|
185
|
-
console.log(
|
|
186
|
-
console.log(' ' +
|
|
187
|
-
console.log(' ' +
|
|
188
|
-
console.log(' ' +
|
|
189
|
-
console.log(' ' +
|
|
188
|
+
console.log(chalk.bold('Next steps:'));
|
|
189
|
+
console.log(' ' + chalk.cyan('aribot diagrams') + ' - List your diagrams');
|
|
190
|
+
console.log(' ' + chalk.cyan('aribot analyze <file>') + ' - Analyze a new diagram');
|
|
191
|
+
console.log(' ' + chalk.cyan('aribot status') + ' - Check API status');
|
|
192
|
+
console.log(' ' + chalk.cyan('aribot --help') + ' - See all commands');
|
|
190
193
|
}
|
|
191
194
|
else {
|
|
192
|
-
spinner.fail(
|
|
195
|
+
spinner.fail(chalk.red('Authentication failed'));
|
|
193
196
|
console.log();
|
|
194
197
|
try {
|
|
195
198
|
const error = await response.json();
|
|
196
|
-
console.log(
|
|
199
|
+
console.log(chalk.red(error.message || error.detail || 'Invalid API key'));
|
|
197
200
|
}
|
|
198
201
|
catch {
|
|
199
202
|
if (response.status === 401) {
|
|
200
|
-
console.log(
|
|
203
|
+
console.log(chalk.red('Invalid API key. Please check and try again.'));
|
|
201
204
|
}
|
|
202
205
|
else if (response.status === 403) {
|
|
203
|
-
console.log(
|
|
206
|
+
console.log(chalk.red('API key is disabled or expired.'));
|
|
204
207
|
}
|
|
205
208
|
else {
|
|
206
|
-
console.log(
|
|
209
|
+
console.log(chalk.red(`Authentication failed (HTTP ${response.status})`));
|
|
207
210
|
}
|
|
208
211
|
}
|
|
209
212
|
console.log();
|
|
210
|
-
console.log(
|
|
211
|
-
console.log(' ' +
|
|
213
|
+
console.log(chalk.dim('Need a new API key? Visit:'));
|
|
214
|
+
console.log(' ' + chalk.cyan('https://developer.ayurak.com'));
|
|
212
215
|
}
|
|
213
216
|
}
|
|
214
217
|
catch (error) {
|
|
215
|
-
spinner.fail(
|
|
218
|
+
spinner.fail(chalk.red('Authentication failed'));
|
|
216
219
|
console.log();
|
|
217
220
|
if (error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED') {
|
|
218
|
-
console.log(
|
|
219
|
-
console.log(
|
|
221
|
+
console.log(chalk.red('Could not connect to Aribot servers.'));
|
|
222
|
+
console.log(chalk.dim('Please check your internet connection.'));
|
|
220
223
|
}
|
|
221
224
|
else {
|
|
222
225
|
console.error(error.message || error);
|
|
@@ -229,7 +232,7 @@ program
|
|
|
229
232
|
.description('Remove stored credentials')
|
|
230
233
|
.action(() => {
|
|
231
234
|
config.delete('apiKey');
|
|
232
|
-
console.log(
|
|
235
|
+
console.log(chalk.green('Logged out successfully.'));
|
|
233
236
|
});
|
|
234
237
|
// List diagrams
|
|
235
238
|
program
|
|
@@ -237,21 +240,21 @@ program
|
|
|
237
240
|
.description('List all your diagrams')
|
|
238
241
|
.option('-l, --limit <number>', 'Number of diagrams to show', '10')
|
|
239
242
|
.action(async (options) => {
|
|
240
|
-
const spinner = (
|
|
243
|
+
const spinner = ora('Fetching diagrams...').start();
|
|
241
244
|
try {
|
|
242
245
|
const data = await apiRequest(`/v2/threat-modeling/diagrams/?limit=${options.limit}`);
|
|
243
246
|
spinner.stop();
|
|
244
|
-
console.log(
|
|
247
|
+
console.log(chalk.bold('\nYour Diagrams:\n'));
|
|
245
248
|
if (!data.results?.length) {
|
|
246
|
-
console.log(
|
|
249
|
+
console.log(chalk.dim('No diagrams found. Create one at https://developer.ayurak.com'));
|
|
247
250
|
return;
|
|
248
251
|
}
|
|
249
252
|
data.results.forEach((d) => {
|
|
250
|
-
const status = d.stage === 'completed' ?
|
|
253
|
+
const status = d.stage === 'completed' ? chalk.green('✓') : chalk.yellow('⋯');
|
|
251
254
|
const name = d.name || d.filename || 'Unnamed';
|
|
252
|
-
console.log(`${status} ${
|
|
255
|
+
console.log(`${status} ${chalk.cyan(d.id.slice(0, 8))} ${name} ${chalk.dim(d.threats_count + ' threats')}`);
|
|
253
256
|
});
|
|
254
|
-
console.log(
|
|
257
|
+
console.log(chalk.dim(`\nShowing ${data.results.length} of ${data.count} diagrams`));
|
|
255
258
|
}
|
|
256
259
|
catch (error) {
|
|
257
260
|
spinner.fail('Failed to fetch diagrams');
|
|
@@ -265,16 +268,16 @@ program
|
|
|
265
268
|
.option('-n, --name <name>', 'Diagram name')
|
|
266
269
|
.option('--auto-threats', 'Automatically generate AI threats', true)
|
|
267
270
|
.action(async (file, options) => {
|
|
268
|
-
if (!
|
|
269
|
-
console.error(
|
|
271
|
+
if (!fs.existsSync(file)) {
|
|
272
|
+
console.error(chalk.red(`File not found: ${file}`));
|
|
270
273
|
process.exit(1);
|
|
271
274
|
}
|
|
272
|
-
const spinner = (
|
|
275
|
+
const spinner = ora('Uploading diagram...').start();
|
|
273
276
|
try {
|
|
274
277
|
const fetch = (await import('node-fetch')).default;
|
|
275
|
-
const form = new
|
|
276
|
-
form.append('file',
|
|
277
|
-
form.append('name', options.name ||
|
|
278
|
+
const form = new FormData();
|
|
279
|
+
form.append('file', fs.createReadStream(file));
|
|
280
|
+
form.append('name', options.name || path.basename(file, path.extname(file)));
|
|
278
281
|
form.append('auto_generate_threats', options.autoThreats ? 'true' : 'false');
|
|
279
282
|
const apiKey = config.get('apiKey');
|
|
280
283
|
const response = await fetch(`${API_BASE}/v2/threat-modeling/diagrams/upload-analyze/`, {
|
|
@@ -287,12 +290,12 @@ program
|
|
|
287
290
|
}
|
|
288
291
|
const data = await response.json();
|
|
289
292
|
spinner.succeed('Diagram uploaded!');
|
|
290
|
-
console.log(
|
|
291
|
-
console.log(` ID: ${
|
|
293
|
+
console.log(chalk.bold('\nDiagram Created:'));
|
|
294
|
+
console.log(` ID: ${chalk.cyan(data.id)}`);
|
|
292
295
|
console.log(` Name: ${data.name}`);
|
|
293
296
|
console.log(` Status: ${data.status}`);
|
|
294
297
|
if (options.autoThreats) {
|
|
295
|
-
const threatSpinner = (
|
|
298
|
+
const threatSpinner = ora('Generating AI threats...').start();
|
|
296
299
|
// Poll for completion
|
|
297
300
|
let attempts = 0;
|
|
298
301
|
while (attempts < 30) {
|
|
@@ -305,7 +308,7 @@ program
|
|
|
305
308
|
attempts++;
|
|
306
309
|
}
|
|
307
310
|
}
|
|
308
|
-
console.log(
|
|
311
|
+
console.log(chalk.dim(`\nView at: https://developer.ayurak.com/diagrams/${data.id}`));
|
|
309
312
|
}
|
|
310
313
|
catch (error) {
|
|
311
314
|
spinner.fail('Analysis failed');
|
|
@@ -318,7 +321,7 @@ program
|
|
|
318
321
|
.description('List threats for a diagram')
|
|
319
322
|
.option('-s, --severity <level>', 'Filter by severity (critical, high, medium, low)')
|
|
320
323
|
.action(async (diagramId, options) => {
|
|
321
|
-
const spinner = (
|
|
324
|
+
const spinner = ora('Fetching threats...').start();
|
|
322
325
|
try {
|
|
323
326
|
// Resolve short UUID to full UUID
|
|
324
327
|
const fullId = await resolveDiagramId(diagramId);
|
|
@@ -328,21 +331,21 @@ program
|
|
|
328
331
|
}
|
|
329
332
|
const data = await apiRequest(url);
|
|
330
333
|
spinner.stop();
|
|
331
|
-
console.log(
|
|
334
|
+
console.log(chalk.bold('\nThreats:\n'));
|
|
332
335
|
const severityColors = {
|
|
333
|
-
critical:
|
|
334
|
-
high:
|
|
335
|
-
medium:
|
|
336
|
-
low:
|
|
336
|
+
critical: chalk.red,
|
|
337
|
+
high: chalk.yellow,
|
|
338
|
+
medium: chalk.blue,
|
|
339
|
+
low: chalk.dim
|
|
337
340
|
};
|
|
338
341
|
const threats = data.threats || data.results || [];
|
|
339
342
|
threats.forEach((t) => {
|
|
340
|
-
const color = severityColors[t.severity] ||
|
|
343
|
+
const color = severityColors[t.severity] || chalk.white;
|
|
341
344
|
console.log(`${color(`[${t.severity?.toUpperCase() || 'UNKNOWN'}]`)} ${t.title || t.name}`);
|
|
342
|
-
console.log(
|
|
345
|
+
console.log(chalk.dim(` Category: ${t.category || t.stride_category || 'N/A'} | ID: ${String(t.id).slice(0, 8)}`));
|
|
343
346
|
console.log();
|
|
344
347
|
});
|
|
345
|
-
console.log(
|
|
348
|
+
console.log(chalk.dim(`Total: ${threats.length} threats`));
|
|
346
349
|
}
|
|
347
350
|
catch (error) {
|
|
348
351
|
spinner.fail('Failed to fetch threats');
|
|
@@ -356,7 +359,7 @@ program
|
|
|
356
359
|
.option('-f, --format <format>', 'Export format (pdf, json, csv)', 'json')
|
|
357
360
|
.option('-o, --output <file>', 'Output file path')
|
|
358
361
|
.action(async (diagramId, options) => {
|
|
359
|
-
const spinner = (
|
|
362
|
+
const spinner = ora(`Exporting ${options.format.toUpperCase()} report...`).start();
|
|
360
363
|
try {
|
|
361
364
|
// Resolve short UUID to full UUID
|
|
362
365
|
const fullId = await resolveDiagramId(diagramId);
|
|
@@ -380,13 +383,13 @@ program
|
|
|
380
383
|
const outputPath = options.output || `aribot-report-${fullId.slice(0, 8)}.${options.format}`;
|
|
381
384
|
if (options.format === 'json') {
|
|
382
385
|
const data = await response.json();
|
|
383
|
-
|
|
386
|
+
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));
|
|
384
387
|
}
|
|
385
388
|
else {
|
|
386
389
|
const buffer = await response.arrayBuffer();
|
|
387
|
-
|
|
390
|
+
fs.writeFileSync(outputPath, Buffer.from(buffer));
|
|
388
391
|
}
|
|
389
|
-
spinner.succeed(`Report saved to ${
|
|
392
|
+
spinner.succeed(`Report saved to ${chalk.cyan(outputPath)}`);
|
|
390
393
|
}
|
|
391
394
|
catch (error) {
|
|
392
395
|
spinner.fail('Export failed');
|
|
@@ -398,7 +401,7 @@ program
|
|
|
398
401
|
.command('generate-threats <diagram-id>')
|
|
399
402
|
.description('Generate AI threats for an existing diagram')
|
|
400
403
|
.action(async (diagramId) => {
|
|
401
|
-
const spinner = (
|
|
404
|
+
const spinner = ora('Generating AI threats...').start();
|
|
402
405
|
try {
|
|
403
406
|
// Resolve short UUID to full UUID
|
|
404
407
|
const fullId = await resolveDiagramId(diagramId);
|
|
@@ -431,8 +434,8 @@ program
|
|
|
431
434
|
.action(async () => {
|
|
432
435
|
const apiKey = config.get('apiKey');
|
|
433
436
|
if (!apiKey) {
|
|
434
|
-
console.log(
|
|
435
|
-
console.log(
|
|
437
|
+
console.log(chalk.yellow('Not authenticated'));
|
|
438
|
+
console.log(chalk.dim('Run: aribot login'));
|
|
436
439
|
return;
|
|
437
440
|
}
|
|
438
441
|
try {
|
|
@@ -441,7 +444,7 @@ program
|
|
|
441
444
|
apiRequest('/v1/developer/api-keys/')
|
|
442
445
|
]);
|
|
443
446
|
const company = keysData?.[0]?.company_name || userData.company || 'N/A';
|
|
444
|
-
console.log(
|
|
447
|
+
console.log(chalk.green('Authenticated as:'));
|
|
445
448
|
console.log(` Email: ${userData.email}`);
|
|
446
449
|
console.log(` Company: ${company}`);
|
|
447
450
|
if (keysData?.[0]) {
|
|
@@ -449,7 +452,7 @@ program
|
|
|
449
452
|
}
|
|
450
453
|
}
|
|
451
454
|
catch {
|
|
452
|
-
console.log(
|
|
455
|
+
console.log(chalk.yellow('API key stored but validation failed'));
|
|
453
456
|
}
|
|
454
457
|
});
|
|
455
458
|
// Status command - Check API status and rate limits
|
|
@@ -457,29 +460,29 @@ program
|
|
|
457
460
|
.command('status')
|
|
458
461
|
.description('Check API status and rate limits')
|
|
459
462
|
.action(async () => {
|
|
460
|
-
const spinner = (
|
|
463
|
+
const spinner = ora('Checking API status...').start();
|
|
461
464
|
try {
|
|
462
465
|
const fetch = (await import('node-fetch')).default;
|
|
463
466
|
// Check health endpoint (no auth required)
|
|
464
467
|
const healthResponse = await fetch(`${API_BASE}/health/`);
|
|
465
468
|
const health = await healthResponse.json();
|
|
466
469
|
spinner.stop();
|
|
467
|
-
console.log(
|
|
468
|
-
console.log(` Status: ${health.status === 'healthy' ?
|
|
469
|
-
console.log(` Version: ${
|
|
470
|
-
console.log(` Features: ${health.features_enabled ?
|
|
470
|
+
console.log(chalk.bold('\nAPI Status:\n'));
|
|
471
|
+
console.log(` Status: ${health.status === 'healthy' ? chalk.green('✓ Healthy') : chalk.red('✗ Unhealthy')}`);
|
|
472
|
+
console.log(` Version: ${chalk.cyan(health.version || 'N/A')}`);
|
|
473
|
+
console.log(` Features: ${health.features_enabled ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
|
|
471
474
|
// Check rate limits if authenticated
|
|
472
475
|
const apiKey = config.get('apiKey');
|
|
473
476
|
if (apiKey) {
|
|
474
477
|
try {
|
|
475
478
|
const limits = await apiRequest('/v2/developer-portal/rate-limits/usage/');
|
|
476
|
-
console.log(
|
|
479
|
+
console.log(chalk.bold('\nRate Limits:\n'));
|
|
477
480
|
console.log(` Requests/min: ${limits.requests_per_minute?.used || 0}/${limits.requests_per_minute?.limit || 'unlimited'}`);
|
|
478
481
|
console.log(` Requests/hour: ${limits.requests_per_hour?.used || 0}/${limits.requests_per_hour?.limit || 'unlimited'}`);
|
|
479
482
|
console.log(` Requests/day: ${limits.requests_per_day?.used || 0}/${limits.requests_per_day?.limit || 'unlimited'}`);
|
|
480
483
|
}
|
|
481
484
|
catch {
|
|
482
|
-
console.log(
|
|
485
|
+
console.log(chalk.dim('\nRate limit info requires authentication'));
|
|
483
486
|
}
|
|
484
487
|
}
|
|
485
488
|
}
|
|
@@ -497,7 +500,7 @@ program
|
|
|
497
500
|
.option('--list-standards', 'List all available compliance standards')
|
|
498
501
|
.action(async (diagramId, options) => {
|
|
499
502
|
if (options.listStandards) {
|
|
500
|
-
console.log(
|
|
503
|
+
console.log(chalk.bold('\nSupported Compliance Standards:\n'));
|
|
501
504
|
const standards = [
|
|
502
505
|
'SOC2', 'ISO27001', 'ISO27017', 'ISO27018', 'ISO22301',
|
|
503
506
|
'NIST-CSF', 'NIST-800-53', 'NIST-800-171',
|
|
@@ -509,16 +512,16 @@ program
|
|
|
509
512
|
'SOX', 'GLBA', 'FISMA',
|
|
510
513
|
'CSA-CCM', 'MITRE-ATT&CK', 'OWASP-TOP-10',
|
|
511
514
|
];
|
|
512
|
-
standards.forEach(s => console.log(` ${
|
|
515
|
+
standards.forEach(s => console.log(` ${chalk.cyan('•')} ${s}`));
|
|
513
516
|
return;
|
|
514
517
|
}
|
|
515
518
|
if (!diagramId) {
|
|
516
|
-
console.error(
|
|
517
|
-
console.log(
|
|
518
|
-
console.log(
|
|
519
|
+
console.error(chalk.red('Error: diagram-id is required for compliance assessment'));
|
|
520
|
+
console.log(chalk.dim('Usage: aribot compliance <diagram-id> --standard SOC2'));
|
|
521
|
+
console.log(chalk.dim(' aribot compliance --list-standards'));
|
|
519
522
|
process.exit(1);
|
|
520
523
|
}
|
|
521
|
-
const spinner = (
|
|
524
|
+
const spinner = ora(`Running ${options.standard} compliance assessment...`).start();
|
|
522
525
|
try {
|
|
523
526
|
// Resolve short UUID to full UUID
|
|
524
527
|
const fullId = await resolveDiagramId(diagramId);
|
|
@@ -530,15 +533,15 @@ program
|
|
|
530
533
|
})
|
|
531
534
|
});
|
|
532
535
|
spinner.succeed('Compliance assessment complete!');
|
|
533
|
-
console.log(
|
|
534
|
-
console.log(` Score: ${data.score >= 80 ?
|
|
535
|
-
console.log(` Passed Controls: ${
|
|
536
|
-
console.log(` Failed Controls: ${
|
|
537
|
-
console.log(` Status: ${data.status === 'compliant' ?
|
|
536
|
+
console.log(chalk.bold(`\n${options.standard} Compliance Report:\n`));
|
|
537
|
+
console.log(` Score: ${data.score >= 80 ? chalk.green(data.score + '%') : data.score >= 60 ? chalk.yellow(data.score + '%') : chalk.red(data.score + '%')}`);
|
|
538
|
+
console.log(` Passed Controls: ${chalk.green(data.passed_controls || 0)}`);
|
|
539
|
+
console.log(` Failed Controls: ${chalk.red(data.failed_controls || 0)}`);
|
|
540
|
+
console.log(` Status: ${data.status === 'compliant' ? chalk.green('Compliant') : chalk.yellow('Non-Compliant')}`);
|
|
538
541
|
if (data.findings?.length > 0) {
|
|
539
|
-
console.log(
|
|
542
|
+
console.log(chalk.bold('\nTop Findings:\n'));
|
|
540
543
|
data.findings.slice(0, 5).forEach((f) => {
|
|
541
|
-
const severityColor = f.severity === 'high' ?
|
|
544
|
+
const severityColor = f.severity === 'high' ? chalk.red : f.severity === 'medium' ? chalk.yellow : chalk.dim;
|
|
542
545
|
console.log(` ${severityColor(`[${f.severity?.toUpperCase()}]`)} ${f.title || f.control_id}`);
|
|
543
546
|
});
|
|
544
547
|
}
|
|
@@ -558,7 +561,7 @@ program
|
|
|
558
561
|
.option('--cost <diagram-id>', 'AI-powered cost intelligence for diagram')
|
|
559
562
|
.option('--dashboard', 'Show economic intelligence dashboard')
|
|
560
563
|
.action(async (options) => {
|
|
561
|
-
const spinner = (
|
|
564
|
+
const spinner = ora('Calculating...').start();
|
|
562
565
|
try {
|
|
563
566
|
if (options.roi) {
|
|
564
567
|
const investment = parseFloat(options.roi);
|
|
@@ -571,12 +574,12 @@ program
|
|
|
571
574
|
})
|
|
572
575
|
});
|
|
573
576
|
spinner.succeed('ROI Analysis Complete!');
|
|
574
|
-
console.log(
|
|
575
|
-
console.log(` Investment: ${
|
|
576
|
-
console.log(` Expected ROI: ${
|
|
577
|
-
console.log(` NPV: ${
|
|
578
|
-
console.log(` Payback Period: ${
|
|
579
|
-
console.log(` Risk Reduction: ${
|
|
577
|
+
console.log(chalk.bold('\nSecurity ROI Analysis:\n'));
|
|
578
|
+
console.log(` Investment: ${chalk.cyan('$' + investment.toLocaleString())}`);
|
|
579
|
+
console.log(` Expected ROI: ${chalk.green((data.roi_percentage || data.roi || 0) + '%')}`);
|
|
580
|
+
console.log(` NPV: ${chalk.green('$' + (data.npv || 0).toLocaleString())}`);
|
|
581
|
+
console.log(` Payback Period: ${chalk.cyan((data.payback_months || data.payback_period || 0) + ' months')}`);
|
|
582
|
+
console.log(` Risk Reduction: ${chalk.green('50%')}`);
|
|
580
583
|
}
|
|
581
584
|
else if (options.tco) {
|
|
582
585
|
// TCO per diagram using economic intelligence
|
|
@@ -593,25 +596,25 @@ program
|
|
|
593
596
|
spinner.succeed('TCO Analysis Complete!');
|
|
594
597
|
const tco = data.tco || data;
|
|
595
598
|
const diagramName = tco.diagram_name || 'Diagram';
|
|
596
|
-
console.log(
|
|
599
|
+
console.log(chalk.bold(`\nTotal Cost of Ownership - ${diagramName}:\n`));
|
|
597
600
|
// Cost summary
|
|
598
|
-
console.log(` Monthly Cost: ${
|
|
599
|
-
console.log(` Annual Cost: ${
|
|
600
|
-
console.log(` 3-Year TCO: ${
|
|
601
|
+
console.log(` Monthly Cost: ${chalk.cyan('$' + (tco.monthly_cost || tco.total_monthly || 0).toLocaleString())}`);
|
|
602
|
+
console.log(` Annual Cost: ${chalk.cyan('$' + (tco.annual_cost || tco.year_1 || 0).toLocaleString())}`);
|
|
603
|
+
console.log(` 3-Year TCO: ${chalk.yellow('$' + (tco.total_3_year || tco.total_cost || 0).toLocaleString())}`);
|
|
601
604
|
// Cost breakdown by component
|
|
602
605
|
if (tco.cost_breakdown) {
|
|
603
|
-
console.log(
|
|
606
|
+
console.log(chalk.bold('\nCost Breakdown:\n'));
|
|
604
607
|
const breakdown = tco.cost_breakdown;
|
|
605
608
|
Object.entries(breakdown).forEach(([key, value]) => {
|
|
606
609
|
if (typeof value === 'number') {
|
|
607
610
|
const label = key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
608
|
-
console.log(` ${label}: ${
|
|
611
|
+
console.log(` ${label}: ${chalk.cyan('$' + value.toLocaleString())}`);
|
|
609
612
|
}
|
|
610
613
|
});
|
|
611
614
|
}
|
|
612
615
|
// Customizable costs info
|
|
613
616
|
if (tco.customizable) {
|
|
614
|
-
console.log(
|
|
617
|
+
console.log(chalk.dim('\nCosts can be customized in the Economic Intelligence panel'));
|
|
615
618
|
}
|
|
616
619
|
}
|
|
617
620
|
else if (options.analyze) {
|
|
@@ -620,32 +623,32 @@ program
|
|
|
620
623
|
body: JSON.stringify({ diagram_id: options.analyze })
|
|
621
624
|
});
|
|
622
625
|
spinner.succeed('Cost Analysis Complete!');
|
|
623
|
-
console.log(
|
|
624
|
-
console.log(` Estimated Monthly: ${
|
|
625
|
-
console.log(` Security Costs: ${
|
|
626
|
-
console.log(` Breach Risk Cost: ${
|
|
626
|
+
console.log(chalk.bold('\nDiagram Cost Analysis:\n'));
|
|
627
|
+
console.log(` Estimated Monthly: ${chalk.cyan('$' + (data.monthly_estimate || 0).toLocaleString())}`);
|
|
628
|
+
console.log(` Security Costs: ${chalk.yellow('$' + (data.security_cost || 0).toLocaleString())}`);
|
|
629
|
+
console.log(` Breach Risk Cost: ${chalk.red('$' + (data.breach_risk_cost || 0).toLocaleString())}`);
|
|
627
630
|
}
|
|
628
631
|
else if (options.cost) {
|
|
629
632
|
// Diagram-specific cost analysis
|
|
630
633
|
const fullId = await resolveDiagramId(options.cost);
|
|
631
634
|
const data = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/cost-intelligence/`);
|
|
632
635
|
spinner.succeed('Cost analysis complete!');
|
|
633
|
-
console.log(
|
|
636
|
+
console.log(chalk.bold('\nDiagram Cost Analysis:\n'));
|
|
634
637
|
const summary = data.cost_summary || data;
|
|
635
|
-
console.log(` Monthly Cost: ${
|
|
636
|
-
console.log(` Annual Cost: ${
|
|
637
|
-
console.log(` Component Count: ${
|
|
638
|
-
console.log(` Region: ${
|
|
638
|
+
console.log(` Monthly Cost: ${chalk.cyan('$' + (summary.total_monthly || summary.monthly || 0).toLocaleString())}`);
|
|
639
|
+
console.log(` Annual Cost: ${chalk.yellow('$' + (summary.total_annual || (summary.total_monthly || 0) * 12).toLocaleString())}`);
|
|
640
|
+
console.log(` Component Count: ${chalk.white(summary.component_count || data.components?.length || 0)}`);
|
|
641
|
+
console.log(` Region: ${chalk.white(summary.region || 'us-east-1')}`);
|
|
639
642
|
if (data.cost_breakdown?.length > 0) {
|
|
640
|
-
console.log(
|
|
643
|
+
console.log(chalk.bold('\nCost Breakdown:\n'));
|
|
641
644
|
data.cost_breakdown.slice(0, 5).forEach((c) => {
|
|
642
|
-
console.log(` ${
|
|
645
|
+
console.log(` ${chalk.cyan('•')} ${c.name || c.component}: ${chalk.yellow('$' + (c.monthly || c.cost || 0).toLocaleString())}/mo`);
|
|
643
646
|
});
|
|
644
647
|
}
|
|
645
648
|
if (data.recommendations?.length > 0) {
|
|
646
|
-
console.log(
|
|
649
|
+
console.log(chalk.bold('\nOptimization Recommendations:\n'));
|
|
647
650
|
data.recommendations.slice(0, 3).forEach((r) => {
|
|
648
|
-
console.log(` ${
|
|
651
|
+
console.log(` ${chalk.green('•')} ${r.title || r.description || r}`);
|
|
649
652
|
});
|
|
650
653
|
}
|
|
651
654
|
}
|
|
@@ -653,28 +656,28 @@ program
|
|
|
653
656
|
// Get economic intelligence from threat modeling endpoint
|
|
654
657
|
const data = await apiRequest('/v2/threat-modeling/economic-intelligence/');
|
|
655
658
|
spinner.succeed('Dashboard loaded!');
|
|
656
|
-
console.log(
|
|
659
|
+
console.log(chalk.bold('\nEconomic Intelligence Dashboard:\n'));
|
|
657
660
|
const summary = data.company_summary || data.summary || data;
|
|
658
|
-
console.log(` Total Monthly: ${
|
|
659
|
-
console.log(` Total Annual: ${
|
|
660
|
-
console.log(` Total Diagrams: ${
|
|
661
|
-
console.log(` Region: ${
|
|
661
|
+
console.log(` Total Monthly: ${chalk.cyan('$' + (summary.total_monthly || summary.total_security_spend || 0).toLocaleString())}`);
|
|
662
|
+
console.log(` Total Annual: ${chalk.yellow('$' + (summary.total_annual || 0).toLocaleString())}`);
|
|
663
|
+
console.log(` Total Diagrams: ${chalk.white(summary.total_diagrams || 0)}`);
|
|
664
|
+
console.log(` Region: ${chalk.white(summary.region || 'us-east-1')}`);
|
|
662
665
|
if (data.top_cost_drivers?.length > 0) {
|
|
663
|
-
console.log(
|
|
666
|
+
console.log(chalk.bold('\nTop Cost Drivers:\n'));
|
|
664
667
|
data.top_cost_drivers.slice(0, 5).forEach((d) => {
|
|
665
|
-
console.log(` ${
|
|
668
|
+
console.log(` ${chalk.cyan('•')} ${d.name}: ${chalk.yellow('$' + (d.monthly_cost || 0).toLocaleString())}/mo (${d.component_count || 0} components)`);
|
|
666
669
|
});
|
|
667
670
|
}
|
|
668
671
|
if (data.intelligence?.recommendations?.length > 0) {
|
|
669
|
-
console.log(
|
|
672
|
+
console.log(chalk.bold('\nAI Recommendations:\n'));
|
|
670
673
|
data.intelligence.recommendations.slice(0, 3).forEach((r) => {
|
|
671
|
-
console.log(` ${
|
|
674
|
+
console.log(` ${chalk.green('•')} ${r.title || r.description || r}`);
|
|
672
675
|
});
|
|
673
676
|
}
|
|
674
677
|
}
|
|
675
678
|
else {
|
|
676
679
|
spinner.stop();
|
|
677
|
-
console.log(
|
|
680
|
+
console.log(chalk.yellow('Usage: aribot economics [--roi <amount>] [--tco <diagram-id>] [--analyze <diagram-id>] [--dashboard]'));
|
|
678
681
|
}
|
|
679
682
|
}
|
|
680
683
|
catch (error) {
|
|
@@ -691,28 +694,28 @@ program
|
|
|
691
694
|
.option('--dashboard', 'Show cloud security dashboard')
|
|
692
695
|
.option('-s, --severity <level>', 'Filter findings by severity (critical, high, medium, low)')
|
|
693
696
|
.action(async (options) => {
|
|
694
|
-
const spinner = (
|
|
697
|
+
const spinner = ora('Scanning cloud security...').start();
|
|
695
698
|
try {
|
|
696
699
|
if (options.scan) {
|
|
697
700
|
const provider = typeof options.scan === 'string' ? options.scan : undefined;
|
|
698
701
|
// Use security posture endpoint
|
|
699
702
|
const data = await apiRequest('/v2/compliances/dashboard/cloud-stats/' + (provider ? `?provider=${provider}` : ''));
|
|
700
703
|
spinner.succeed('Cloud security scan complete!');
|
|
701
|
-
console.log(
|
|
704
|
+
console.log(chalk.bold('\nCloud Security Posture:\n'));
|
|
702
705
|
const stats = data.stats || data;
|
|
703
|
-
console.log(` Security Score: ${stats.security_score >= 80 ?
|
|
704
|
-
console.log(` Total Resources: ${
|
|
705
|
-
console.log(` Compliant: ${
|
|
706
|
-
console.log(` Non-Compliant: ${
|
|
707
|
-
console.log(` Critical Issues: ${
|
|
706
|
+
console.log(` Security Score: ${stats.security_score >= 80 ? chalk.green(stats.security_score + '%') : chalk.yellow(stats.security_score + '%' || 'N/A')}`);
|
|
707
|
+
console.log(` Total Resources: ${chalk.cyan(stats.total_resources || stats.resource_count || 0)}`);
|
|
708
|
+
console.log(` Compliant: ${chalk.green(stats.compliant_resources || stats.compliant || 0)}`);
|
|
709
|
+
console.log(` Non-Compliant: ${chalk.red(stats.non_compliant_resources || stats.non_compliant || 0)}`);
|
|
710
|
+
console.log(` Critical Issues: ${chalk.red(stats.critical_findings || stats.critical || 0)}`);
|
|
708
711
|
if (provider) {
|
|
709
|
-
console.log(`\n Provider: ${
|
|
712
|
+
console.log(`\n Provider: ${chalk.cyan(provider.toUpperCase())}`);
|
|
710
713
|
}
|
|
711
714
|
// Show provider breakdown if available
|
|
712
715
|
if (data.by_provider && !provider) {
|
|
713
|
-
console.log(
|
|
716
|
+
console.log(chalk.bold('\nBy Provider:\n'));
|
|
714
717
|
Object.entries(data.by_provider).forEach(([p, s]) => {
|
|
715
|
-
console.log(` ${
|
|
718
|
+
console.log(` ${chalk.cyan(p.toUpperCase().padEnd(8))} Resources: ${s.count || 0} | Score: ${s.score || 'N/A'}%`);
|
|
716
719
|
});
|
|
717
720
|
}
|
|
718
721
|
}
|
|
@@ -724,37 +727,37 @@ program
|
|
|
724
727
|
}
|
|
725
728
|
const data = await apiRequest(url);
|
|
726
729
|
spinner.stop();
|
|
727
|
-
console.log(
|
|
730
|
+
console.log(chalk.bold('\nCloud Security Findings:\n'));
|
|
728
731
|
const findings = data.results || data.findings || [];
|
|
729
732
|
if (findings.length === 0) {
|
|
730
|
-
console.log(
|
|
733
|
+
console.log(chalk.green(' No open findings! Your cloud is secure.'));
|
|
731
734
|
}
|
|
732
735
|
else {
|
|
733
736
|
const severityColors = {
|
|
734
|
-
critical:
|
|
735
|
-
high:
|
|
736
|
-
medium:
|
|
737
|
-
low:
|
|
737
|
+
critical: chalk.red,
|
|
738
|
+
high: chalk.yellow,
|
|
739
|
+
medium: chalk.blue,
|
|
740
|
+
low: chalk.dim
|
|
738
741
|
};
|
|
739
742
|
findings.slice(0, 10).forEach((f) => {
|
|
740
|
-
const color = severityColors[f.severity] ||
|
|
743
|
+
const color = severityColors[f.severity] || chalk.white;
|
|
741
744
|
console.log(` ${color(`[${f.severity?.toUpperCase()}]`)} ${f.title}`);
|
|
742
|
-
console.log(
|
|
745
|
+
console.log(chalk.dim(` Resource: ${f.resource_type || 'N/A'} | Policy: ${f.policy || 'N/A'}`));
|
|
743
746
|
});
|
|
744
|
-
console.log(
|
|
747
|
+
console.log(chalk.dim(`\nShowing ${Math.min(10, findings.length)} of ${findings.length} findings`));
|
|
745
748
|
}
|
|
746
749
|
}
|
|
747
750
|
else if (options.dashboard) {
|
|
748
751
|
const data = await apiRequest('/v2/compliances/dashboard/cloud-stats/');
|
|
749
752
|
spinner.succeed('Dashboard loaded!');
|
|
750
|
-
console.log(
|
|
751
|
-
console.log(` Security Score: ${data.security_score >= 80 ?
|
|
752
|
-
console.log(` Total Resources: ${
|
|
753
|
-
console.log(` Open Findings: ${
|
|
753
|
+
console.log(chalk.bold('\nCloud Security Dashboard:\n'));
|
|
754
|
+
console.log(` Security Score: ${data.security_score >= 80 ? chalk.green(data.security_score) : chalk.yellow(data.security_score || 'N/A')}`);
|
|
755
|
+
console.log(` Total Resources: ${chalk.cyan(data.total_resources || 0)}`);
|
|
756
|
+
console.log(` Open Findings: ${chalk.yellow(data.open_findings || 0)}`);
|
|
754
757
|
}
|
|
755
758
|
else {
|
|
756
759
|
spinner.stop();
|
|
757
|
-
console.log(
|
|
760
|
+
console.log(chalk.yellow('Usage: aribot cloud-security [--scan [provider]] [--findings] [--dashboard]'));
|
|
758
761
|
}
|
|
759
762
|
}
|
|
760
763
|
catch (error) {
|
|
@@ -778,26 +781,26 @@ program
|
|
|
778
781
|
.option('--patterns <diagram-id>', 'Detect AI patterns in diagram')
|
|
779
782
|
.action(async (options) => {
|
|
780
783
|
if (options.methodologies) {
|
|
781
|
-
const spinner = (
|
|
784
|
+
const spinner = ora('Fetching methodologies...').start();
|
|
782
785
|
try {
|
|
783
786
|
const data = await apiRequest('/v2/threat-engine/threat-models/');
|
|
784
787
|
spinner.stop();
|
|
785
|
-
console.log(
|
|
788
|
+
console.log(chalk.bold('\nThreat Modeling Methodologies:\n'));
|
|
786
789
|
(data.available_methodologies || []).forEach((m) => {
|
|
787
|
-
console.log(` ${
|
|
790
|
+
console.log(` ${chalk.cyan(m.name.toUpperCase().padEnd(12))} ${chalk.dim(m.description)}`);
|
|
788
791
|
});
|
|
789
|
-
console.log(
|
|
792
|
+
console.log(chalk.bold('\nRisk Levels:\n'));
|
|
790
793
|
(data.risk_levels || []).forEach((r) => {
|
|
791
|
-
console.log(` ${
|
|
794
|
+
console.log(` ${chalk.yellow(r.name.padEnd(12))} ${chalk.dim(r.description)}`);
|
|
792
795
|
});
|
|
793
|
-
console.log(
|
|
796
|
+
console.log(chalk.bold('\nCompliance Frameworks:\n'));
|
|
794
797
|
(data.compliance_frameworks || []).slice(0, 10).forEach((f) => {
|
|
795
|
-
console.log(` ${
|
|
798
|
+
console.log(` ${chalk.green(f.name.padEnd(20))} ${chalk.dim(f.description)}`);
|
|
796
799
|
});
|
|
797
|
-
console.log(
|
|
800
|
+
console.log(chalk.bold('\nEngine Capabilities:\n'));
|
|
798
801
|
const caps = data.engine_capabilities || {};
|
|
799
802
|
Object.entries(caps).forEach(([key, value]) => {
|
|
800
|
-
console.log(` ${value ?
|
|
803
|
+
console.log(` ${value ? chalk.green('✓') : chalk.red('✗')} ${key.replace(/_/g, ' ')}`);
|
|
801
804
|
});
|
|
802
805
|
}
|
|
803
806
|
catch (error) {
|
|
@@ -807,24 +810,24 @@ program
|
|
|
807
810
|
return;
|
|
808
811
|
}
|
|
809
812
|
if (options.intelligence) {
|
|
810
|
-
const spinner = (
|
|
813
|
+
const spinner = ora('Fetching threat intelligence...').start();
|
|
811
814
|
try {
|
|
812
815
|
const data = await apiRequest('/v2/threat-engine/threat-intelligence/');
|
|
813
816
|
spinner.stop();
|
|
814
|
-
console.log(
|
|
817
|
+
console.log(chalk.bold('\nThreat Intelligence Summary:\n'));
|
|
815
818
|
const intel = data.threat_intelligence || {};
|
|
816
|
-
console.log(` Integration: ${intel.integration_status === 'active' ?
|
|
817
|
-
console.log(` Cache TTL: ${
|
|
818
|
-
console.log(` Real-time Feeds: ${intel.real_time_feeds ?
|
|
819
|
-
console.log(` Correlation: ${intel.correlation_engine ?
|
|
820
|
-
console.log(
|
|
819
|
+
console.log(` Integration: ${intel.integration_status === 'active' ? chalk.green('Active') : chalk.red('Inactive')}`);
|
|
820
|
+
console.log(` Cache TTL: ${chalk.cyan(intel.cache_ttl + 's')}`);
|
|
821
|
+
console.log(` Real-time Feeds: ${intel.real_time_feeds ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
|
|
822
|
+
console.log(` Correlation: ${intel.correlation_engine ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
|
|
823
|
+
console.log(chalk.bold('\nSupported Indicators:\n'));
|
|
821
824
|
(intel.supported_indicators || []).forEach((i) => {
|
|
822
|
-
console.log(` ${
|
|
825
|
+
console.log(` ${chalk.cyan('•')} ${i}`);
|
|
823
826
|
});
|
|
824
|
-
console.log(
|
|
827
|
+
console.log(chalk.bold('\nVision 2040 Features:\n'));
|
|
825
828
|
const v2040 = data.vision_2040_features || {};
|
|
826
829
|
Object.entries(v2040).forEach(([key, value]) => {
|
|
827
|
-
console.log(` ${value ?
|
|
830
|
+
console.log(` ${value ? chalk.green('✓') : chalk.red('✗')} ${key.replace(/_/g, ' ')}`);
|
|
828
831
|
});
|
|
829
832
|
}
|
|
830
833
|
catch (error) {
|
|
@@ -835,10 +838,10 @@ program
|
|
|
835
838
|
}
|
|
836
839
|
if (options.attackPaths) {
|
|
837
840
|
if (!options.diagram) {
|
|
838
|
-
console.log(
|
|
841
|
+
console.log(chalk.yellow('Usage: aribot redteam --attack-paths --diagram <diagram-id>'));
|
|
839
842
|
return;
|
|
840
843
|
}
|
|
841
|
-
const spinner = (
|
|
844
|
+
const spinner = ora('Analyzing attack paths...').start();
|
|
842
845
|
try {
|
|
843
846
|
// First get the diagram components
|
|
844
847
|
const fullId = await resolveDiagramId(options.diagram);
|
|
@@ -855,8 +858,8 @@ program
|
|
|
855
858
|
}));
|
|
856
859
|
if (components.length < 2) {
|
|
857
860
|
spinner.stop();
|
|
858
|
-
console.log(
|
|
859
|
-
console.log(
|
|
861
|
+
console.log(chalk.yellow('\nInsufficient components for attack path analysis.'));
|
|
862
|
+
console.log(chalk.dim('Upload a diagram with at least 2 connected components.'));
|
|
860
863
|
return;
|
|
861
864
|
}
|
|
862
865
|
// Generate attack paths
|
|
@@ -870,30 +873,30 @@ program
|
|
|
870
873
|
})
|
|
871
874
|
});
|
|
872
875
|
spinner.succeed('Attack path analysis complete!');
|
|
873
|
-
console.log(
|
|
874
|
-
console.log(` Source: ${
|
|
875
|
-
console.log(` Target: ${
|
|
876
|
-
console.log(` Paths Found: ${
|
|
876
|
+
console.log(chalk.bold('\nAttack Path Analysis:\n'));
|
|
877
|
+
console.log(` Source: ${chalk.cyan(data.analysis_summary?.source_node || 'N/A')}`);
|
|
878
|
+
console.log(` Target: ${chalk.cyan(data.analysis_summary?.target_node || 'N/A')}`);
|
|
879
|
+
console.log(` Paths Found: ${chalk.yellow(data.analysis_summary?.total_paths_found || 0)}`);
|
|
877
880
|
const paths = data.attack_paths || [];
|
|
878
881
|
if (paths.length > 0) {
|
|
879
|
-
console.log(
|
|
882
|
+
console.log(chalk.bold('\nIdentified Attack Paths:\n'));
|
|
880
883
|
paths.slice(0, 5).forEach((p, i) => {
|
|
881
|
-
const riskColor = p.risk_score > 0.5 ?
|
|
882
|
-
console.log(` ${
|
|
884
|
+
const riskColor = p.risk_score > 0.5 ? chalk.red : p.risk_score > 0.2 ? chalk.yellow : chalk.green;
|
|
885
|
+
console.log(` ${chalk.bold(`Path ${i + 1}:`)} ${p.source_node} → ${p.target_node}`);
|
|
883
886
|
console.log(` Risk Score: ${riskColor((p.risk_score * 100).toFixed(1) + '%')}`);
|
|
884
|
-
console.log(` Likelihood: ${
|
|
885
|
-
console.log(` Impact: ${
|
|
886
|
-
console.log(` Steps: ${
|
|
887
|
+
console.log(` Likelihood: ${chalk.cyan((p.likelihood * 100).toFixed(1) + '%')}`);
|
|
888
|
+
console.log(` Impact: ${chalk.yellow((p.impact * 100).toFixed(1) + '%')}`);
|
|
889
|
+
console.log(` Steps: ${chalk.dim(p.steps?.length || 0)}`);
|
|
887
890
|
if (p.steps?.length > 0) {
|
|
888
891
|
p.steps.forEach((s, j) => {
|
|
889
|
-
console.log(
|
|
892
|
+
console.log(chalk.dim(` ${j + 1}. ${s.from_node} → ${s.to_node}`));
|
|
890
893
|
});
|
|
891
894
|
}
|
|
892
895
|
console.log();
|
|
893
896
|
});
|
|
894
897
|
}
|
|
895
898
|
else {
|
|
896
|
-
console.log(
|
|
899
|
+
console.log(chalk.green('\n No critical attack paths identified!'));
|
|
897
900
|
}
|
|
898
901
|
}
|
|
899
902
|
catch (error) {
|
|
@@ -903,7 +906,7 @@ program
|
|
|
903
906
|
return;
|
|
904
907
|
}
|
|
905
908
|
if (options.analyze) {
|
|
906
|
-
const spinner = (
|
|
909
|
+
const spinner = ora('Running comprehensive threat analysis...').start();
|
|
907
910
|
try {
|
|
908
911
|
const fullId = await resolveDiagramId(options.analyze);
|
|
909
912
|
const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
|
|
@@ -917,29 +920,29 @@ program
|
|
|
917
920
|
})
|
|
918
921
|
});
|
|
919
922
|
spinner.succeed('Comprehensive analysis complete!');
|
|
920
|
-
console.log(
|
|
921
|
-
console.log(` Diagram: ${
|
|
923
|
+
console.log(chalk.bold('\nComprehensive Threat Analysis:\n'));
|
|
924
|
+
console.log(` Diagram: ${chalk.cyan(diagramData.name || 'N/A')}`);
|
|
922
925
|
const analysis = data.analysis || data;
|
|
923
|
-
console.log(` Risk Level: ${analysis.risk_level === 'critical' ?
|
|
924
|
-
console.log(` Risk Score: ${
|
|
925
|
-
console.log(` Threats Found: ${
|
|
926
|
+
console.log(` Risk Level: ${analysis.risk_level === 'critical' ? chalk.red(analysis.risk_level) : chalk.yellow(analysis.risk_level || 'N/A')}`);
|
|
927
|
+
console.log(` Risk Score: ${chalk.red(analysis.risk_score || analysis.overall_score || 'N/A')}`);
|
|
928
|
+
console.log(` Threats Found: ${chalk.yellow(analysis.threat_count || analysis.total_threats || 0)}`);
|
|
926
929
|
const threats = analysis.threats || data.threats || [];
|
|
927
930
|
if (threats.length > 0) {
|
|
928
|
-
console.log(
|
|
931
|
+
console.log(chalk.bold('\nTop Threats:\n'));
|
|
929
932
|
threats.slice(0, 5).forEach((t) => {
|
|
930
|
-
const severity = t.severity === 'critical' ?
|
|
933
|
+
const severity = t.severity === 'critical' ? chalk.red : t.severity === 'high' ? chalk.yellow : chalk.blue;
|
|
931
934
|
console.log(` ${severity(`[${t.severity?.toUpperCase()}]`)} ${t.title || t.name}`);
|
|
932
|
-
console.log(
|
|
935
|
+
console.log(chalk.dim(` Category: ${t.category || 'N/A'} | MITRE: ${t.mitre_id || t.mitre_mapping || 'N/A'}`));
|
|
933
936
|
});
|
|
934
937
|
}
|
|
935
938
|
const recommendations = analysis.recommendations || data.recommendations || [];
|
|
936
939
|
if (recommendations.length > 0) {
|
|
937
|
-
console.log(
|
|
940
|
+
console.log(chalk.bold('\nTop Recommendations:\n'));
|
|
938
941
|
recommendations.slice(0, 3).forEach((r) => {
|
|
939
|
-
console.log(` ${
|
|
942
|
+
console.log(` ${chalk.green('→')} ${r.title || r.description || r}`);
|
|
940
943
|
});
|
|
941
944
|
}
|
|
942
|
-
console.log(
|
|
945
|
+
console.log(chalk.dim(`\nMethodologies: ${analysis.methodologies?.join(', ') || data.methodologies?.join(', ') || 'STRIDE, PASTA, NIST'}`));
|
|
943
946
|
}
|
|
944
947
|
catch (error) {
|
|
945
948
|
spinner.fail('Comprehensive analysis failed');
|
|
@@ -948,7 +951,7 @@ program
|
|
|
948
951
|
return;
|
|
949
952
|
}
|
|
950
953
|
if (options.requirements) {
|
|
951
|
-
const spinner = (
|
|
954
|
+
const spinner = ora('Generating security requirements...').start();
|
|
952
955
|
try {
|
|
953
956
|
const fullId = await resolveDiagramId(options.requirements);
|
|
954
957
|
const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/threats/`);
|
|
@@ -966,18 +969,18 @@ program
|
|
|
966
969
|
})
|
|
967
970
|
});
|
|
968
971
|
spinner.succeed('Security requirements generated!');
|
|
969
|
-
console.log(
|
|
970
|
-
console.log(` Total: ${
|
|
971
|
-
console.log(` Critical: ${
|
|
972
|
-
console.log(` High: ${
|
|
972
|
+
console.log(chalk.bold('\nSecurity Requirements:\n'));
|
|
973
|
+
console.log(` Total: ${chalk.cyan(data.summary?.total_requirements || 0)}`);
|
|
974
|
+
console.log(` Critical: ${chalk.red(data.summary?.critical_requirements || 0)}`);
|
|
975
|
+
console.log(` High: ${chalk.yellow(data.summary?.high_requirements || 0)}`);
|
|
973
976
|
const reqs = data.security_requirements || [];
|
|
974
977
|
if (reqs.length > 0) {
|
|
975
|
-
console.log(
|
|
978
|
+
console.log(chalk.bold('\nRequirements:\n'));
|
|
976
979
|
reqs.slice(0, 5).forEach((r, i) => {
|
|
977
|
-
const priority = r.priority === 'critical' ?
|
|
980
|
+
const priority = r.priority === 'critical' ? chalk.red : r.priority === 'high' ? chalk.yellow : chalk.blue;
|
|
978
981
|
console.log(` ${i + 1}. ${priority(`[${r.priority?.toUpperCase()}]`)} ${r.title}`);
|
|
979
|
-
console.log(
|
|
980
|
-
console.log(
|
|
982
|
+
console.log(chalk.dim(` ${r.description?.slice(0, 80) || ''}...`));
|
|
983
|
+
console.log(chalk.dim(` Category: ${r.category || 'N/A'}`));
|
|
981
984
|
});
|
|
982
985
|
}
|
|
983
986
|
}
|
|
@@ -989,7 +992,7 @@ program
|
|
|
989
992
|
}
|
|
990
993
|
// AI-powered attack path analysis
|
|
991
994
|
if (options.aiAttackPaths) {
|
|
992
|
-
const spinner = (
|
|
995
|
+
const spinner = ora('Running AI-powered attack path analysis...').start();
|
|
993
996
|
try {
|
|
994
997
|
const fullId = await resolveDiagramId(options.aiAttackPaths);
|
|
995
998
|
const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
|
|
@@ -1010,34 +1013,34 @@ program
|
|
|
1010
1013
|
})
|
|
1011
1014
|
});
|
|
1012
1015
|
spinner.succeed('AI attack path analysis complete!');
|
|
1013
|
-
console.log(
|
|
1014
|
-
console.log(` Diagram: ${
|
|
1016
|
+
console.log(chalk.bold('\nAI Attack Path Analysis:\n'));
|
|
1017
|
+
console.log(` Diagram: ${chalk.cyan(diagramData.name || 'N/A')}`);
|
|
1015
1018
|
const analysis = data.analysis || data;
|
|
1016
|
-
console.log(` Risk Level: ${analysis.risk_level === 'critical' ?
|
|
1017
|
-
console.log(` AI Confidence: ${
|
|
1019
|
+
console.log(` Risk Level: ${analysis.risk_level === 'critical' ? chalk.red(analysis.risk_level) : chalk.yellow(analysis.risk_level || 'N/A')}`);
|
|
1020
|
+
console.log(` AI Confidence: ${chalk.green((analysis.confidence || analysis.ai_confidence || 0.85) * 100 + '%')}`);
|
|
1018
1021
|
const attackPaths = analysis.attack_paths || data.attack_paths || [];
|
|
1019
1022
|
if (attackPaths.length > 0) {
|
|
1020
|
-
console.log(
|
|
1023
|
+
console.log(chalk.bold(`\nIdentified Attack Paths (${attackPaths.length}):\n`));
|
|
1021
1024
|
attackPaths.slice(0, 5).forEach((path, i) => {
|
|
1022
|
-
const riskColor = path.risk_score > 0.7 ?
|
|
1023
|
-
console.log(` ${
|
|
1025
|
+
const riskColor = path.risk_score > 0.7 ? chalk.red : path.risk_score > 0.4 ? chalk.yellow : chalk.green;
|
|
1026
|
+
console.log(` ${chalk.bold(`Path ${i + 1}:`)} ${path.name || path.description || 'Attack Vector'}`);
|
|
1024
1027
|
console.log(` Risk Score: ${riskColor((path.risk_score * 100).toFixed(0) + '%')}`);
|
|
1025
|
-
console.log(` Attack Steps: ${
|
|
1026
|
-
console.log(` Entry Point: ${
|
|
1027
|
-
console.log(` Target: ${
|
|
1028
|
+
console.log(` Attack Steps: ${chalk.cyan(path.steps?.length || path.hop_count || 'N/A')}`);
|
|
1029
|
+
console.log(` Entry Point: ${chalk.yellow(path.entry_point || path.source || 'External')}`);
|
|
1030
|
+
console.log(` Target: ${chalk.red(path.target || path.destination || 'Critical Asset')}`);
|
|
1028
1031
|
if (path.mitre_techniques?.length > 0) {
|
|
1029
|
-
console.log(` MITRE: ${
|
|
1032
|
+
console.log(` MITRE: ${chalk.dim(path.mitre_techniques.slice(0, 3).join(', '))}`);
|
|
1030
1033
|
}
|
|
1031
1034
|
});
|
|
1032
1035
|
}
|
|
1033
1036
|
else {
|
|
1034
|
-
console.log(
|
|
1037
|
+
console.log(chalk.green('\n No critical attack paths identified!'));
|
|
1035
1038
|
}
|
|
1036
1039
|
const mitigations = analysis.mitigations || data.mitigations || [];
|
|
1037
1040
|
if (mitigations.length > 0) {
|
|
1038
|
-
console.log(
|
|
1041
|
+
console.log(chalk.bold('\nAI-Recommended Mitigations:\n'));
|
|
1039
1042
|
mitigations.slice(0, 3).forEach((m) => {
|
|
1040
|
-
console.log(` ${
|
|
1043
|
+
console.log(` ${chalk.green('→')} ${m.title || m.description || m}`);
|
|
1041
1044
|
});
|
|
1042
1045
|
}
|
|
1043
1046
|
}
|
|
@@ -1049,7 +1052,7 @@ program
|
|
|
1049
1052
|
}
|
|
1050
1053
|
// AI threat prediction
|
|
1051
1054
|
if (options.aiPredict) {
|
|
1052
|
-
const spinner = (
|
|
1055
|
+
const spinner = ora('Running AI threat prediction...').start();
|
|
1053
1056
|
try {
|
|
1054
1057
|
const fullId = await resolveDiagramId(options.aiPredict);
|
|
1055
1058
|
const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
|
|
@@ -1068,26 +1071,26 @@ program
|
|
|
1068
1071
|
})
|
|
1069
1072
|
});
|
|
1070
1073
|
spinner.succeed('AI threat prediction complete!');
|
|
1071
|
-
console.log(
|
|
1072
|
-
console.log(` Diagram: ${
|
|
1073
|
-
console.log(` Model: ${
|
|
1074
|
+
console.log(chalk.bold('\nAI Threat Prediction:\n'));
|
|
1075
|
+
console.log(` Diagram: ${chalk.cyan(diagramData.name || 'N/A')}`);
|
|
1076
|
+
console.log(` Model: ${chalk.green('ML Ensemble (STRIDE + PASTA + NIST)')}`);
|
|
1074
1077
|
const predictions = data.predictions || data;
|
|
1075
|
-
console.log(` Confidence: ${
|
|
1076
|
-
console.log(` Predicted Risk: ${predictions.risk_level === 'critical' ?
|
|
1078
|
+
console.log(` Confidence: ${chalk.green((predictions.confidence || 0.92) * 100 + '%')}`);
|
|
1079
|
+
console.log(` Predicted Risk: ${predictions.risk_level === 'critical' ? chalk.red(predictions.risk_level) : chalk.yellow(predictions.risk_level || 'medium')}`);
|
|
1077
1080
|
const threats = predictions.predicted_threats || predictions.threats || [];
|
|
1078
1081
|
if (threats.length > 0) {
|
|
1079
|
-
console.log(
|
|
1082
|
+
console.log(chalk.bold('\nPredicted Threats:\n'));
|
|
1080
1083
|
threats.slice(0, 5).forEach((t) => {
|
|
1081
1084
|
const prob = t.probability || t.confidence || 0.8;
|
|
1082
|
-
const probColor = prob > 0.8 ?
|
|
1085
|
+
const probColor = prob > 0.8 ? chalk.red : prob > 0.5 ? chalk.yellow : chalk.green;
|
|
1083
1086
|
console.log(` ${probColor(`[${(prob * 100).toFixed(0)}%]`)} ${t.title || t.name}`);
|
|
1084
|
-
console.log(
|
|
1087
|
+
console.log(chalk.dim(` Category: ${t.category || 'N/A'} | Impact: ${t.impact || 'high'}`));
|
|
1085
1088
|
});
|
|
1086
1089
|
}
|
|
1087
1090
|
if (predictions.emerging_threats?.length > 0) {
|
|
1088
|
-
console.log(
|
|
1091
|
+
console.log(chalk.bold('\nEmerging Threat Patterns:\n'));
|
|
1089
1092
|
predictions.emerging_threats.slice(0, 3).forEach((t) => {
|
|
1090
|
-
console.log(` ${
|
|
1093
|
+
console.log(` ${chalk.yellow('⚠')} ${t.name || t.description || t}`);
|
|
1091
1094
|
});
|
|
1092
1095
|
}
|
|
1093
1096
|
}
|
|
@@ -1099,7 +1102,7 @@ program
|
|
|
1099
1102
|
}
|
|
1100
1103
|
// AI architecture insights
|
|
1101
1104
|
if (options.aiInsights) {
|
|
1102
|
-
const spinner = (
|
|
1105
|
+
const spinner = ora('Generating AI architecture insights...').start();
|
|
1103
1106
|
try {
|
|
1104
1107
|
const fullId = await resolveDiagramId(options.aiInsights);
|
|
1105
1108
|
const data = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/generate-ai-insights/`, {
|
|
@@ -1109,31 +1112,31 @@ program
|
|
|
1109
1112
|
})
|
|
1110
1113
|
});
|
|
1111
1114
|
spinner.succeed('AI insights generated!');
|
|
1112
|
-
console.log(
|
|
1113
|
-
console.log(` Diagram: ${
|
|
1114
|
-
console.log(` Components: ${
|
|
1115
|
-
console.log(` AI Provider: ${
|
|
1116
|
-
console.log(` Generated: ${
|
|
1115
|
+
console.log(chalk.bold('\nAI Architecture Insights:\n'));
|
|
1116
|
+
console.log(` Diagram: ${chalk.cyan(data.diagram_name || 'N/A')}`);
|
|
1117
|
+
console.log(` Components: ${chalk.white(data.component_count || 0)}`);
|
|
1118
|
+
console.log(` AI Provider: ${chalk.green(data.provider || 'ai_agent')}`);
|
|
1119
|
+
console.log(` Generated: ${chalk.gray(data.generated_at || 'now')}`);
|
|
1117
1120
|
const threats = data.threats || [];
|
|
1118
1121
|
if (threats.length > 0) {
|
|
1119
|
-
console.log(
|
|
1122
|
+
console.log(chalk.bold('\nPredicted Threats:\n'));
|
|
1120
1123
|
threats.slice(0, 5).forEach((t) => {
|
|
1121
1124
|
const severity = t.severity || 'medium';
|
|
1122
|
-
const severityColor = severity === 'critical' || severity === 'high' ?
|
|
1125
|
+
const severityColor = severity === 'critical' || severity === 'high' ? chalk.red : chalk.yellow;
|
|
1123
1126
|
console.log(` ${severityColor('!')} ${t.name || t.threat_id}: ${t.description || ''}`);
|
|
1124
1127
|
if (t.probability) {
|
|
1125
|
-
console.log(` ${
|
|
1128
|
+
console.log(` ${chalk.gray(`Probability: ${(t.probability * 100).toFixed(0)}%`)}`);
|
|
1126
1129
|
}
|
|
1127
1130
|
});
|
|
1128
1131
|
}
|
|
1129
1132
|
else {
|
|
1130
|
-
console.log(
|
|
1133
|
+
console.log(chalk.green('\n No critical threats identified.'));
|
|
1131
1134
|
}
|
|
1132
1135
|
const recommendations = data.recommendations || [];
|
|
1133
1136
|
if (recommendations.length > 0) {
|
|
1134
|
-
console.log(
|
|
1137
|
+
console.log(chalk.bold('\nAI Recommendations:\n'));
|
|
1135
1138
|
recommendations.slice(0, 5).forEach((r) => {
|
|
1136
|
-
console.log(` ${
|
|
1139
|
+
console.log(` ${chalk.cyan('→')} ${typeof r === 'string' ? r : (r.title || r.description || r)}`);
|
|
1137
1140
|
});
|
|
1138
1141
|
}
|
|
1139
1142
|
}
|
|
@@ -1145,7 +1148,7 @@ program
|
|
|
1145
1148
|
}
|
|
1146
1149
|
// AI pattern detection
|
|
1147
1150
|
if (options.patterns) {
|
|
1148
|
-
const spinner = (
|
|
1151
|
+
const spinner = ora('Detecting AI patterns...').start();
|
|
1149
1152
|
try {
|
|
1150
1153
|
const fullId = await resolveDiagramId(options.patterns);
|
|
1151
1154
|
const data = await apiRequest('/v2/threat-modeling/ai-patterns/detect/', {
|
|
@@ -1156,25 +1159,25 @@ program
|
|
|
1156
1159
|
})
|
|
1157
1160
|
});
|
|
1158
1161
|
spinner.succeed('AI pattern detection complete!');
|
|
1159
|
-
console.log(
|
|
1162
|
+
console.log(chalk.bold('\nAI Pattern Detection:\n'));
|
|
1160
1163
|
const detection = data.detection || data;
|
|
1161
|
-
console.log(` Patterns Found: ${
|
|
1162
|
-
console.log(` Security Patterns: ${
|
|
1163
|
-
console.log(` Risk Patterns: ${
|
|
1164
|
+
console.log(` Patterns Found: ${chalk.cyan(detection.total_patterns || 0)}`);
|
|
1165
|
+
console.log(` Security Patterns: ${chalk.yellow(detection.security_patterns || 0)}`);
|
|
1166
|
+
console.log(` Risk Patterns: ${chalk.red(detection.risk_patterns || 0)}`);
|
|
1164
1167
|
const patterns = detection.patterns || data.patterns || [];
|
|
1165
1168
|
if (patterns.length > 0) {
|
|
1166
|
-
console.log(
|
|
1169
|
+
console.log(chalk.bold('\nDetected Patterns:\n'));
|
|
1167
1170
|
patterns.slice(0, 5).forEach((p) => {
|
|
1168
|
-
const typeColor = p.type === 'risk' ?
|
|
1171
|
+
const typeColor = p.type === 'risk' ? chalk.red : p.type === 'security' ? chalk.green : chalk.cyan;
|
|
1169
1172
|
console.log(` ${typeColor(`[${p.type?.toUpperCase() || 'PATTERN'}]`)} ${p.name || p.title}`);
|
|
1170
|
-
console.log(
|
|
1173
|
+
console.log(chalk.dim(` Confidence: ${((p.confidence || 0.85) * 100).toFixed(0)}% | Impact: ${p.impact || 'medium'}`));
|
|
1171
1174
|
});
|
|
1172
1175
|
}
|
|
1173
1176
|
const anomalies = detection.anomalies || [];
|
|
1174
1177
|
if (anomalies.length > 0) {
|
|
1175
|
-
console.log(
|
|
1178
|
+
console.log(chalk.bold('\nDetected Anomalies:\n'));
|
|
1176
1179
|
anomalies.slice(0, 3).forEach((a) => {
|
|
1177
|
-
console.log(` ${
|
|
1180
|
+
console.log(` ${chalk.yellow('⚠')} ${a.description || a.name || a}`);
|
|
1178
1181
|
});
|
|
1179
1182
|
}
|
|
1180
1183
|
}
|
|
@@ -1185,17 +1188,17 @@ program
|
|
|
1185
1188
|
return;
|
|
1186
1189
|
}
|
|
1187
1190
|
// Default: show usage
|
|
1188
|
-
console.log(
|
|
1189
|
-
console.log(` ${
|
|
1190
|
-
console.log(` ${
|
|
1191
|
-
console.log(` ${
|
|
1192
|
-
console.log(` ${
|
|
1193
|
-
console.log(` ${
|
|
1194
|
-
console.log(
|
|
1195
|
-
console.log(` ${
|
|
1196
|
-
console.log(` ${
|
|
1197
|
-
console.log(` ${
|
|
1198
|
-
console.log(` ${
|
|
1191
|
+
console.log(chalk.bold('\nRed Team Commands:\n'));
|
|
1192
|
+
console.log(` ${chalk.cyan('aribot redteam --methodologies')} List threat modeling methodologies`);
|
|
1193
|
+
console.log(` ${chalk.cyan('aribot redteam --intelligence')} Get threat intelligence summary`);
|
|
1194
|
+
console.log(` ${chalk.cyan('aribot redteam --attack-paths -d <id>')} Analyze attack paths for diagram`);
|
|
1195
|
+
console.log(` ${chalk.cyan('aribot redteam --analyze <id>')} Comprehensive threat analysis`);
|
|
1196
|
+
console.log(` ${chalk.cyan('aribot redteam --requirements <id>')} Generate security requirements`);
|
|
1197
|
+
console.log(chalk.bold('\nAI-Powered Commands:\n'));
|
|
1198
|
+
console.log(` ${chalk.green('aribot redteam --ai-attack-paths <id>')} AI attack path analysis`);
|
|
1199
|
+
console.log(` ${chalk.green('aribot redteam --ai-predict <id>')} AI threat prediction (ML)`);
|
|
1200
|
+
console.log(` ${chalk.green('aribot redteam --ai-insights <id>')} Generate AI architecture insights`);
|
|
1201
|
+
console.log(` ${chalk.green('aribot redteam --patterns <id>')} Detect AI patterns in diagram`);
|
|
1199
1202
|
});
|
|
1200
1203
|
// AI Analysis command
|
|
1201
1204
|
program
|
|
@@ -1206,7 +1209,7 @@ program
|
|
|
1206
1209
|
.option('--recommendations <diagram-id>', 'Get AI recommendations')
|
|
1207
1210
|
.option('--cost <diagram-id>', 'Analyze costs with AI')
|
|
1208
1211
|
.action(async (options) => {
|
|
1209
|
-
const spinner = (
|
|
1212
|
+
const spinner = ora('Running AI analysis...').start();
|
|
1210
1213
|
try {
|
|
1211
1214
|
if (options.analyze) {
|
|
1212
1215
|
const fullId = await resolveDiagramId(options.analyze);
|
|
@@ -1215,10 +1218,10 @@ program
|
|
|
1215
1218
|
body: JSON.stringify({ diagram_id: fullId })
|
|
1216
1219
|
});
|
|
1217
1220
|
spinner.succeed('AI analysis complete!');
|
|
1218
|
-
console.log(
|
|
1219
|
-
console.log(` Risk Level: ${
|
|
1220
|
-
console.log(` Findings: ${
|
|
1221
|
-
console.log(` Confidence: ${
|
|
1221
|
+
console.log(chalk.bold('\nAI Analysis Results:\n'));
|
|
1222
|
+
console.log(` Risk Level: ${chalk.yellow(data.risk_level || 'N/A')}`);
|
|
1223
|
+
console.log(` Findings: ${chalk.cyan(data.findings_count || 0)}`);
|
|
1224
|
+
console.log(` Confidence: ${chalk.green((data.confidence || 0) + '%')}`);
|
|
1222
1225
|
}
|
|
1223
1226
|
else if (options.predict) {
|
|
1224
1227
|
const fullId = await resolveDiagramId(options.predict);
|
|
@@ -1227,9 +1230,9 @@ program
|
|
|
1227
1230
|
body: JSON.stringify({ diagram_id: fullId })
|
|
1228
1231
|
});
|
|
1229
1232
|
spinner.succeed('Threat prediction complete!');
|
|
1230
|
-
console.log(
|
|
1233
|
+
console.log(chalk.bold('\nPredicted Threats:\n'));
|
|
1231
1234
|
(data.predictions || []).slice(0, 5).forEach((p) => {
|
|
1232
|
-
console.log(` ${
|
|
1235
|
+
console.log(` ${chalk.red('•')} ${p.threat_type}: ${p.probability}% likelihood`);
|
|
1233
1236
|
});
|
|
1234
1237
|
}
|
|
1235
1238
|
else if (options.recommendations) {
|
|
@@ -1239,24 +1242,24 @@ program
|
|
|
1239
1242
|
body: JSON.stringify({ diagram_id: fullId })
|
|
1240
1243
|
});
|
|
1241
1244
|
spinner.succeed('Recommendations generated!');
|
|
1242
|
-
console.log(
|
|
1245
|
+
console.log(chalk.bold('\nAI Recommendations:\n'));
|
|
1243
1246
|
(data.recommendations || []).slice(0, 5).forEach((r, i) => {
|
|
1244
1247
|
console.log(` ${i + 1}. ${r.title}`);
|
|
1245
|
-
console.log(
|
|
1248
|
+
console.log(chalk.dim(` Priority: ${r.priority} | Impact: ${r.impact}`));
|
|
1246
1249
|
});
|
|
1247
1250
|
}
|
|
1248
1251
|
else if (options.cost) {
|
|
1249
1252
|
const fullId = await resolveDiagramId(options.cost);
|
|
1250
1253
|
const data = await apiRequest(`/v2/ai-agents/cost-analysis/${fullId}/`);
|
|
1251
1254
|
spinner.succeed('Cost analysis complete!');
|
|
1252
|
-
console.log(
|
|
1253
|
-
console.log(` Monthly Estimate: ${
|
|
1254
|
-
console.log(` Annual Estimate: ${
|
|
1255
|
-
console.log(` Optimization: ${
|
|
1255
|
+
console.log(chalk.bold('\nAI Cost Analysis:\n'));
|
|
1256
|
+
console.log(` Monthly Estimate: ${chalk.cyan('$' + (data.monthly_cost || 0).toLocaleString())}`);
|
|
1257
|
+
console.log(` Annual Estimate: ${chalk.cyan('$' + (data.annual_cost || 0).toLocaleString())}`);
|
|
1258
|
+
console.log(` Optimization: ${chalk.green((data.optimization_potential || 0) + '%')}`);
|
|
1256
1259
|
}
|
|
1257
1260
|
else {
|
|
1258
1261
|
spinner.stop();
|
|
1259
|
-
console.log(
|
|
1262
|
+
console.log(chalk.yellow('Usage: aribot ai [--analyze|--predict|--recommendations|--cost] <diagram-id>'));
|
|
1260
1263
|
}
|
|
1261
1264
|
}
|
|
1262
1265
|
catch (error) {
|
|
@@ -1273,7 +1276,7 @@ program
|
|
|
1273
1276
|
.option('--vulnerabilities [sbom-id]', 'Scan for vulnerabilities')
|
|
1274
1277
|
.option('--list', 'List all SBOM documents')
|
|
1275
1278
|
.action(async (options) => {
|
|
1276
|
-
const spinner = (
|
|
1279
|
+
const spinner = ora('Processing SBOM...').start();
|
|
1277
1280
|
try {
|
|
1278
1281
|
if (options.generate) {
|
|
1279
1282
|
const fullId = await resolveDiagramId(options.generate);
|
|
@@ -1282,10 +1285,10 @@ program
|
|
|
1282
1285
|
body: JSON.stringify({ diagram_id: fullId })
|
|
1283
1286
|
});
|
|
1284
1287
|
spinner.succeed('SBOM generated!');
|
|
1285
|
-
console.log(
|
|
1286
|
-
console.log(` ID: ${
|
|
1287
|
-
console.log(` Components: ${
|
|
1288
|
-
console.log(` Format: ${
|
|
1288
|
+
console.log(chalk.bold('\nSBOM Document:\n'));
|
|
1289
|
+
console.log(` ID: ${chalk.cyan(data.id || data.sbom_id)}`);
|
|
1290
|
+
console.log(` Components: ${chalk.yellow(data.component_count || 0)}`);
|
|
1291
|
+
console.log(` Format: ${chalk.dim(data.format || 'CycloneDX')}`);
|
|
1289
1292
|
}
|
|
1290
1293
|
else if (options.analyze) {
|
|
1291
1294
|
const data = await apiRequest('/v2/sbom/analyze/', {
|
|
@@ -1293,39 +1296,39 @@ program
|
|
|
1293
1296
|
body: JSON.stringify({ sbom_id: options.analyze })
|
|
1294
1297
|
});
|
|
1295
1298
|
spinner.succeed('SBOM analysis complete!');
|
|
1296
|
-
console.log(
|
|
1297
|
-
console.log(` Total Dependencies: ${
|
|
1298
|
-
console.log(` Direct: ${
|
|
1299
|
-
console.log(` Transitive: ${
|
|
1300
|
-
console.log(` Outdated: ${
|
|
1299
|
+
console.log(chalk.bold('\nDependency Analysis:\n'));
|
|
1300
|
+
console.log(` Total Dependencies: ${chalk.cyan(data.total_dependencies || 0)}`);
|
|
1301
|
+
console.log(` Direct: ${chalk.yellow(data.direct_dependencies || 0)}`);
|
|
1302
|
+
console.log(` Transitive: ${chalk.dim(data.transitive_dependencies || 0)}`);
|
|
1303
|
+
console.log(` Outdated: ${chalk.red(data.outdated_count || 0)}`);
|
|
1301
1304
|
}
|
|
1302
1305
|
else if (options.vulnerabilities) {
|
|
1303
1306
|
const data = await apiRequest('/v2/sbom/vulnerabilities/');
|
|
1304
1307
|
spinner.succeed('Vulnerability scan complete!');
|
|
1305
|
-
console.log(
|
|
1306
|
-
console.log(` Critical: ${
|
|
1307
|
-
console.log(` High: ${
|
|
1308
|
-
console.log(` Medium: ${
|
|
1309
|
-
console.log(` Low: ${
|
|
1308
|
+
console.log(chalk.bold('\nVulnerability Report:\n'));
|
|
1309
|
+
console.log(` Critical: ${chalk.red(data.critical || 0)}`);
|
|
1310
|
+
console.log(` High: ${chalk.yellow(data.high || 0)}`);
|
|
1311
|
+
console.log(` Medium: ${chalk.blue(data.medium || 0)}`);
|
|
1312
|
+
console.log(` Low: ${chalk.dim(data.low || 0)}`);
|
|
1310
1313
|
}
|
|
1311
1314
|
else if (options.list) {
|
|
1312
1315
|
const data = await apiRequest('/v2/sbom/documents/');
|
|
1313
1316
|
spinner.stop();
|
|
1314
|
-
console.log(
|
|
1317
|
+
console.log(chalk.bold('\nSBOM Documents:\n'));
|
|
1315
1318
|
// Backend returns {sbom_documents: [...]}
|
|
1316
1319
|
const docs = data.sbom_documents || data.results || (Array.isArray(data) ? data : []);
|
|
1317
1320
|
if (docs.length === 0) {
|
|
1318
|
-
console.log(
|
|
1321
|
+
console.log(chalk.dim(' No SBOM documents found'));
|
|
1319
1322
|
}
|
|
1320
1323
|
else {
|
|
1321
1324
|
docs.forEach((s) => {
|
|
1322
|
-
console.log(` ${
|
|
1325
|
+
console.log(` ${chalk.cyan(String(s.id || s.sbom_id).slice(0, 8))} ${s.name || 'Unnamed'} ${chalk.dim((s.component_count || 0) + ' components')}`);
|
|
1323
1326
|
});
|
|
1324
1327
|
}
|
|
1325
1328
|
}
|
|
1326
1329
|
else {
|
|
1327
1330
|
spinner.stop();
|
|
1328
|
-
console.log(
|
|
1331
|
+
console.log(chalk.yellow('Usage: aribot sbom [--generate <diagram-id>] [--analyze <sbom-id>] [--vulnerabilities] [--list]'));
|
|
1329
1332
|
}
|
|
1330
1333
|
}
|
|
1331
1334
|
catch (error) {
|
|
@@ -1343,24 +1346,24 @@ program
|
|
|
1343
1346
|
.option('--discover <provider-id>', 'Discover cloud resources')
|
|
1344
1347
|
.option('--health', 'Check digital twin health')
|
|
1345
1348
|
.action(async (options) => {
|
|
1346
|
-
const spinner = (
|
|
1349
|
+
const spinner = ora('Processing...').start();
|
|
1347
1350
|
try {
|
|
1348
1351
|
if (options.providers) {
|
|
1349
1352
|
const data = await apiRequest('/v2/digital-twin/providers/');
|
|
1350
1353
|
spinner.stop();
|
|
1351
|
-
console.log(
|
|
1354
|
+
console.log(chalk.bold('\nCloud Providers:\n'));
|
|
1352
1355
|
(data.results || data || []).forEach((p) => {
|
|
1353
|
-
const status = p.connected ?
|
|
1354
|
-
console.log(` ${status} ${
|
|
1356
|
+
const status = p.connected ? chalk.green('✓') : chalk.red('✗');
|
|
1357
|
+
console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.provider_type || p.type)}`);
|
|
1355
1358
|
});
|
|
1356
1359
|
}
|
|
1357
1360
|
else if (options.resources) {
|
|
1358
1361
|
const provider = typeof options.resources === 'string' ? `?provider=${options.resources}` : '';
|
|
1359
1362
|
const data = await apiRequest(`/v2/digital-twin/resources/${provider}`);
|
|
1360
1363
|
spinner.stop();
|
|
1361
|
-
console.log(
|
|
1364
|
+
console.log(chalk.bold('\nCloud Resources:\n'));
|
|
1362
1365
|
(data.results || data || []).slice(0, 20).forEach((r) => {
|
|
1363
|
-
console.log(` ${
|
|
1366
|
+
console.log(` ${chalk.cyan(r.resource_type || r.type)} ${r.name} ${chalk.dim(r.region || '')}`);
|
|
1364
1367
|
});
|
|
1365
1368
|
}
|
|
1366
1369
|
else if (options.sync) {
|
|
@@ -1369,7 +1372,7 @@ program
|
|
|
1369
1372
|
body: JSON.stringify({ provider_id: options.sync })
|
|
1370
1373
|
});
|
|
1371
1374
|
spinner.succeed('Cloud sync initiated!');
|
|
1372
|
-
console.log(` Resources discovered: ${
|
|
1375
|
+
console.log(` Resources discovered: ${chalk.cyan(data.resources_found || 0)}`);
|
|
1373
1376
|
}
|
|
1374
1377
|
else if (options.discover) {
|
|
1375
1378
|
const data = await apiRequest('/v2/digital-twin/discover/', {
|
|
@@ -1377,20 +1380,20 @@ program
|
|
|
1377
1380
|
body: JSON.stringify({ provider_id: options.discover })
|
|
1378
1381
|
});
|
|
1379
1382
|
spinner.succeed('Discovery complete!');
|
|
1380
|
-
console.log(` Resources found: ${
|
|
1383
|
+
console.log(` Resources found: ${chalk.cyan(data.resources_count || 0)}`);
|
|
1381
1384
|
}
|
|
1382
1385
|
else if (options.health) {
|
|
1383
1386
|
const data = await apiRequest('/v2/digital-twin/health/');
|
|
1384
1387
|
spinner.stop();
|
|
1385
|
-
console.log(
|
|
1386
|
-
console.log(` Status: ${data.healthy ?
|
|
1387
|
-
console.log(` Providers: ${
|
|
1388
|
-
console.log(` Resources: ${
|
|
1389
|
-
console.log(` Last Sync: ${
|
|
1388
|
+
console.log(chalk.bold('\nDigital Twin Health:\n'));
|
|
1389
|
+
console.log(` Status: ${data.healthy ? chalk.green('Healthy') : chalk.red('Unhealthy')}`);
|
|
1390
|
+
console.log(` Providers: ${chalk.cyan(data.providers_connected || 0)}`);
|
|
1391
|
+
console.log(` Resources: ${chalk.cyan(data.total_resources || 0)}`);
|
|
1392
|
+
console.log(` Last Sync: ${chalk.dim(data.last_sync || 'Never')}`);
|
|
1390
1393
|
}
|
|
1391
1394
|
else {
|
|
1392
1395
|
spinner.stop();
|
|
1393
|
-
console.log(
|
|
1396
|
+
console.log(chalk.yellow('Usage: aribot digital-twin [--providers] [--resources] [--sync <id>] [--discover <id>] [--health]'));
|
|
1394
1397
|
}
|
|
1395
1398
|
}
|
|
1396
1399
|
catch (error) {
|
|
@@ -1408,34 +1411,34 @@ program
|
|
|
1408
1411
|
.option('--scan <project-id>', 'Run a new scan')
|
|
1409
1412
|
.option('--stats', 'Get pipeline statistics')
|
|
1410
1413
|
.action(async (options) => {
|
|
1411
|
-
const spinner = (
|
|
1414
|
+
const spinner = ora('Processing...').start();
|
|
1412
1415
|
try {
|
|
1413
1416
|
if (options.projects) {
|
|
1414
1417
|
const data = await apiRequest('/v1/pipeline/projects/');
|
|
1415
1418
|
spinner.stop();
|
|
1416
|
-
console.log(
|
|
1419
|
+
console.log(chalk.bold('\nPipeline Projects:\n'));
|
|
1417
1420
|
(data.results || data || []).forEach((p) => {
|
|
1418
|
-
const status = p.last_scan_status === 'passed' ?
|
|
1419
|
-
console.log(` ${status} ${
|
|
1421
|
+
const status = p.last_scan_status === 'passed' ? chalk.green('✓') : chalk.red('✗');
|
|
1422
|
+
console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.repository || '')}`);
|
|
1420
1423
|
});
|
|
1421
1424
|
}
|
|
1422
1425
|
else if (options.scans) {
|
|
1423
1426
|
const project = typeof options.scans === 'string' ? `?project=${options.scans}` : '';
|
|
1424
1427
|
const data = await apiRequest(`/v1/pipeline/scans/${project}`);
|
|
1425
1428
|
spinner.stop();
|
|
1426
|
-
console.log(
|
|
1429
|
+
console.log(chalk.bold('\nPipeline Scans:\n'));
|
|
1427
1430
|
(data.results || data || []).slice(0, 10).forEach((s) => {
|
|
1428
|
-
const status = s.status === 'completed' ?
|
|
1429
|
-
console.log(` ${status} ${
|
|
1431
|
+
const status = s.status === 'completed' ? chalk.green('✓') : chalk.yellow('⋯');
|
|
1432
|
+
console.log(` ${status} ${chalk.cyan(String(s.id).slice(0, 8))} ${s.scan_type || 'security'} ${chalk.dim(s.created_at?.slice(0, 10) || '')}`);
|
|
1430
1433
|
});
|
|
1431
1434
|
}
|
|
1432
1435
|
else if (options.vulnerabilities) {
|
|
1433
1436
|
const project = typeof options.vulnerabilities === 'string' ? `?project=${options.vulnerabilities}` : '';
|
|
1434
1437
|
const data = await apiRequest(`/v1/pipeline/vulnerabilities/${project}`);
|
|
1435
1438
|
spinner.stop();
|
|
1436
|
-
console.log(
|
|
1439
|
+
console.log(chalk.bold('\nPipeline Vulnerabilities:\n'));
|
|
1437
1440
|
(data.results || data || []).slice(0, 10).forEach((v) => {
|
|
1438
|
-
const severity = v.severity === 'critical' ?
|
|
1441
|
+
const severity = v.severity === 'critical' ? chalk.red : v.severity === 'high' ? chalk.yellow : chalk.blue;
|
|
1439
1442
|
console.log(` ${severity(`[${v.severity?.toUpperCase()}]`)} ${v.title || v.name}`);
|
|
1440
1443
|
});
|
|
1441
1444
|
}
|
|
@@ -1445,20 +1448,20 @@ program
|
|
|
1445
1448
|
body: JSON.stringify({ project_id: options.scan })
|
|
1446
1449
|
});
|
|
1447
1450
|
spinner.succeed('Scan initiated!');
|
|
1448
|
-
console.log(` Scan ID: ${
|
|
1451
|
+
console.log(` Scan ID: ${chalk.cyan(data.id || data.scan_id)}`);
|
|
1449
1452
|
}
|
|
1450
1453
|
else if (options.stats) {
|
|
1451
1454
|
const data = await apiRequest('/v1/pipeline/stats/');
|
|
1452
1455
|
spinner.stop();
|
|
1453
|
-
console.log(
|
|
1454
|
-
console.log(` Total Projects: ${
|
|
1455
|
-
console.log(` Total Scans: ${
|
|
1456
|
-
console.log(` Vulnerabilities: ${
|
|
1457
|
-
console.log(` Pass Rate: ${
|
|
1456
|
+
console.log(chalk.bold('\nPipeline Statistics:\n'));
|
|
1457
|
+
console.log(` Total Projects: ${chalk.cyan(data.total_projects || 0)}`);
|
|
1458
|
+
console.log(` Total Scans: ${chalk.cyan(data.total_scans || 0)}`);
|
|
1459
|
+
console.log(` Vulnerabilities: ${chalk.red(data.total_vulnerabilities || 0)}`);
|
|
1460
|
+
console.log(` Pass Rate: ${chalk.green((data.pass_rate || 0) + '%')}`);
|
|
1458
1461
|
}
|
|
1459
1462
|
else {
|
|
1460
1463
|
spinner.stop();
|
|
1461
|
-
console.log(
|
|
1464
|
+
console.log(chalk.yellow('Usage: aribot pipeline [--projects] [--scans] [--vulnerabilities] [--scan <id>] [--stats]'));
|
|
1462
1465
|
}
|
|
1463
1466
|
}
|
|
1464
1467
|
catch (error) {
|
|
@@ -1475,16 +1478,16 @@ program
|
|
|
1475
1478
|
.option('--delete <key-id>', 'Delete API key')
|
|
1476
1479
|
.option('--usage', 'Show API usage')
|
|
1477
1480
|
.action(async (options) => {
|
|
1478
|
-
const spinner = (
|
|
1481
|
+
const spinner = ora('Processing...').start();
|
|
1479
1482
|
try {
|
|
1480
1483
|
if (options.list) {
|
|
1481
1484
|
const data = await apiRequest('/v1/developer/api-keys/');
|
|
1482
1485
|
spinner.stop();
|
|
1483
|
-
console.log(
|
|
1486
|
+
console.log(chalk.bold('\nAPI Keys:\n'));
|
|
1484
1487
|
(data.results || data || []).forEach((k) => {
|
|
1485
|
-
const status = (k.is_active || k.status === 'active') ?
|
|
1488
|
+
const status = (k.is_active || k.status === 'active') ? chalk.green('active') : chalk.red('inactive');
|
|
1486
1489
|
const keyPrefix = k.key_prefix || (k.key ? k.key.slice(0, 8) : 'xxxxxxxx');
|
|
1487
|
-
console.log(` ${
|
|
1490
|
+
console.log(` ${chalk.cyan(k.name)} ${chalk.dim(keyPrefix + '...')} ${status}`);
|
|
1488
1491
|
});
|
|
1489
1492
|
}
|
|
1490
1493
|
else if (options.create) {
|
|
@@ -1493,10 +1496,10 @@ program
|
|
|
1493
1496
|
body: JSON.stringify({ name: options.create })
|
|
1494
1497
|
});
|
|
1495
1498
|
spinner.succeed('API key created!');
|
|
1496
|
-
console.log(
|
|
1497
|
-
console.log(` Name: ${
|
|
1498
|
-
console.log(` Key: ${
|
|
1499
|
-
console.log(
|
|
1499
|
+
console.log(chalk.bold('\nNew API Key:\n'));
|
|
1500
|
+
console.log(` Name: ${chalk.cyan(data.name)}`);
|
|
1501
|
+
console.log(` Key: ${chalk.yellow(data.key)}`);
|
|
1502
|
+
console.log(chalk.red('\n ⚠ Save this key now - it won\'t be shown again!'));
|
|
1500
1503
|
}
|
|
1501
1504
|
else if (options.delete) {
|
|
1502
1505
|
await apiRequest(`/v1/developer/api-keys/${options.delete}/`, {
|
|
@@ -1507,14 +1510,14 @@ program
|
|
|
1507
1510
|
else if (options.usage) {
|
|
1508
1511
|
const data = await apiRequest('/v1/developer/usage/');
|
|
1509
1512
|
spinner.stop();
|
|
1510
|
-
console.log(
|
|
1511
|
-
console.log(` Today: ${
|
|
1512
|
-
console.log(` This Month: ${
|
|
1513
|
-
console.log(` Limit: ${
|
|
1513
|
+
console.log(chalk.bold('\nAPI Usage:\n'));
|
|
1514
|
+
console.log(` Today: ${chalk.cyan(data.today || 0)} requests`);
|
|
1515
|
+
console.log(` This Month: ${chalk.cyan(data.this_month || 0)} requests`);
|
|
1516
|
+
console.log(` Limit: ${chalk.dim(data.limit || 'unlimited')}`);
|
|
1514
1517
|
}
|
|
1515
1518
|
else {
|
|
1516
1519
|
spinner.stop();
|
|
1517
|
-
console.log(
|
|
1520
|
+
console.log(chalk.yellow('Usage: aribot api-keys [--list] [--create <name>] [--delete <id>] [--usage]'));
|
|
1518
1521
|
}
|
|
1519
1522
|
}
|
|
1520
1523
|
catch (error) {
|
|
@@ -1532,55 +1535,55 @@ program
|
|
|
1532
1535
|
.option('--my-templates', 'List your templates')
|
|
1533
1536
|
.option('--get <template-id>', 'Get template details')
|
|
1534
1537
|
.action(async (options) => {
|
|
1535
|
-
const spinner = (
|
|
1538
|
+
const spinner = ora('Fetching...').start();
|
|
1536
1539
|
try {
|
|
1537
1540
|
if (options.search) {
|
|
1538
1541
|
const data = await apiRequest(`/v2/marketplace/search/?q=${encodeURIComponent(options.search)}`);
|
|
1539
1542
|
spinner.stop();
|
|
1540
|
-
console.log(
|
|
1543
|
+
console.log(chalk.bold(`\nSearch Results for "${options.search}":\n`));
|
|
1541
1544
|
(data.results || data || []).slice(0, 10).forEach((t) => {
|
|
1542
|
-
console.log(` ${
|
|
1543
|
-
console.log(
|
|
1545
|
+
console.log(` ${chalk.cyan(t.title || t.name)} ${chalk.dim('$' + (t.price || 0))}`);
|
|
1546
|
+
console.log(chalk.dim(` ${t.description?.slice(0, 60) || ''}...`));
|
|
1544
1547
|
});
|
|
1545
1548
|
}
|
|
1546
1549
|
else if (options.featured) {
|
|
1547
1550
|
const data = await apiRequest('/v2/marketplace/featured/');
|
|
1548
1551
|
spinner.stop();
|
|
1549
|
-
console.log(
|
|
1552
|
+
console.log(chalk.bold('\nFeatured Templates:\n'));
|
|
1550
1553
|
(data.results || data || []).forEach((t) => {
|
|
1551
|
-
console.log(` ${
|
|
1554
|
+
console.log(` ${chalk.green('★')} ${chalk.cyan(t.title || t.name)} ${chalk.dim('$' + (t.price || 0))}`);
|
|
1552
1555
|
});
|
|
1553
1556
|
}
|
|
1554
1557
|
else if (options.categories) {
|
|
1555
1558
|
const data = await apiRequest('/v2/marketplace/categories/');
|
|
1556
1559
|
spinner.stop();
|
|
1557
|
-
console.log(
|
|
1560
|
+
console.log(chalk.bold('\nTemplate Categories:\n'));
|
|
1558
1561
|
// Backend returns {value, label} format
|
|
1559
1562
|
(data.results || data || []).forEach((c) => {
|
|
1560
|
-
console.log(` ${
|
|
1563
|
+
console.log(` ${chalk.cyan(c.label || c.name || c.value)} ${chalk.dim((c.template_count || c.count || '') + ' templates')}`);
|
|
1561
1564
|
});
|
|
1562
1565
|
}
|
|
1563
1566
|
else if (options.myTemplates) {
|
|
1564
1567
|
const data = await apiRequest('/v2/marketplace/my-templates/');
|
|
1565
1568
|
spinner.stop();
|
|
1566
|
-
console.log(
|
|
1569
|
+
console.log(chalk.bold('\nYour Templates:\n'));
|
|
1567
1570
|
(data.results || data || []).forEach((t) => {
|
|
1568
|
-
console.log(` ${
|
|
1571
|
+
console.log(` ${chalk.cyan(t.title || t.name)} ${chalk.dim(t.status)}`);
|
|
1569
1572
|
});
|
|
1570
1573
|
}
|
|
1571
1574
|
else if (options.get) {
|
|
1572
1575
|
const data = await apiRequest(`/v2/marketplace/v2/templates/${options.get}/`);
|
|
1573
1576
|
spinner.stop();
|
|
1574
|
-
console.log(
|
|
1575
|
-
console.log(` Category: ${
|
|
1576
|
-
console.log(` Price: ${
|
|
1577
|
-
console.log(` Downloads: ${
|
|
1578
|
-
console.log(` Rating: ${
|
|
1579
|
-
console.log(`\n ${
|
|
1577
|
+
console.log(chalk.bold(`\n${data.title || data.name}\n`));
|
|
1578
|
+
console.log(` Category: ${chalk.cyan(data.category)}`);
|
|
1579
|
+
console.log(` Price: ${chalk.yellow('$' + (data.price || 0))}`);
|
|
1580
|
+
console.log(` Downloads: ${chalk.dim(data.download_count || 0)}`);
|
|
1581
|
+
console.log(` Rating: ${chalk.green(data.rating || 'N/A')}`);
|
|
1582
|
+
console.log(`\n ${chalk.dim(data.description || '')}`);
|
|
1580
1583
|
}
|
|
1581
1584
|
else {
|
|
1582
1585
|
spinner.stop();
|
|
1583
|
-
console.log(
|
|
1586
|
+
console.log(chalk.yellow('Usage: aribot marketplace [--search <query>] [--featured] [--categories] [--my-templates] [--get <id>]'));
|
|
1584
1587
|
}
|
|
1585
1588
|
}
|
|
1586
1589
|
catch (error) {
|
|
@@ -1597,40 +1600,40 @@ program
|
|
|
1597
1600
|
.option('--risk', 'Show risk summary')
|
|
1598
1601
|
.option('--billing', 'Show billing information')
|
|
1599
1602
|
.action(async (options) => {
|
|
1600
|
-
const spinner = (
|
|
1603
|
+
const spinner = ora('Loading dashboard...').start();
|
|
1601
1604
|
try {
|
|
1602
1605
|
if (options.overview || (!options.recent && !options.risk && !options.billing)) {
|
|
1603
1606
|
const data = await apiRequest('/v2/threat-modeling/dashboard/');
|
|
1604
1607
|
spinner.stop();
|
|
1605
|
-
console.log(
|
|
1606
|
-
console.log(` Total Diagrams: ${
|
|
1607
|
-
console.log(` Total Threats: ${
|
|
1608
|
-
console.log(` Critical Threats: ${
|
|
1609
|
-
console.log(` Compliance Score: ${
|
|
1608
|
+
console.log(chalk.bold('\nDashboard Overview:\n'));
|
|
1609
|
+
console.log(` Total Diagrams: ${chalk.cyan(data.total_diagrams || 0)}`);
|
|
1610
|
+
console.log(` Total Threats: ${chalk.yellow(data.total_threats || 0)}`);
|
|
1611
|
+
console.log(` Critical Threats: ${chalk.red(data.critical_threats || 0)}`);
|
|
1612
|
+
console.log(` Compliance Score: ${chalk.green((data.compliance_score || 0) + '%')}`);
|
|
1610
1613
|
}
|
|
1611
1614
|
else if (options.recent) {
|
|
1612
1615
|
const data = await apiRequest('/v2/threat-modeling/dashboard/recent-activity/');
|
|
1613
1616
|
spinner.stop();
|
|
1614
|
-
console.log(
|
|
1617
|
+
console.log(chalk.bold('\nRecent Activity:\n'));
|
|
1615
1618
|
(data.activities || data || []).slice(0, 10).forEach((a) => {
|
|
1616
|
-
console.log(` ${
|
|
1619
|
+
console.log(` ${chalk.dim(a.timestamp?.slice(0, 16) || '')} ${a.action} ${chalk.cyan(a.resource || '')}`);
|
|
1617
1620
|
});
|
|
1618
1621
|
}
|
|
1619
1622
|
else if (options.risk) {
|
|
1620
1623
|
const data = await apiRequest('/v2/threat-modeling/dashboard/risk-summary/');
|
|
1621
1624
|
spinner.stop();
|
|
1622
|
-
console.log(
|
|
1623
|
-
console.log(` Overall Risk: ${data.overall_risk === 'high' ?
|
|
1624
|
-
console.log(` Open Threats: ${
|
|
1625
|
-
console.log(` Mitigated: ${
|
|
1625
|
+
console.log(chalk.bold('\nRisk Summary:\n'));
|
|
1626
|
+
console.log(` Overall Risk: ${data.overall_risk === 'high' ? chalk.red(data.overall_risk) : chalk.yellow(data.overall_risk || 'N/A')}`);
|
|
1627
|
+
console.log(` Open Threats: ${chalk.yellow(data.open_threats || 0)}`);
|
|
1628
|
+
console.log(` Mitigated: ${chalk.green(data.mitigated_threats || 0)}`);
|
|
1626
1629
|
}
|
|
1627
1630
|
else if (options.billing) {
|
|
1628
1631
|
const data = await apiRequest('/v1/developer/billing/');
|
|
1629
1632
|
spinner.stop();
|
|
1630
|
-
console.log(
|
|
1631
|
-
console.log(` Plan: ${
|
|
1632
|
-
console.log(` Usage: ${
|
|
1633
|
-
console.log(` Next Billing: ${
|
|
1633
|
+
console.log(chalk.bold('\nBilling Information:\n'));
|
|
1634
|
+
console.log(` Plan: ${chalk.cyan(data.plan || 'Free')}`);
|
|
1635
|
+
console.log(` Usage: ${chalk.yellow((data.usage || 0) + ' requests')}`);
|
|
1636
|
+
console.log(` Next Billing: ${chalk.dim(data.next_billing_date || 'N/A')}`);
|
|
1634
1637
|
}
|
|
1635
1638
|
}
|
|
1636
1639
|
catch (error) {
|