nsauditor-ai 0.2.2 → 0.2.3
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 +1 -1
- package/mcp_server.mjs +1 -1
- package/package.json +1 -1
- package/utils/cloud_finding_summary.mjs +12 -3
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ NSAuditor AI is the open-source core of a privacy-first security intelligence pl
|
|
|
17
17
|
|
|
18
18
|
## What's New
|
|
19
19
|
|
|
20
|
-
**Latest: CE 0.2.
|
|
20
|
+
**Latest: CE 0.2.3 + Enterprise 0.18.2** (June 2026) — the MCP `scan_cloud` summary now **surfaces evidence-gaps**: a dedicated "Evidence gaps (unverified)" section so a Claude Desktop auditor sees the no-false-clean "we couldn't verify this" disclosures instead of a silent LOW count. Paired with **EE 0.18.2**, which retrofits the AWS S3 / Azure / IAM plugins to mark their scan-coverage gaps via a new CI producer-contract (so they reach the collector across all three clouds). Plugin count UNCHANGED at 28; all six coverage matrices UNCHANGED.
|
|
21
21
|
|
|
22
22
|
→ Full release history: **[CHANGELOG.md](./CHANGELOG.md)**
|
|
23
23
|
→ See a sample EE scan output: **[walk-through with synthetic Acme Corp AWS account](https://www.nsauditor.com/ai/docs/sample-scan/)** (no signup required)
|
package/mcp_server.mjs
CHANGED
|
@@ -216,7 +216,7 @@ const TOOLS = [
|
|
|
216
216
|
{
|
|
217
217
|
name: 'scan_cloud',
|
|
218
218
|
description:
|
|
219
|
-
'Audit one or more cloud accounts (AWS / GCP / Azure) for security & compliance posture using the credentials configured in the server environment. No network host required. Requires an Enterprise license. Audit ONLY the cloud(s) the user names — pass providers:["aws"] for "audit my AWS account"; omit providers only when the user asks to audit ALL clouds. Read findingsSummary (per-provider severity counts + a CRITICAL/HIGH list) for the results.',
|
|
219
|
+
'Audit one or more cloud accounts (AWS / GCP / Azure) for security & compliance posture using the credentials configured in the server environment. No network host required. Requires an Enterprise license. Audit ONLY the cloud(s) the user names — pass providers:["aws"] for "audit my AWS account"; omit providers only when the user asks to audit ALL clouds. Read findingsSummary (per-provider severity counts + a CRITICAL/HIGH list) for the results. findingsSummary[provider].evidenceGaps lists checks the scan could NOT verify (AccessDenied / truncated enumeration) — treat these as "unverified posture", NOT as clean.',
|
|
220
220
|
inputSchema: {
|
|
221
221
|
type: 'object',
|
|
222
222
|
properties: {
|
package/package.json
CHANGED
|
@@ -35,8 +35,11 @@ function findingsOf(r) {
|
|
|
35
35
|
/**
|
|
36
36
|
* @param {Array} results out.results (each {id, result:{findings|data}})
|
|
37
37
|
* @param {(id:any)=>string|null} providerOf plugin id -> cloudProvider
|
|
38
|
-
* @param {number} [cap] max CRITICAL/HIGH entries listed per provider
|
|
39
|
-
* @returns {Object} { [provider]: { counts:{SEV:n}, findings:[{severity,plugin,title}], truncated:boolean
|
|
38
|
+
* @param {number} [cap] max CRITICAL/HIGH entries listed per provider (also caps evidenceGaps independently)
|
|
39
|
+
* @returns {Object} { [provider]: { counts:{SEV:n}, findings:[{severity,plugin,title}], truncated:boolean,
|
|
40
|
+
* evidenceGaps:[{severity,plugin,title}], evidenceGapsTruncated?:boolean } }
|
|
41
|
+
* evidenceGaps surfaces findings carrying `details.evidenceGap === true` (the no-false-clean
|
|
42
|
+
* "could not verify" disclosures) REGARDLESS of severity, so a LOW/INFO gap is never invisible.
|
|
40
43
|
*/
|
|
41
44
|
export function summarizeCloudFindings(results, providerOf, cap = Number(process.env.CLOUD_FINDINGS_CAP) || 60) {
|
|
42
45
|
const out = {};
|
|
@@ -59,13 +62,16 @@ export function summarizeCloudFindings(results, providerOf, cap = Number(process
|
|
|
59
62
|
// bucketed under 'unknown' rather than silently dropped (defense-in-depth against a
|
|
60
63
|
// future id collision / cloudProvider drift — never let a real finding vanish).
|
|
61
64
|
const prov = providerOf(r?.id ?? r?.result?.id) || UNKNOWN_PROVIDER;
|
|
62
|
-
const bucket = (out[prov] ||= { counts: {}, findings: [], truncated: false });
|
|
65
|
+
const bucket = (out[prov] ||= { counts: {}, findings: [], evidenceGaps: [], truncated: false });
|
|
63
66
|
for (const x of found) {
|
|
64
67
|
const sev = String(x?.severity || x?.level || 'INFO').toUpperCase();
|
|
65
68
|
bucket.counts[sev] = (bucket.counts[sev] || 0) + 1;
|
|
66
69
|
if (sev === 'CRITICAL' || sev === 'HIGH') {
|
|
67
70
|
bucket.findings.push({ severity: sev, plugin: String(r?.id ?? ''), title: describeFinding(x) });
|
|
68
71
|
}
|
|
72
|
+
if (x && typeof x === 'object' && x.details && x.details.evidenceGap === true) {
|
|
73
|
+
bucket.evidenceGaps.push({ severity: sev, plugin: String(r?.id ?? ''), title: describeFinding(x) });
|
|
74
|
+
}
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
// Sort by severity (CRITICAL first) THEN truncate — so a CRITICAL is never evicted
|
|
@@ -75,6 +81,7 @@ export function summarizeCloudFindings(results, providerOf, cap = Number(process
|
|
|
75
81
|
const b = out[prov];
|
|
76
82
|
b.findings.sort((a, c) => (RANK[c.severity] || 0) - (RANK[a.severity] || 0));
|
|
77
83
|
if (b.findings.length > cap) { b.truncated = true; b.findings = b.findings.slice(0, cap); }
|
|
84
|
+
if (b.evidenceGaps.length > cap) { b.evidenceGapsTruncated = true; b.evidenceGaps = b.evidenceGaps.slice(0, cap); }
|
|
78
85
|
}
|
|
79
86
|
return out;
|
|
80
87
|
}
|
|
@@ -119,6 +126,8 @@ export function renderCloudFindingsMarkdown(summary, providers) {
|
|
|
119
126
|
lines.push(`## ${String(prov).toUpperCase()} — ${c.CRITICAL || 0} CRITICAL · ${c.HIGH || 0} HIGH · ${c.MEDIUM || 0} MEDIUM · ${c.LOW || 0} LOW · ${c.PASS || 0} PASS`);
|
|
120
127
|
for (const f of (b.findings || [])) lines.push(`- **[${f.severity}]** ${f.plugin}: ${f.title}`);
|
|
121
128
|
if (b.truncated) lines.push(`- _…CRITICAL/HIGH list truncated; see counts above for totals._`);
|
|
129
|
+
for (const g of (b.evidenceGaps || [])) lines.push(`- **[⚠ EVIDENCE GAP — unverified]** ${g.plugin}: ${g.title}`);
|
|
130
|
+
if (b.evidenceGapsTruncated) lines.push(`- _…evidence-gap list truncated; see LOW count for totals._`);
|
|
122
131
|
lines.push('');
|
|
123
132
|
}
|
|
124
133
|
// Append the incomplete-coverage advisory (when present) as an informational note.
|