nsauditor-ai 0.1.27 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli.mjs +42 -16
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -90,7 +90,7 @@ function redactSensitiveForAI(input, targetHost) {
90
90
 
91
91
  /* ------------------------- OpenAI & reporting -------------------------- */
92
92
 
93
- async function maybeSendToOpenAI({ host, results, conclusion, promptMode = 'basic' }) {
93
+ async function maybeSendToOpenAI({ host, results, conclusion, promptMode = 'basic', outDir: presetOutDir = null }) {
94
94
  // --- env & opts -----------------------------------------------------------
95
95
  const sendEnabled = parseBool(process.env.AI_ENABLED);
96
96
  const redactEnabled = parseBool(process.env.OPENAI_REDACT, true);
@@ -108,17 +108,17 @@ async function maybeSendToOpenAI({ host, results, conclusion, promptMode = 'basi
108
108
  : await resolveSecret(process.env.OPENAI_API_KEY);
109
109
  const key = keyRaw ? String(keyRaw).trim() : null;
110
110
 
111
- // Base output folder (resolved via the shared helper honors --out and
112
- // the SCAN_OUT_PATH / OPENAI_OUT_PATH env vars consistently with the
113
- // SARIF/CSV/MD writers below).
114
- const baseOutDir = resolveBaseOutDir();
115
-
116
- await fsp.mkdir(baseOutDir, { recursive: true });
117
-
118
- // Per-scan folder
119
- const ts = nowStamp();
120
- const runDir = `${safeHost(host)}_${ts}`;
121
- const outDir = path.join(baseOutDir, runDir);
111
+ // Per-scan folder. Caller (scanSingleHost) may pass a pre-computed outDir so
112
+ // that EE enrichment + compliance artifacts share the same folder as the AI
113
+ // outputs otherwise compute one here for legacy callers.
114
+ let outDir = presetOutDir;
115
+ if (!outDir) {
116
+ const baseOutDir = resolveBaseOutDir();
117
+ await fsp.mkdir(baseOutDir, { recursive: true });
118
+ const ts = nowStamp();
119
+ const runDir = `${safeHost(host)}_${ts}`;
120
+ outDir = path.join(baseOutDir, runDir);
121
+ }
122
122
  await fsp.mkdir(outDir, { recursive: true });
123
123
 
124
124
  // Paths (fixed names inside per-scan folder)
@@ -536,7 +536,7 @@ async function parseArgs(argv) {
536
536
  const p = get('plugins');
537
537
  if (p && p !== true && p.toLowerCase() !== 'all') {
538
538
  args.plugins = p.split(',').map((s) => s.trim()).filter(Boolean);
539
- } else if (p && p.toLowerCase() === 'all') {
539
+ } else if (p && p !== true && p.toLowerCase() === 'all') {
540
540
  args.plugins = 'all';
541
541
  }
542
542
  args.insecureHttps = !!(get('insecure-https') || get('insecure_https'));
@@ -570,6 +570,13 @@ async function parseArgs(argv) {
570
570
  const alertSev = get('alert-severity') || get('alert_severity') || null;
571
571
  args.alertSeverity = (alertSev && alertSev !== true) ? alertSev.toLowerCase() : 'high';
572
572
 
573
+ // Compliance: framework selector + scope file. Forwarded to EE's
574
+ // runCompliancePhase via enrichScan(). No-op without an EE Enterprise license.
575
+ const complianceVal = get('compliance');
576
+ args.compliance = (complianceVal && complianceVal !== true) ? complianceVal : null;
577
+ const complianceScopeVal = get('compliance-scope') || get('compliance_scope');
578
+ args.complianceScope = (complianceScopeVal && complianceScopeVal !== true) ? complianceScopeVal : null;
579
+
573
580
  return args;
574
581
  }
575
582
 
@@ -599,17 +606,34 @@ async function scanSingleHost(pm, host, plugins, opts, promptMode) {
599
606
  conclusion.result.techniques = techniques;
600
607
  }
601
608
 
609
+ // Pre-compute the per-scan output folder so EE enrichment, compliance
610
+ // artifacts, and AI outputs all land in the same directory. maybeSendToOpenAI
611
+ // will reuse this presetOutDir below.
612
+ const baseOutDir = resolveBaseOutDir();
613
+ await fsp.mkdir(baseOutDir, { recursive: true });
614
+ const ts = nowStamp();
615
+ const outDir = path.join(baseOutDir, `${safeHost(host)}_${ts}`);
616
+ await fsp.mkdir(outDir, { recursive: true });
617
+
602
618
  // EE enrichment hook — no-op if @nsasoft/nsauditor-ai-ee is not installed
619
+ // or the license tier doesn't grant intelligenceEngine. Compliance + outDir
620
+ // are forwarded so EE can write scan_finding_queue.json and SOC 2 artifacts.
603
621
  try {
604
622
  const { enrichScan } = await import('@nsasoft/nsauditor-ai-ee');
605
- const eeEnrichment = await enrichScan(conclusion, { host });
623
+ const eeEnrichment = await enrichScan(conclusion, {
624
+ host,
625
+ outDir,
626
+ compliance: opts.compliance ?? process.env.COMPLIANCE_FRAMEWORKS ?? null,
627
+ complianceScope: opts.complianceScope ?? null,
628
+ onWarn: (msg) => console.warn(`[EE] ${msg}`),
629
+ });
606
630
  if (eeEnrichment?.enrichedPrompt) {
607
631
  conclusion.result = conclusion.result || {};
608
632
  conclusion.result.eeEnrichment = eeEnrichment;
609
633
  }
610
634
  } catch { /* EE not installed — CE proceeds unchanged */ }
611
635
 
612
- const { file_paths: ai_file_paths, ai_conclusion } = await maybeSendToOpenAI({ host, results, conclusion, promptMode });
636
+ const { file_paths: ai_file_paths, ai_conclusion } = await maybeSendToOpenAI({ host, results, conclusion, promptMode, outDir });
613
637
 
614
638
  // --- Scan history: record & compare ---
615
639
  let scanDiff = null;
@@ -724,7 +748,7 @@ function maxSeverityInConclusion(conclusion) {
724
748
  }
725
749
 
726
750
  async function main() {
727
- const { cmd, host, plugins, insecureHttps, hostFile, parallel, failOn, outputFormat, watch, intervalMinutes, webhookUrl, alertSeverity, ports } = await parseArgs(process.argv);
751
+ const { cmd, host, plugins, insecureHttps, hostFile, parallel, failOn, outputFormat, watch, intervalMinutes, webhookUrl, alertSeverity, ports, compliance, complianceScope } = await parseArgs(process.argv);
728
752
 
729
753
  // Verify license JWT at startup (~5ms for ES256). Populates _verifiedTier
730
754
  // so all subsequent getTierFromEnv() calls return the cryptographically
@@ -844,6 +868,8 @@ async function main() {
844
868
 
845
869
  const opts = { insecureHttps };
846
870
  if (ports) opts.ports = ports;
871
+ if (compliance) opts.compliance = compliance;
872
+ if (complianceScope) opts.complianceScope = complianceScope;
847
873
  const pm = await PluginManager.create(`${__dirname}/plugins`);
848
874
  const promptMode = String(process.env.OPENAI_PROMPT_MODE || 'basic').toLowerCase().trim();
849
875
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nsauditor-ai",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "Modular AI-assisted network security audit platform — Community Edition",
5
5
  "type": "module",
6
6
  "private": false,