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.
- package/cli.mjs +42 -16
- 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
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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, {
|
|
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
|
|