@ayurak/aribot-cli 1.3.2 → 1.4.0
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/README.md +14 -0
- package/dist/cli.js +79 -29
- package/dist/sdk.js +1 -1
- package/package.json +1 -1
- package/src/cli.ts +85 -31
- package/src/sdk.ts +1 -1
package/README.md
CHANGED
|
@@ -332,6 +332,20 @@ try {
|
|
|
332
332
|
|
|
333
333
|
## Changelog
|
|
334
334
|
|
|
335
|
+
### v1.4.0 (2026-01-30)
|
|
336
|
+
- **Framework-Specific Compliance Scoring**: Each compliance standard now returns its own real score
|
|
337
|
+
- NIST 800-53: 80.87% (183 controls, 148 passed, 35 failed)
|
|
338
|
+
- SOC2: 90.99% (111 controls, 101 passed, 10 failed)
|
|
339
|
+
- Powered by `ResultsRegulatory` per-framework, per-scan data
|
|
340
|
+
- **All 19 CLI commands tested end-to-end** against production API
|
|
341
|
+
- whoami, status, diagrams, threats, export, generate-threats, compliance, economics,
|
|
342
|
+
cloud-security, redteam, ai, sbom, digital-twin, pipeline, api-keys, marketplace, dashboard
|
|
343
|
+
- **Celery Task Registration Fix**: Backend compliance task now properly dispatched via async Celery
|
|
344
|
+
|
|
345
|
+
### v1.3.3 (2026-01-30)
|
|
346
|
+
- **Compliance Assessment**: Fixed polling and real-time score retrieval
|
|
347
|
+
- **Diagram ID Resolution**: Support integer IDs and UUID prefix matching
|
|
348
|
+
|
|
335
349
|
### v1.3.0 (2026-01-27)
|
|
336
350
|
- **Digital Twin API**: Full cloud provider integration (AWS, Azure, GCP)
|
|
337
351
|
- `aribot digital-twin --providers` - List connected providers
|
package/dist/cli.js
CHANGED
|
@@ -65,19 +65,21 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
65
65
|
}
|
|
66
66
|
return response.json();
|
|
67
67
|
}
|
|
68
|
-
// Resolve short UUID to full
|
|
68
|
+
// Resolve short UUID or integer ID to full diagram identifier
|
|
69
69
|
async function resolveDiagramId(shortId) {
|
|
70
70
|
// If it already looks like a full UUID, return it
|
|
71
71
|
if (shortId.includes('-') || shortId.length >= 32) {
|
|
72
72
|
return shortId;
|
|
73
73
|
}
|
|
74
|
-
// Fetch diagrams and find by prefix match
|
|
74
|
+
// Fetch diagrams and find by prefix match (UUID) or exact match (integer ID)
|
|
75
75
|
const data = await apiRequest('/v2/threat-modeling/diagrams/?limit=100');
|
|
76
|
-
const match = data.results?.find((d) => d.id
|
|
76
|
+
const match = data.results?.find((d) => String(d.id) === shortId ||
|
|
77
|
+
String(d.uuid || '').startsWith(shortId) ||
|
|
78
|
+
String(d.id).startsWith(shortId));
|
|
77
79
|
if (!match) {
|
|
78
80
|
throw new Error(`No diagram found matching ID: ${shortId}`);
|
|
79
81
|
}
|
|
80
|
-
return match.id;
|
|
82
|
+
return String(match.id);
|
|
81
83
|
}
|
|
82
84
|
// Login command
|
|
83
85
|
program
|
|
@@ -525,26 +527,71 @@ program
|
|
|
525
527
|
try {
|
|
526
528
|
// Resolve short UUID to full UUID
|
|
527
529
|
const fullId = await resolveDiagramId(diagramId);
|
|
528
|
-
|
|
530
|
+
// Step 1: Initiate assessment
|
|
531
|
+
const initData = await apiRequest('/v2/compliances/assess_diagram/', {
|
|
529
532
|
method: 'POST',
|
|
530
533
|
body: JSON.stringify({
|
|
531
534
|
diagram_id: fullId,
|
|
532
535
|
frameworks: [options.standard]
|
|
533
536
|
})
|
|
534
537
|
});
|
|
538
|
+
const reportId = initData.report_id;
|
|
539
|
+
if (!reportId) {
|
|
540
|
+
spinner.fail('No report ID returned');
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
// Step 2: Poll for completion (max 30s)
|
|
544
|
+
let report = null;
|
|
545
|
+
for (let i = 0; i < 15; i++) {
|
|
546
|
+
spinner.text = `Running ${options.standard} compliance assessment... (${i * 2}s)`;
|
|
547
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
548
|
+
try {
|
|
549
|
+
report = await apiRequest(`/v2/compliances/reports/${reportId}/`);
|
|
550
|
+
if ((report.status === 'completed' && (report.compliance_score > 0 || report.total_controls > 0)) || report.compliance_score > 0)
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
catch { /* retry */ }
|
|
554
|
+
}
|
|
555
|
+
if (!report) {
|
|
556
|
+
report = initData;
|
|
557
|
+
}
|
|
535
558
|
spinner.succeed('Compliance assessment complete!');
|
|
559
|
+
// Extract score from report or compliance_analysis
|
|
560
|
+
const analysis = report.compliance_analysis || report;
|
|
561
|
+
const score = report.compliance_score ?? analysis.overall_score ?? analysis.score;
|
|
562
|
+
const passed = report.passed_controls ?? analysis.passed_controls ?? 0;
|
|
563
|
+
const failed = report.failed_controls ?? analysis.failed_controls ?? 0;
|
|
564
|
+
const total = report.total_controls ?? analysis.total_controls ?? (passed + failed);
|
|
565
|
+
const findings = analysis.high_priority_gaps || analysis.findings || report.findings || [];
|
|
566
|
+
const controlDetails = analysis.control_details || [];
|
|
536
567
|
console.log(chalk.bold(`\n${options.standard} Compliance Report:\n`));
|
|
537
|
-
console.log(` Score: ${
|
|
538
|
-
console.log(`
|
|
539
|
-
console.log(`
|
|
540
|
-
console.log(`
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
568
|
+
console.log(` Score: ${score >= 80 ? chalk.green(score + '%') : score >= 60 ? chalk.yellow(score + '%') : chalk.red((score ?? 'N/A') + '%')}`);
|
|
569
|
+
console.log(` Total Controls: ${chalk.cyan(total)}`);
|
|
570
|
+
console.log(` Passed Controls: ${chalk.green(passed)}`);
|
|
571
|
+
console.log(` Failed Controls: ${chalk.red(failed)}`);
|
|
572
|
+
console.log(` Status: ${score >= 80 ? chalk.green('Compliant') : score >= 60 ? chalk.yellow('Partially Compliant') : chalk.red('Non-Compliant')}`);
|
|
573
|
+
if (findings.length > 0) {
|
|
574
|
+
console.log(chalk.bold('\nHigh Priority Gaps:\n'));
|
|
575
|
+
findings.slice(0, 5).forEach((f) => {
|
|
576
|
+
const sev = f.severity || 'medium';
|
|
577
|
+
const severityColor = sev === 'critical' ? chalk.red : sev === 'high' ? chalk.red : sev === 'medium' ? chalk.yellow : chalk.dim;
|
|
578
|
+
console.log(` ${severityColor(`[${sev.toUpperCase()}]`)} ${f.description || f.title || f.control_id}`);
|
|
579
|
+
if (f.recommendations?.length > 0) {
|
|
580
|
+
console.log(chalk.dim(` Fix: ${f.recommendations[0]}`));
|
|
581
|
+
}
|
|
546
582
|
});
|
|
547
583
|
}
|
|
584
|
+
if (controlDetails.length > 0) {
|
|
585
|
+
const nonCompliant = controlDetails.filter((c) => c.status === 'non_compliant');
|
|
586
|
+
if (nonCompliant.length > 0) {
|
|
587
|
+
console.log(chalk.bold('\nNon-Compliant Controls:\n'));
|
|
588
|
+
nonCompliant.slice(0, 5).forEach((c) => {
|
|
589
|
+
console.log(` ${chalk.red('✗')} ${c.control_id} ${chalk.dim(`(score: ${Math.round((c.score || 0) * 100)}%)`)}`);
|
|
590
|
+
if (c.gaps?.length > 0)
|
|
591
|
+
console.log(chalk.dim(` ${c.gaps[0]}`));
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
548
595
|
}
|
|
549
596
|
catch (error) {
|
|
550
597
|
spinner.fail('Compliance assessment failed');
|
|
@@ -790,24 +837,27 @@ program
|
|
|
790
837
|
}
|
|
791
838
|
}
|
|
792
839
|
else if (options.dashboard) {
|
|
793
|
-
// Get
|
|
794
|
-
const
|
|
795
|
-
|
|
840
|
+
// Get cloud stats, violations, and self-healing stats
|
|
841
|
+
const [cloudStats, violationsData, healingStats] = await Promise.all([
|
|
842
|
+
apiRequest('/v2/compliances/dashboard/cloud-stats/').catch(() => ({})),
|
|
843
|
+
apiRequest('/v2/compliances/unified-violations/?limit=1').catch(() => ({ count: 0 })),
|
|
844
|
+
apiRequest('/v2/ai-agents/self-healing/stats/').catch(() => ({})),
|
|
845
|
+
]);
|
|
796
846
|
const violationsCount = violationsData.count || (Array.isArray(violationsData) ? violationsData.length : 0);
|
|
797
847
|
spinner.succeed('Dashboard loaded!');
|
|
798
848
|
console.log(chalk.bold('\nCloud Security Dashboard:\n'));
|
|
799
|
-
console.log(`
|
|
800
|
-
console.log(`
|
|
801
|
-
console.log(`
|
|
802
|
-
console.log(`
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
if (
|
|
806
|
-
console.log(chalk.bold('\
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
const color =
|
|
810
|
-
console.log(` ${
|
|
849
|
+
console.log(` Open Violations: ${chalk.yellow(violationsCount)}`);
|
|
850
|
+
console.log(` Remediations: ${chalk.cyan(healingStats.total_executions || 0)}`);
|
|
851
|
+
console.log(` Success Rate: ${healingStats.success_rate >= 80 ? chalk.green(healingStats.success_rate + '%') : chalk.yellow((healingStats.success_rate || 0) + '%')}`);
|
|
852
|
+
console.log(` Pending Approval: ${chalk.yellow(healingStats.pending_approval || 0)}`);
|
|
853
|
+
// Show per-provider compliance
|
|
854
|
+
const providers = Object.entries(cloudStats).filter(([k]) => ['aws', 'azure', 'gcp'].includes(k));
|
|
855
|
+
if (providers.length > 0) {
|
|
856
|
+
console.log(chalk.bold('\nCloud Compliance by Provider:\n'));
|
|
857
|
+
providers.forEach(([provider, stats]) => {
|
|
858
|
+
const pct = stats.compliance_percent || 0;
|
|
859
|
+
const color = pct >= 80 ? chalk.green : pct >= 60 ? chalk.yellow : chalk.red;
|
|
860
|
+
console.log(` ${chalk.cyan(provider.toUpperCase().padEnd(8))} ${color(pct + '%')} compliance | ${stats.account_count || 0} accounts`);
|
|
811
861
|
});
|
|
812
862
|
}
|
|
813
863
|
}
|
package/dist/sdk.js
CHANGED
|
@@ -234,7 +234,7 @@ class ThreatModelingResource {
|
|
|
234
234
|
return data.threats || data.results || [];
|
|
235
235
|
}
|
|
236
236
|
async generateThreats(diagramId, options = {}) {
|
|
237
|
-
await this.client.request('POST', `/v2/threat-modeling/diagrams/${diagramId}/
|
|
237
|
+
await this.client.request('POST', `/v2/threat-modeling/diagrams/${diagramId}/analyze-threats/`);
|
|
238
238
|
if (options.waitForCompletion !== false) {
|
|
239
239
|
const timeout = options.timeout || 120000;
|
|
240
240
|
const start = Date.now();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ayurak/aribot-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Aribot - Economic, Regulatory & Security APIs for Modern Applications. Advanced multi-framework threat modeling (STRIDE, PASTA, NIST, Aristiun), 100+ compliance standards, Cloud Security, FinOps, and Red Team automation.",
|
|
6
6
|
"main": "dist/index.js",
|
package/src/cli.ts
CHANGED
|
@@ -76,22 +76,26 @@ async function apiRequest(endpoint: string, options: any = {}): Promise<any> {
|
|
|
76
76
|
return response.json();
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// Resolve short UUID to full
|
|
79
|
+
// Resolve short UUID or integer ID to full diagram identifier
|
|
80
80
|
async function resolveDiagramId(shortId: string): Promise<string> {
|
|
81
81
|
// If it already looks like a full UUID, return it
|
|
82
82
|
if (shortId.includes('-') || shortId.length >= 32) {
|
|
83
83
|
return shortId;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
// Fetch diagrams and find by prefix match
|
|
86
|
+
// Fetch diagrams and find by prefix match (UUID) or exact match (integer ID)
|
|
87
87
|
const data = await apiRequest('/v2/threat-modeling/diagrams/?limit=100');
|
|
88
|
-
const match = data.results?.find((d: any) =>
|
|
88
|
+
const match = data.results?.find((d: any) =>
|
|
89
|
+
String(d.id) === shortId ||
|
|
90
|
+
String(d.uuid || '').startsWith(shortId) ||
|
|
91
|
+
String(d.id).startsWith(shortId)
|
|
92
|
+
);
|
|
89
93
|
|
|
90
94
|
if (!match) {
|
|
91
95
|
throw new Error(`No diagram found matching ID: ${shortId}`);
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
return match.id;
|
|
98
|
+
return String(match.id);
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
// Login command
|
|
@@ -590,7 +594,8 @@ program
|
|
|
590
594
|
// Resolve short UUID to full UUID
|
|
591
595
|
const fullId = await resolveDiagramId(diagramId);
|
|
592
596
|
|
|
593
|
-
|
|
597
|
+
// Step 1: Initiate assessment
|
|
598
|
+
const initData = await apiRequest('/v2/compliances/assess_diagram/', {
|
|
594
599
|
method: 'POST',
|
|
595
600
|
body: JSON.stringify({
|
|
596
601
|
diagram_id: fullId,
|
|
@@ -598,21 +603,67 @@ program
|
|
|
598
603
|
})
|
|
599
604
|
});
|
|
600
605
|
|
|
606
|
+
const reportId = initData.report_id;
|
|
607
|
+
if (!reportId) {
|
|
608
|
+
spinner.fail('No report ID returned');
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Step 2: Poll for completion (max 30s)
|
|
613
|
+
let report: any = null;
|
|
614
|
+
for (let i = 0; i < 15; i++) {
|
|
615
|
+
spinner.text = `Running ${options.standard} compliance assessment... (${i * 2}s)`;
|
|
616
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
617
|
+
try {
|
|
618
|
+
report = await apiRequest(`/v2/compliances/reports/${reportId}/`);
|
|
619
|
+
if ((report.status === 'completed' && (report.compliance_score > 0 || report.total_controls > 0)) || report.compliance_score > 0) break;
|
|
620
|
+
} catch { /* retry */ }
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!report) {
|
|
624
|
+
report = initData;
|
|
625
|
+
}
|
|
626
|
+
|
|
601
627
|
spinner.succeed('Compliance assessment complete!');
|
|
602
628
|
|
|
629
|
+
// Extract score from report or compliance_analysis
|
|
630
|
+
const analysis = report.compliance_analysis || report;
|
|
631
|
+
const score = report.compliance_score ?? analysis.overall_score ?? analysis.score;
|
|
632
|
+
const passed = report.passed_controls ?? analysis.passed_controls ?? 0;
|
|
633
|
+
const failed = report.failed_controls ?? analysis.failed_controls ?? 0;
|
|
634
|
+
const total = report.total_controls ?? analysis.total_controls ?? (passed + failed);
|
|
635
|
+
const findings = analysis.high_priority_gaps || analysis.findings || report.findings || [];
|
|
636
|
+
const controlDetails = analysis.control_details || [];
|
|
637
|
+
|
|
603
638
|
console.log(chalk.bold(`\n${options.standard} Compliance Report:\n`));
|
|
604
|
-
console.log(` Score: ${
|
|
605
|
-
console.log(`
|
|
606
|
-
console.log(`
|
|
607
|
-
console.log(`
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
639
|
+
console.log(` Score: ${score >= 80 ? chalk.green(score + '%') : score >= 60 ? chalk.yellow(score + '%') : chalk.red((score ?? 'N/A') + '%')}`);
|
|
640
|
+
console.log(` Total Controls: ${chalk.cyan(total)}`);
|
|
641
|
+
console.log(` Passed Controls: ${chalk.green(passed)}`);
|
|
642
|
+
console.log(` Failed Controls: ${chalk.red(failed)}`);
|
|
643
|
+
console.log(` Status: ${score >= 80 ? chalk.green('Compliant') : score >= 60 ? chalk.yellow('Partially Compliant') : chalk.red('Non-Compliant')}`);
|
|
644
|
+
|
|
645
|
+
if (findings.length > 0) {
|
|
646
|
+
console.log(chalk.bold('\nHigh Priority Gaps:\n'));
|
|
647
|
+
findings.slice(0, 5).forEach((f: any) => {
|
|
648
|
+
const sev = f.severity || 'medium';
|
|
649
|
+
const severityColor = sev === 'critical' ? chalk.red : sev === 'high' ? chalk.red : sev === 'medium' ? chalk.yellow : chalk.dim;
|
|
650
|
+
console.log(` ${severityColor(`[${sev.toUpperCase()}]`)} ${f.description || f.title || f.control_id}`);
|
|
651
|
+
if (f.recommendations?.length > 0) {
|
|
652
|
+
console.log(chalk.dim(` Fix: ${f.recommendations[0]}`));
|
|
653
|
+
}
|
|
614
654
|
});
|
|
615
655
|
}
|
|
656
|
+
|
|
657
|
+
if (controlDetails.length > 0) {
|
|
658
|
+
const nonCompliant = controlDetails.filter((c: any) => c.status === 'non_compliant');
|
|
659
|
+
if (nonCompliant.length > 0) {
|
|
660
|
+
console.log(chalk.bold('\nNon-Compliant Controls:\n'));
|
|
661
|
+
nonCompliant.slice(0, 5).forEach((c: any) => {
|
|
662
|
+
console.log(` ${chalk.red('✗')} ${c.control_id} ${chalk.dim(`(score: ${Math.round((c.score || 0) * 100)}%)`)}`);
|
|
663
|
+
if (c.gaps?.length > 0) console.log(chalk.dim(` ${c.gaps[0]}`));
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
616
667
|
} catch (error) {
|
|
617
668
|
spinner.fail('Compliance assessment failed');
|
|
618
669
|
console.error(error);
|
|
@@ -881,26 +932,29 @@ program
|
|
|
881
932
|
}
|
|
882
933
|
|
|
883
934
|
} else if (options.dashboard) {
|
|
884
|
-
// Get
|
|
885
|
-
const
|
|
886
|
-
|
|
935
|
+
// Get cloud stats, violations, and self-healing stats
|
|
936
|
+
const [cloudStats, violationsData, healingStats] = await Promise.all([
|
|
937
|
+
apiRequest('/v2/compliances/dashboard/cloud-stats/').catch(() => ({})),
|
|
938
|
+
apiRequest('/v2/compliances/unified-violations/?limit=1').catch(() => ({ count: 0 })),
|
|
939
|
+
apiRequest('/v2/ai-agents/self-healing/stats/').catch(() => ({})),
|
|
940
|
+
]);
|
|
887
941
|
const violationsCount = violationsData.count || (Array.isArray(violationsData) ? violationsData.length : 0);
|
|
888
942
|
|
|
889
943
|
spinner.succeed('Dashboard loaded!');
|
|
890
944
|
console.log(chalk.bold('\nCloud Security Dashboard:\n'));
|
|
891
|
-
console.log(`
|
|
892
|
-
console.log(`
|
|
893
|
-
console.log(`
|
|
894
|
-
console.log(`
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
if (
|
|
899
|
-
console.log(chalk.bold('\
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
const color =
|
|
903
|
-
console.log(` ${
|
|
945
|
+
console.log(` Open Violations: ${chalk.yellow(violationsCount)}`);
|
|
946
|
+
console.log(` Remediations: ${chalk.cyan(healingStats.total_executions || 0)}`);
|
|
947
|
+
console.log(` Success Rate: ${healingStats.success_rate >= 80 ? chalk.green(healingStats.success_rate + '%') : chalk.yellow((healingStats.success_rate || 0) + '%')}`);
|
|
948
|
+
console.log(` Pending Approval: ${chalk.yellow(healingStats.pending_approval || 0)}`);
|
|
949
|
+
|
|
950
|
+
// Show per-provider compliance
|
|
951
|
+
const providers = Object.entries(cloudStats).filter(([k]) => ['aws', 'azure', 'gcp'].includes(k));
|
|
952
|
+
if (providers.length > 0) {
|
|
953
|
+
console.log(chalk.bold('\nCloud Compliance by Provider:\n'));
|
|
954
|
+
providers.forEach(([provider, stats]: [string, any]) => {
|
|
955
|
+
const pct = stats.compliance_percent || 0;
|
|
956
|
+
const color = pct >= 80 ? chalk.green : pct >= 60 ? chalk.yellow : chalk.red;
|
|
957
|
+
console.log(` ${chalk.cyan(provider.toUpperCase().padEnd(8))} ${color(pct + '%')} compliance | ${stats.account_count || 0} accounts`);
|
|
904
958
|
});
|
|
905
959
|
}
|
|
906
960
|
|
package/src/sdk.ts
CHANGED
|
@@ -356,7 +356,7 @@ class ThreatModelingResource {
|
|
|
356
356
|
diagramId: string,
|
|
357
357
|
options: { waitForCompletion?: boolean; timeout?: number } = {}
|
|
358
358
|
): Promise<Diagram> {
|
|
359
|
-
await this.client.request('POST', `/v2/threat-modeling/diagrams/${diagramId}/
|
|
359
|
+
await this.client.request('POST', `/v2/threat-modeling/diagrams/${diagramId}/analyze-threats/`);
|
|
360
360
|
|
|
361
361
|
if (options.waitForCompletion !== false) {
|
|
362
362
|
const timeout = options.timeout || 120000;
|