@ayurak/aribot-cli 1.2.0 → 1.3.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/dist/cli.js CHANGED
@@ -693,71 +693,370 @@ program
693
693
  .option('--findings', 'List security findings')
694
694
  .option('--dashboard', 'Show cloud security dashboard')
695
695
  .option('-s, --severity <level>', 'Filter findings by severity (critical, high, medium, low)')
696
+ .option('--dynamic-scan <account-id>', 'Run dynamic cloud scan')
697
+ .option('--unified-scan', 'Run unified scan with scope')
698
+ .option('--scope <type>', 'Scan scope: account, standard, control, policy, diagram, component', 'account')
699
+ .option('--scope-id <id>', 'ID for the scan scope')
700
+ .option('--rules', 'List scanner rules')
701
+ .option('--create-rule', 'Create a new scanner rule (interactive)')
702
+ .option('--sync-rules', 'Sync rules from cloud providers')
703
+ .option('--scanner-stats', 'Show scanner statistics')
704
+ .option('--remediate <policy-id>', 'Execute remediation for a policy')
705
+ .option('--remediate-preview <policy-id>', 'Preview remediation without applying')
706
+ .option('--account-id <id>', 'Cloud account ID for operations')
696
707
  .action(async (options) => {
697
708
  const spinner = ora('Scanning cloud security...').start();
698
709
  try {
699
710
  if (options.scan) {
700
711
  const provider = typeof options.scan === 'string' ? options.scan : undefined;
701
- // Use security posture endpoint
702
- const data = await apiRequest('/v2/compliances/dashboard/cloud-stats/' + (provider ? `?provider=${provider}` : ''));
712
+ // Get violations from unified-violations endpoint
713
+ let violationsUrl = '/v2/compliances/unified-violations/?limit=100';
714
+ if (provider) {
715
+ violationsUrl += `&platform=${provider}`;
716
+ }
717
+ const violationsData = await apiRequest(violationsUrl);
718
+ const violationsList = Array.isArray(violationsData) ? violationsData : (violationsData.results || violationsData.violations || []);
719
+ const totalViolations = violationsData.count || violationsList.length;
720
+ // Get cloud accounts count
721
+ let totalAccounts = 0;
722
+ try {
723
+ const customersData = await apiRequest('/v1/customers/');
724
+ const customers = customersData.results || [];
725
+ totalAccounts = customers.reduce((sum, c) => sum + (c.ac_count || 0), 0);
726
+ }
727
+ catch { /* ignore */ }
728
+ // Count by severity and platform
729
+ const severityCounts = { critical: 0, high: 0, medium: 0, low: 0 };
730
+ const platformCounts = {};
731
+ violationsList.forEach((v) => {
732
+ const sev = (v.severity || 'medium').toLowerCase();
733
+ if (sev in severityCounts)
734
+ severityCounts[sev]++;
735
+ const platform = (v.platform || 'unknown').toLowerCase();
736
+ platformCounts[platform] = (platformCounts[platform] || 0) + 1;
737
+ });
703
738
  spinner.succeed('Cloud security scan complete!');
704
739
  console.log(chalk.bold('\nCloud Security Posture:\n'));
705
- const stats = data.stats || data;
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)}`);
740
+ console.log(` Connected Accounts: ${chalk.cyan(totalAccounts)}`);
741
+ console.log(` Total Violations: ${chalk.yellow(totalViolations)}`);
742
+ console.log(` Critical Issues: ${chalk.red(severityCounts.critical)}`);
743
+ console.log(` High Issues: ${chalk.yellow(severityCounts.high)}`);
744
+ console.log(` Medium Issues: ${chalk.blue(severityCounts.medium)}`);
711
745
  if (provider) {
712
- console.log(`\n Provider: ${chalk.cyan(provider.toUpperCase())}`);
746
+ console.log(`\n Provider: ${chalk.cyan(provider.toUpperCase())}`);
713
747
  }
714
- // Show provider breakdown if available
715
- if (data.by_provider && !provider) {
716
- console.log(chalk.bold('\nBy Provider:\n'));
717
- Object.entries(data.by_provider).forEach(([p, s]) => {
718
- console.log(` ${chalk.cyan(p.toUpperCase().padEnd(8))} Resources: ${s.count || 0} | Score: ${s.score || 'N/A'}%`);
748
+ // Show platform breakdown if scanning all
749
+ if (Object.keys(platformCounts).length > 0 && !provider) {
750
+ console.log(chalk.bold('\nBy Platform:\n'));
751
+ Object.entries(platformCounts)
752
+ .sort((a, b) => b[1] - a[1])
753
+ .forEach(([p, count]) => {
754
+ console.log(` ${chalk.cyan(p.toUpperCase().padEnd(10))} ${count} violations`);
719
755
  });
720
756
  }
721
757
  }
722
758
  else if (options.findings) {
723
- // Use top non-compliant assets endpoint
724
- let url = '/v2/compliances/dashboard/top-assets/?limit=20';
759
+ // Use unified violations endpoint
760
+ let url = '/v2/compliances/unified-violations/?limit=20';
725
761
  if (options.severity) {
726
762
  url += `&severity=${options.severity}`;
727
763
  }
728
764
  const data = await apiRequest(url);
729
765
  spinner.stop();
730
766
  console.log(chalk.bold('\nCloud Security Findings:\n'));
731
- const findings = data.results || data.findings || [];
767
+ const findings = Array.isArray(data) ? data : (data.results || data.violations || data.findings || []);
732
768
  if (findings.length === 0) {
733
769
  console.log(chalk.green(' No open findings! Your cloud is secure.'));
734
770
  }
735
771
  else {
736
772
  const severityColors = {
737
773
  critical: chalk.red,
774
+ crit: chalk.red,
738
775
  high: chalk.yellow,
739
776
  medium: chalk.blue,
740
777
  low: chalk.dim
741
778
  };
742
779
  findings.slice(0, 10).forEach((f) => {
743
- const color = severityColors[f.severity] || chalk.white;
744
- console.log(` ${color(`[${f.severity?.toUpperCase()}]`)} ${f.title}`);
745
- console.log(chalk.dim(` Resource: ${f.resource_type || 'N/A'} | Policy: ${f.policy || 'N/A'}`));
780
+ const sev = (f.severity || 'medium').toLowerCase();
781
+ const color = severityColors[sev] || chalk.white;
782
+ const ruleName = f.rule_name || f.title || 'Unknown';
783
+ const resource = f.resource_name || f.resource_type || 'N/A';
784
+ const platform = (f.platform || 'N/A').toUpperCase();
785
+ console.log(` ${color(`[${sev.toUpperCase()}]`)} ${ruleName}`);
786
+ console.log(chalk.dim(` Resource: ${resource} | Platform: ${platform}`));
746
787
  });
747
- console.log(chalk.dim(`\nShowing ${Math.min(10, findings.length)} of ${findings.length} findings`));
788
+ const totalCount = data.count || findings.length;
789
+ console.log(chalk.dim(`\nShowing ${Math.min(10, findings.length)} of ${totalCount} findings`));
748
790
  }
749
791
  }
750
792
  else if (options.dashboard) {
751
- const data = await apiRequest('/v2/compliances/dashboard/cloud-stats/');
793
+ // Get dashboard trends and violations count
794
+ const dashboardData = await apiRequest('/v2/compliances/dashboard/trends/');
795
+ const violationsData = await apiRequest('/v2/compliances/unified-violations/?limit=1');
796
+ const violationsCount = violationsData.count || (Array.isArray(violationsData) ? violationsData.length : 0);
752
797
  spinner.succeed('Dashboard loaded!');
753
798
  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)}`);
799
+ console.log(` Fix Velocity: ${chalk.green(dashboardData.fix_velocity || 'N/A')}`);
800
+ console.log(` Time Range: ${chalk.cyan(dashboardData.time_range || '7d')}`);
801
+ console.log(` Resolved Issues: ${chalk.green(dashboardData.total_resolved || 0)}`);
802
+ console.log(` Avg Resolution: ${dashboardData.avg_resolution_time_hours || 'N/A'}h`);
803
+ console.log(` Open Violations: ${chalk.yellow(violationsCount)}`);
804
+ // Show severity breakdown if available
805
+ if (dashboardData.by_severity) {
806
+ console.log(chalk.bold('\nResolved by Severity:\n'));
807
+ const sevColors = { critical: chalk.red, high: chalk.yellow, medium: chalk.blue, low: chalk.dim };
808
+ Object.entries(dashboardData.by_severity).forEach(([sev, count]) => {
809
+ const color = sevColors[sev.toLowerCase()] || chalk.white;
810
+ console.log(` ${color(sev.toUpperCase().padEnd(10))} ${count}`);
811
+ });
812
+ }
813
+ }
814
+ else if (options.dynamicScan) {
815
+ // Dynamic cloud scan
816
+ spinner.text = 'Running dynamic cloud scan...';
817
+ const data = await apiRequest('/v2/compliances/dynamic-scan/execute/', {
818
+ method: 'POST',
819
+ body: JSON.stringify({ account_id: parseInt(options.dynamicScan) })
820
+ });
821
+ spinner.succeed('Dynamic scan initiated!');
822
+ console.log(chalk.bold('\nDynamic Scan Results:\n'));
823
+ console.log(` Scan ID: ${chalk.cyan(data.scan_id || 'N/A')}`);
824
+ console.log(` Account ID: ${options.dynamicScan}`);
825
+ console.log(` Status: ${chalk.green(data.status || 'initiated')}`);
826
+ console.log(` Started At: ${chalk.dim(data.started_at || 'now')}`);
827
+ if (data.findings_count) {
828
+ console.log(` Findings: ${chalk.yellow(data.findings_count)}`);
829
+ }
830
+ if (data.async) {
831
+ console.log(chalk.dim('\nScan running asynchronously. Check status with --dashboard'));
832
+ }
833
+ }
834
+ else if (options.unifiedScan) {
835
+ // Unified scan with scope
836
+ if (!options.scopeId && options.scope !== 'account') {
837
+ spinner.fail('--scope-id required for non-account scopes');
838
+ return;
839
+ }
840
+ spinner.text = `Running unified scan (${options.scope})...`;
841
+ const scanData = { scope: options.scope };
842
+ if (options.scope === 'account') {
843
+ scanData.account_id = options.accountId || (options.scopeId ? parseInt(options.scopeId) : undefined);
844
+ }
845
+ else if (options.scope === 'standard') {
846
+ scanData.standard_id = options.scopeId;
847
+ }
848
+ else if (options.scope === 'control') {
849
+ scanData.control_id = options.scopeId;
850
+ }
851
+ else if (options.scope === 'policy') {
852
+ scanData.policy_id = options.scopeId;
853
+ }
854
+ else if (options.scope === 'diagram') {
855
+ scanData.diagram_id = options.scopeId;
856
+ }
857
+ else if (options.scope === 'component') {
858
+ scanData.component_id = options.scopeId;
859
+ }
860
+ if (options.accountId) {
861
+ scanData.account_id = parseInt(options.accountId);
862
+ }
863
+ const data = await apiRequest('/v2/compliances/scan/execute/', {
864
+ method: 'POST',
865
+ body: JSON.stringify(scanData)
866
+ });
867
+ spinner.succeed('Unified scan complete!');
868
+ console.log(chalk.bold(`\nUnified Scan Results (${options.scope}):\n`));
869
+ console.log(` Scan ID: ${chalk.cyan(data.scan_id || 'N/A')}`);
870
+ console.log(` Scope: ${options.scope}`);
871
+ console.log(` Status: ${chalk.green(data.status || 'completed')}`);
872
+ const results = data.results || data;
873
+ console.log(` Total Checked: ${results.total_checks || results.total || 0}`);
874
+ console.log(` Passed: ${chalk.green(results.passed || 0)}`);
875
+ console.log(` Failed: ${chalk.red(results.failed || 0)}`);
876
+ if (results.compliance_score !== undefined) {
877
+ const score = results.compliance_score;
878
+ const scoreColor = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red;
879
+ console.log(` Score: ${scoreColor(score + '%')}`);
880
+ }
881
+ }
882
+ else if (options.rules) {
883
+ // List scanner rules
884
+ spinner.text = 'Fetching scanner rules...';
885
+ let url = '/v2/compliances/scanner-rules/';
886
+ if (options.severity) {
887
+ url += `?severity=${options.severity}`;
888
+ }
889
+ const data = await apiRequest(url);
890
+ spinner.stop();
891
+ const rulesList = data.results || data.rules || [];
892
+ console.log(chalk.bold(`\nScanner Rules (${rulesList.length} total):\n`));
893
+ if (rulesList.length === 0) {
894
+ console.log(chalk.dim(' No scanner rules found.'));
895
+ }
896
+ else {
897
+ const severityColors = {
898
+ critical: chalk.red,
899
+ high: chalk.yellow,
900
+ medium: chalk.blue,
901
+ low: chalk.dim
902
+ };
903
+ rulesList.slice(0, 20).forEach((r) => {
904
+ const color = severityColors[r.severity] || chalk.white;
905
+ const enabled = r.enabled !== false ? chalk.green('✓') : chalk.red('✗');
906
+ console.log(` ${enabled} ${chalk.cyan((r.id + '').slice(0, 8).padEnd(8))} ${color(`[${(r.severity || 'medium').toUpperCase()}]`)} ${(r.name || 'N/A').slice(0, 40)}`);
907
+ console.log(chalk.dim(` Provider: ${r.provider || 'N/A'}`));
908
+ });
909
+ }
910
+ }
911
+ else if (options.createRule) {
912
+ // Interactive rule creation
913
+ spinner.stop();
914
+ console.log(chalk.bold('\nCreate Scanner Rule\n'));
915
+ const answers = await inquirer.prompt([
916
+ { type: 'input', name: 'name', message: 'Rule name:' },
917
+ { type: 'input', name: 'description', message: 'Description:' },
918
+ { type: 'list', name: 'severity', message: 'Severity:', choices: ['critical', 'high', 'medium', 'low'], default: 'medium' },
919
+ { type: 'list', name: 'provider', message: 'Provider:', choices: ['aws', 'azure', 'gcp', 'custom'], default: 'custom' }
920
+ ]);
921
+ const createSpinner = ora('Creating rule...').start();
922
+ const data = await apiRequest('/v2/compliances/scanner-rules/', {
923
+ method: 'POST',
924
+ body: JSON.stringify({
925
+ name: answers.name,
926
+ description: answers.description,
927
+ severity: answers.severity,
928
+ provider: answers.provider,
929
+ enabled: true
930
+ })
931
+ });
932
+ createSpinner.succeed('Rule created successfully!');
933
+ console.log(` ID: ${chalk.cyan(data.id || 'N/A')}`);
934
+ console.log(` Name: ${data.name || answers.name}`);
935
+ console.log(` Severity: ${data.severity || answers.severity}`);
936
+ }
937
+ else if (options.syncRules) {
938
+ // Sync rules from cloud providers
939
+ spinner.text = 'Syncing rules from cloud providers...';
940
+ const data = await apiRequest('/v2/compliances/scanner-rules/sync_from_providers/', {
941
+ method: 'POST',
942
+ body: JSON.stringify({})
943
+ });
944
+ spinner.succeed('Rules synced successfully!');
945
+ console.log(chalk.bold('\nSync Results:\n'));
946
+ console.log(` AWS Rules: ${chalk.cyan(data.aws_rules || data.aws || 0)}`);
947
+ console.log(` Azure Rules: ${chalk.cyan(data.azure_rules || data.azure || 0)}`);
948
+ console.log(` GCP Rules: ${chalk.cyan(data.gcp_rules || data.gcp || 0)}`);
949
+ console.log(` Total: ${chalk.green(data.total || data.total_synced || 0)}`);
950
+ }
951
+ else if (options.scannerStats) {
952
+ // Scanner statistics
953
+ spinner.text = 'Fetching scanner statistics...';
954
+ const data = await apiRequest('/v2/compliances/scanner-rules/statistics/');
955
+ spinner.stop();
956
+ console.log(chalk.bold('\nScanner Statistics:\n'));
957
+ const stats = data.statistics || data;
958
+ console.log(` Total Rules: ${chalk.cyan(stats.total_rules || 0)}`);
959
+ console.log(` Active Rules: ${chalk.green(stats.active_rules || stats.enabled || 0)}`);
960
+ console.log(` Total Scans: ${stats.total_scans || 0}`);
961
+ console.log(` Findings Today: ${chalk.yellow(stats.findings_today || 0)}`);
962
+ if (stats.by_severity) {
963
+ console.log(chalk.bold('\nRules by Severity:\n'));
964
+ const severityColors = {
965
+ critical: chalk.red,
966
+ high: chalk.yellow,
967
+ medium: chalk.blue,
968
+ low: chalk.dim
969
+ };
970
+ Object.entries(stats.by_severity).forEach(([sev, count]) => {
971
+ const color = severityColors[sev] || chalk.white;
972
+ console.log(` ${color(sev.toUpperCase().padEnd(10))} ${count}`);
973
+ });
974
+ }
975
+ if (stats.by_provider) {
976
+ console.log(chalk.bold('\nRules by Provider:\n'));
977
+ Object.entries(stats.by_provider).forEach(([prov, count]) => {
978
+ console.log(` ${chalk.cyan(prov.toUpperCase().padEnd(10))} ${count}`);
979
+ });
980
+ }
981
+ }
982
+ else if (options.remediate) {
983
+ // Execute remediation
984
+ if (!options.accountId) {
985
+ spinner.fail('--account-id required for remediation');
986
+ return;
987
+ }
988
+ spinner.text = 'Executing remediation...';
989
+ const data = await apiRequest('/v2/compliances/remediation-execution/execute/', {
990
+ method: 'POST',
991
+ body: JSON.stringify({
992
+ policy_id: options.remediate,
993
+ account_id: parseInt(options.accountId)
994
+ })
995
+ });
996
+ spinner.succeed('Remediation executed!');
997
+ console.log(chalk.bold('\nRemediation Results:\n'));
998
+ console.log(` Policy ID: ${chalk.cyan(options.remediate)}`);
999
+ console.log(` Account ID: ${options.accountId}`);
1000
+ console.log(` Status: ${chalk.green(data.status || 'completed')}`);
1001
+ console.log(` Resources: ${data.resources_affected || 0}`);
1002
+ if (data.changes && data.changes.length > 0) {
1003
+ console.log(chalk.bold('\nChanges Applied:\n'));
1004
+ data.changes.slice(0, 5).forEach((change) => {
1005
+ console.log(` ${chalk.green('✓')} ${change.description || change}`);
1006
+ });
1007
+ }
1008
+ }
1009
+ else if (options.remediatePreview) {
1010
+ // Preview remediation
1011
+ if (!options.accountId) {
1012
+ spinner.fail('--account-id required for remediation preview');
1013
+ return;
1014
+ }
1015
+ spinner.text = 'Generating remediation preview...';
1016
+ const data = await apiRequest('/v2/compliances/remediation-execution/preview/', {
1017
+ method: 'POST',
1018
+ body: JSON.stringify({
1019
+ policy_id: options.remediatePreview,
1020
+ account_id: parseInt(options.accountId)
1021
+ })
1022
+ });
1023
+ spinner.stop();
1024
+ console.log(chalk.bold('\nRemediation Preview:\n'));
1025
+ console.log(` Policy ID: ${chalk.cyan(options.remediatePreview)}`);
1026
+ console.log(` Account ID: ${options.accountId}`);
1027
+ console.log(` Resources: ${chalk.yellow(data.resources_affected || 0)}`);
1028
+ console.log(` Estimated Time: ${chalk.dim(data.estimated_time || 'N/A')}`);
1029
+ const changes = data.planned_changes || data.changes || [];
1030
+ if (changes.length > 0) {
1031
+ console.log(chalk.bold('\nPlanned Changes:\n'));
1032
+ changes.slice(0, 10).forEach((change) => {
1033
+ console.log(` ${chalk.yellow('→')} ${change.description || change.action || change}`);
1034
+ if (change.resource) {
1035
+ console.log(chalk.dim(` Resource: ${change.resource}`));
1036
+ }
1037
+ });
1038
+ }
1039
+ console.log(chalk.dim('\nRun with --remediate to apply these changes'));
757
1040
  }
758
1041
  else {
759
1042
  spinner.stop();
760
- console.log(chalk.yellow('Usage: aribot cloud-security [--scan [provider]] [--findings] [--dashboard]'));
1043
+ console.log(chalk.bold('Cloud Security Posture Management (CSPM/CNAPP)\n'));
1044
+ console.log(chalk.bold('Basic Commands'));
1045
+ console.log(` ${chalk.cyan('aribot cloud-security --scan')} Scan all cloud accounts`);
1046
+ console.log(` ${chalk.cyan('aribot cloud-security --scan aws')} Scan AWS only`);
1047
+ console.log(` ${chalk.cyan('aribot cloud-security --findings')} List security findings`);
1048
+ console.log(` ${chalk.cyan('aribot cloud-security --dashboard')} Show security dashboard`);
1049
+ console.log(chalk.bold('\nScanner Commands'));
1050
+ console.log(` ${chalk.green('aribot cloud-security --dynamic-scan <account-id>')} Run dynamic scan`);
1051
+ console.log(` ${chalk.green('aribot cloud-security --unified-scan --scope account --account-id 123')}`);
1052
+ console.log(` ${chalk.green('aribot cloud-security --unified-scan --scope standard --scope-id CIS-AWS')}`);
1053
+ console.log(` ${chalk.green('aribot cloud-security --rules')} List scanner rules`);
1054
+ console.log(` ${chalk.green('aribot cloud-security --create-rule')} Create custom rule`);
1055
+ console.log(` ${chalk.green('aribot cloud-security --sync-rules')} Sync from providers`);
1056
+ console.log(` ${chalk.green('aribot cloud-security --scanner-stats')} Show statistics`);
1057
+ console.log(chalk.bold('\nRemediation Commands'));
1058
+ console.log(` ${chalk.yellow('aribot cloud-security --remediate-preview <policy-id> --account-id 123')}`);
1059
+ console.log(` ${chalk.yellow('aribot cloud-security --remediate <policy-id> --account-id 123')}`);
761
1060
  }
762
1061
  }
763
1062
  catch (error) {
@@ -787,8 +1086,44 @@ program
787
1086
  .action(async (options) => {
788
1087
  if (options.methodologies) {
789
1088
  const spinner = ora('Fetching methodologies...').start();
1089
+ // Static fallback data for when backend engine is unavailable
1090
+ const fallbackData = {
1091
+ available_methodologies: [
1092
+ { name: 'STRIDE', description: 'Spoofing, Tampering, Repudiation, Info Disclosure, DoS, Elevation' },
1093
+ { name: 'PASTA', description: 'Process for Attack Simulation and Threat Analysis' },
1094
+ { name: 'NIST', description: 'NIST Cybersecurity Framework threat modeling' },
1095
+ { name: 'MITRE ATT&CK', description: 'Adversarial tactics, techniques, and common knowledge' },
1096
+ { name: 'OWASP', description: 'Open Web Application Security Project methodology' },
1097
+ { name: 'AI_ENHANCED', description: 'AI-powered predictive threat analysis' },
1098
+ ],
1099
+ risk_levels: [
1100
+ { name: 'Critical', description: 'Immediate action required - system compromise likely' },
1101
+ { name: 'High', description: 'Significant risk - address within 24-48 hours' },
1102
+ { name: 'Medium', description: 'Moderate risk - address within 1-2 weeks' },
1103
+ { name: 'Low', description: 'Minor risk - address in regular maintenance' },
1104
+ { name: 'Info', description: 'Informational finding - no immediate action needed' },
1105
+ ],
1106
+ compliance_frameworks: [
1107
+ { name: 'SOC2', description: 'Service Organization Control 2' },
1108
+ { name: 'ISO27001', description: 'Information Security Management' },
1109
+ { name: 'PCI-DSS', description: 'Payment Card Industry Data Security Standard' },
1110
+ { name: 'GDPR', description: 'General Data Protection Regulation' },
1111
+ { name: 'HIPAA', description: 'Health Insurance Portability and Accountability' },
1112
+ { name: 'NIST-CSF', description: 'NIST Cybersecurity Framework' },
1113
+ { name: 'CIS', description: 'Center for Internet Security Controls' },
1114
+ { name: 'FedRAMP', description: 'Federal Risk and Authorization Management' },
1115
+ ],
1116
+ engine_capabilities: {
1117
+ multi_framework_analysis: true,
1118
+ ai_threat_prediction: true,
1119
+ real_time_scanning: true,
1120
+ attack_path_analysis: true,
1121
+ compliance_mapping: true,
1122
+ automated_remediation: true,
1123
+ }
1124
+ };
790
1125
  try {
791
- const data = await apiRequest('/v2/threat-engine/threat-models/');
1126
+ const data = await apiRequest('/v2/threat-modeling/threat-engine/threat-models/');
792
1127
  spinner.stop();
793
1128
  console.log(chalk.bold('\nThreat Modeling Methodologies:\n'));
794
1129
  (data.available_methodologies || []).forEach((m) => {
@@ -809,15 +1144,38 @@ program
809
1144
  });
810
1145
  }
811
1146
  catch (error) {
812
- spinner.fail('Failed to fetch methodologies');
813
- console.error(error);
1147
+ // Use fallback data for 404/503 errors (endpoint not deployed or engine unavailable)
1148
+ if (error.message?.includes('404') || error.message?.includes('503') || error.message?.includes('unavailable') || error.message?.includes('Not Found')) {
1149
+ spinner.stop();
1150
+ console.log(chalk.dim('(Using cached methodology data)\n'));
1151
+ console.log(chalk.bold('\nThreat Modeling Methodologies:\n'));
1152
+ fallbackData.available_methodologies.forEach((m) => {
1153
+ console.log(` ${chalk.cyan(m.name.toUpperCase().padEnd(14))} ${chalk.dim(m.description)}`);
1154
+ });
1155
+ console.log(chalk.bold('\nRisk Levels:\n'));
1156
+ fallbackData.risk_levels.forEach((r) => {
1157
+ console.log(` ${chalk.yellow(r.name.padEnd(12))} ${chalk.dim(r.description)}`);
1158
+ });
1159
+ console.log(chalk.bold('\nCompliance Frameworks:\n'));
1160
+ fallbackData.compliance_frameworks.forEach((f) => {
1161
+ console.log(` ${chalk.green(f.name.padEnd(12))} ${chalk.dim(f.description)}`);
1162
+ });
1163
+ console.log(chalk.bold('\nEngine Capabilities:\n'));
1164
+ Object.entries(fallbackData.engine_capabilities).forEach(([key, value]) => {
1165
+ console.log(` ${value ? chalk.green('✓') : chalk.red('✗')} ${key.replace(/_/g, ' ')}`);
1166
+ });
1167
+ }
1168
+ else {
1169
+ spinner.fail('Failed to fetch methodologies');
1170
+ console.error(error);
1171
+ }
814
1172
  }
815
1173
  return;
816
1174
  }
817
1175
  if (options.intelligence) {
818
1176
  const spinner = ora('Fetching threat intelligence...').start();
819
1177
  try {
820
- const data = await apiRequest('/v2/threat-engine/threat-intelligence/');
1178
+ const data = await apiRequest('/v2/threat-modeling/threat-engine/threat-intelligence/');
821
1179
  spinner.stop();
822
1180
  console.log(chalk.bold('\nThreat Intelligence Summary:\n'));
823
1181
  const intel = data.threat_intelligence || {};
@@ -867,34 +1225,36 @@ program
867
1225
  console.log(chalk.dim('Upload a diagram with at least 2 connected components.'));
868
1226
  return;
869
1227
  }
870
- // Generate attack paths
871
- const data = await apiRequest('/v2/threat-engine/attack-paths/', {
1228
+ // Generate attack paths using the correct v2 endpoint (same as frontend)
1229
+ const data = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/generate-attack-paths/`, {
872
1230
  method: 'POST',
873
1231
  body: JSON.stringify({
874
- components,
875
- connections,
876
- source_node: components[0]?.id || '',
877
- target_node: components[components.length - 1]?.id || ''
1232
+ scope: 'single',
1233
+ include_compliance: true,
1234
+ save: true
878
1235
  })
879
1236
  });
880
1237
  spinner.succeed('Attack path analysis complete!');
1238
+ // Response matches frontend: { status: 'success', paths: [...] }
1239
+ const paths = data.paths || data.attack_paths || [];
881
1240
  console.log(chalk.bold('\nAttack Path Analysis:\n'));
882
- console.log(` Source: ${chalk.cyan(data.analysis_summary?.source_node || 'N/A')}`);
883
- console.log(` Target: ${chalk.cyan(data.analysis_summary?.target_node || 'N/A')}`);
884
- console.log(` Paths Found: ${chalk.yellow(data.analysis_summary?.total_paths_found || 0)}`);
885
- const paths = data.attack_paths || [];
1241
+ console.log(` Paths Found: ${chalk.yellow(paths.length)}`);
1242
+ console.log(` Status: ${chalk.cyan(data.status || 'completed')}`);
886
1243
  if (paths.length > 0) {
887
1244
  console.log(chalk.bold('\nIdentified Attack Paths:\n'));
888
1245
  paths.slice(0, 5).forEach((p, i) => {
889
- const riskColor = p.risk_score > 0.5 ? chalk.red : p.risk_score > 0.2 ? chalk.yellow : chalk.green;
890
- console.log(` ${chalk.bold(`Path ${i + 1}:`)} ${p.source_node} ${p.target_node}`);
891
- console.log(` Risk Score: ${riskColor((p.risk_score * 100).toFixed(1) + '%')}`);
892
- console.log(` Likelihood: ${chalk.cyan((p.likelihood * 100).toFixed(1) + '%')}`);
893
- console.log(` Impact: ${chalk.yellow((p.impact * 100).toFixed(1) + '%')}`);
894
- console.log(` Steps: ${chalk.dim(p.steps?.length || 0)}`);
1246
+ const riskScore = p.risk_score || 0;
1247
+ const riskColor = riskScore >= 80 ? chalk.red : riskScore >= 60 ? chalk.yellow : chalk.green;
1248
+ const riskLabel = riskScore >= 80 ? 'CRITICAL' : riskScore >= 60 ? 'HIGH' : riskScore >= 40 ? 'MEDIUM' : 'LOW';
1249
+ console.log(` ${chalk.bold(`Path ${i + 1}:`)} ${p.title || 'Attack Path'}`);
1250
+ console.log(` Risk: ${riskColor(riskLabel)} (${riskScore}%)`);
1251
+ console.log(` Description: ${chalk.dim(p.description || 'N/A')}`);
1252
+ console.log(` Steps: ${chalk.cyan(p.steps?.length || 0)}`);
1253
+ console.log(` Mitigations: ${chalk.green(p.mitigations?.length || 0)}`);
895
1254
  if (p.steps?.length > 0) {
1255
+ console.log(chalk.dim(' Attack Chain:'));
896
1256
  p.steps.forEach((s, j) => {
897
- console.log(chalk.dim(` ${j + 1}. ${s.from_node} → ${s.to_node}`));
1257
+ console.log(chalk.dim(` ${j + 1}. ${s.action || s.from_node} → ${s.target_component_name || s.to_node}`));
898
1258
  });
899
1259
  }
900
1260
  console.log();
@@ -966,7 +1326,7 @@ program
966
1326
  severity: t.severity,
967
1327
  category: t.category
968
1328
  }));
969
- const data = await apiRequest('/v2/threat-engine/security-requirements/', {
1329
+ const data = await apiRequest('/v2/threat-modeling/threat-engine/security-requirements/', {
970
1330
  method: 'POST',
971
1331
  body: JSON.stringify({
972
1332
  threats,
@@ -1627,17 +1987,17 @@ program
1627
1987
  const spinner = ora('Processing...').start();
1628
1988
  try {
1629
1989
  if (options.providers) {
1630
- const data = await apiRequest('/v2/digital-twin/providers/');
1990
+ const data = await apiRequest('/v2/threat-modeling/digital-twin/providers/');
1631
1991
  spinner.stop();
1632
1992
  console.log(chalk.bold('\nCloud Providers:\n'));
1633
1993
  (data.results || data || []).forEach((p) => {
1634
1994
  const status = p.connected ? chalk.green('✓') : chalk.red('✗');
1635
- console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.provider_type || p.type)}`);
1995
+ console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.display_name || p.provider_type || p.type || '')}`);
1636
1996
  });
1637
1997
  }
1638
1998
  else if (options.resources) {
1639
1999
  const provider = typeof options.resources === 'string' ? `?provider=${options.resources}` : '';
1640
- const data = await apiRequest(`/v2/digital-twin/resources/${provider}`);
2000
+ const data = await apiRequest(`/v2/threat-modeling/digital-twin/resources/${provider}`);
1641
2001
  spinner.stop();
1642
2002
  console.log(chalk.bold('\nCloud Resources:\n'));
1643
2003
  (data.results || data || []).slice(0, 20).forEach((r) => {
@@ -1645,7 +2005,7 @@ program
1645
2005
  });
1646
2006
  }
1647
2007
  else if (options.sync) {
1648
- const data = await apiRequest('/v2/digital-twin/sync/', {
2008
+ const data = await apiRequest('/v2/threat-modeling/digital-twin/sync/', {
1649
2009
  method: 'POST',
1650
2010
  body: JSON.stringify({ provider_id: options.sync })
1651
2011
  });
@@ -1653,7 +2013,7 @@ program
1653
2013
  console.log(` Resources discovered: ${chalk.cyan(data.resources_found || 0)}`);
1654
2014
  }
1655
2015
  else if (options.discover) {
1656
- const data = await apiRequest('/v2/digital-twin/discover/', {
2016
+ const data = await apiRequest('/v2/threat-modeling/digital-twin/discover/', {
1657
2017
  method: 'POST',
1658
2018
  body: JSON.stringify({ provider_id: options.discover })
1659
2019
  });
@@ -1661,7 +2021,7 @@ program
1661
2021
  console.log(` Resources found: ${chalk.cyan(data.resources_count || 0)}`);
1662
2022
  }
1663
2023
  else if (options.health) {
1664
- const data = await apiRequest('/v2/digital-twin/health/');
2024
+ const data = await apiRequest('/v2/threat-modeling/digital-twin/health/');
1665
2025
  spinner.stop();
1666
2026
  console.log(chalk.bold('\nDigital Twin Health:\n'));
1667
2027
  console.log(` Status: ${data.healthy ? chalk.green('Healthy') : chalk.red('Unhealthy')}`);
@@ -1881,29 +2241,38 @@ program
1881
2241
  const spinner = ora('Loading dashboard...').start();
1882
2242
  try {
1883
2243
  if (options.overview || (!options.recent && !options.risk && !options.billing)) {
1884
- const data = await apiRequest('/v2/threat-modeling/dashboard/');
2244
+ // Use v1 dashboard endpoint which exists
2245
+ const data = await apiRequest('/v1/tm/dashboard/status-progress-compliance/');
1885
2246
  spinner.stop();
1886
2247
  console.log(chalk.bold('\nDashboard Overview:\n'));
1887
- console.log(` Total Diagrams: ${chalk.cyan(data.total_diagrams || 0)}`);
1888
- console.log(` Total Threats: ${chalk.yellow(data.total_threats || 0)}`);
1889
- console.log(` Critical Threats: ${chalk.red(data.critical_threats || 0)}`);
1890
- console.log(` Compliance Score: ${chalk.green((data.compliance_score || 0) + '%')}`);
2248
+ const overall = data.overall_compliance || {};
2249
+ const status = overall.status || {};
2250
+ console.log(` Unresolved: ${chalk.yellow(status.unresolved || 0)}`);
2251
+ console.log(` In Progress: ${chalk.cyan(status.in_progress || 0)}`);
2252
+ console.log(` Resolved: ${chalk.green(status.resolved || 0)}`);
2253
+ console.log(` With Resource: ${chalk.blue((overall.with_resource || 0) + '%')}`);
1891
2254
  }
1892
2255
  else if (options.recent) {
1893
- const data = await apiRequest('/v2/threat-modeling/dashboard/recent-activity/');
2256
+ // Use v1 dashboard activity endpoint
2257
+ const data = await apiRequest('/v1/tm/dashboard/status-progress-compliance/');
1894
2258
  spinner.stop();
1895
2259
  console.log(chalk.bold('\nRecent Activity:\n'));
1896
- (data.activities || data || []).slice(0, 10).forEach((a) => {
1897
- console.log(` ${chalk.dim(a.timestamp?.slice(0, 16) || '')} ${a.action} ${chalk.cyan(a.resource || '')}`);
2260
+ const progress = data.status_progress || [];
2261
+ progress.slice(0, 7).forEach((p) => {
2262
+ console.log(` ${chalk.dim(p.date)} (${p.day}) Unresolved: ${chalk.yellow(p.statuses?.unresolved || 0)} Resolved: ${chalk.green(p.statuses?.resolved || 0)}`);
1898
2263
  });
1899
2264
  }
1900
2265
  else if (options.risk) {
1901
- const data = await apiRequest('/v2/threat-modeling/dashboard/risk-summary/');
2266
+ // Use v1 dashboard for risk summary
2267
+ const data = await apiRequest('/v1/tm/dashboard/status-progress-compliance/');
1902
2268
  spinner.stop();
1903
2269
  console.log(chalk.bold('\nRisk Summary:\n'));
1904
- console.log(` Overall Risk: ${data.overall_risk === 'high' ? chalk.red(data.overall_risk) : chalk.yellow(data.overall_risk || 'N/A')}`);
1905
- console.log(` Open Threats: ${chalk.yellow(data.open_threats || 0)}`);
1906
- console.log(` Mitigated: ${chalk.green(data.mitigated_threats || 0)}`);
2270
+ const status = data.overall_compliance?.status || {};
2271
+ const total = (status.unresolved || 0) + (status.in_progress || 0) + (status.resolved || 0);
2272
+ const riskLevel = status.unresolved > total * 0.5 ? 'high' : status.unresolved > total * 0.2 ? 'medium' : 'low';
2273
+ console.log(` Overall Risk: ${riskLevel === 'high' ? chalk.red(riskLevel) : chalk.yellow(riskLevel)}`);
2274
+ console.log(` Open Threats: ${chalk.yellow(status.unresolved || 0)}`);
2275
+ console.log(` Mitigated: ${chalk.green(status.resolved || 0)}`);
1907
2276
  }
1908
2277
  else if (options.billing) {
1909
2278
  const data = await apiRequest('/v1/developer/billing/');