nsauditor-ai 0.2.50 → 0.2.52

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 CHANGED
@@ -7,7 +7,7 @@ A modular, AI-assisted network security audit platform that scans, understands,
7
7
  [![npm](https://img.shields.io/npm/v/nsauditor-ai.svg)](https://www.npmjs.com/package/nsauditor-ai)
8
8
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
9
  [![Node.js 20+](https://img.shields.io/badge/node-20%2B-green.svg)](https://nodejs.org)
10
- [![Tests](https://img.shields.io/badge/tests-1308%20passing-brightgreen.svg)](#tests)
10
+ [![Tests](https://img.shields.io/badge/tests-1582%20passing-brightgreen.svg)](#tests)
11
11
 
12
12
  ---
13
13
 
@@ -17,6 +17,36 @@ 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.52 + Enterprise 0.45.0 — the Enterprise NTP clock attestation is WITHDRAWN.** The probe
21
+ is deleted: it validated any reply of at least 48 bytes with a non-null transmit timestamp and nothing
22
+ else — no mode byte, no stratum, no originate echo — so over unauthenticated UDP a datagram of the right
23
+ shape produced a false clean reading, and it measured the SCANNER's own clock rather than your estate.
24
+ It had never been reachable from any shipped entry point.
25
+ RFC 3161 trusted timestamping is untouched, opt-in, and is the capability that answers the question —
26
+ off unless you configure a Time-Stamp Authority, and an outbound call to a third party when you do. On the Community side this cycle changes no behaviour: the
27
+ withdrawn-claim guard over `license --capabilities` descriptions learns the wording the product actually
28
+ published, so the class cannot recur silently here. See [CHANGELOG.md](./CHANGELOG.md).
29
+
30
+ **The Pro `report` subcommand, over a run record that states its own coverage (CE 0.2.51 / Enterprise 0.44.0).**
31
+ `nsauditor-ai report --from <dir> --format executive|jira` turns a completed scan run into a
32
+ client-facing deliverable — a self-contained, print-ready HTML report a consultant sends to their
33
+ customer, or a Jira-importer CSV. Beneath it is a **per-run scan record**: written at run start,
34
+ appended per host, finalized at the end, so the report's cover **states** what was covered — hosts
35
+ requested, written and reachable, and the exploit-intelligence as-of dates read from the store's own
36
+ metadata — instead of implying completeness. An incomplete run says so on the cover; `--allow-partial`
37
+ renders it anyway with the caveat visible, never hidden. Two limits are shipped as text rather than
38
+ left to be discovered: the **Jira import mapping has not been verified against a live Jira instance**,
39
+ and a value-less `--from`/`--brand`/`--run`/`--out` is a **fatal error, not a silent default**. On the
40
+ Enterprise side the same cycle stops reporting an S3 audit-trail gap on a bucket whose object-level
41
+ reads and writes a CloudTrail data-event trail already records. See the
42
+ [`report` command section](#report-command-pro) and the [CHANGELOG](./CHANGELOG.md).
43
+ ⚠️ **The Enterprise peer floor stays `>=0.2.49` — it is NOT raised to 0.2.51.** Raising it would charge
44
+ every Enterprise operator an upgrade for a Community feature they may not want. The consequence is
45
+ worth stating rather than discovering: an Enterprise 0.44.0 install resolves cleanly against Community
46
+ 0.2.49 or 0.2.50 and simply has **no `report` command**. Install Community 0.2.51 to get it.
47
+ Every scan now also writes `scan_run_<runId>.json` at the root of `--out` — the record the report is
48
+ built from. On the free tier these are pruned after a retention window; on Pro they are kept.
49
+
20
50
  **A provider badge you can trust, and an evidence gap that never tells an auditor what to type (CE 0.2.50 / Enterprise 0.43.0).**
21
51
  **No Community behaviour changed this cycle** — the version moves so the trio stays in lockstep, and **the Enterprise peer floor stays `>=0.2.49`** rather than being raised reflexively, because the
22
52
  one Community behaviour the Enterprise fix depends on already shipped there. What changed is on the
@@ -120,7 +150,7 @@ Scan → Analyze → Prioritize → Track → Act
120
150
  - **Smart result fusion** — the Result Concluder merges all plugin outputs into a normalized view with OS detection, service fingerprinting, and evidence linking
121
151
  - **Structured finding format** — all findings use a common schema with category, severity, evidence, and remediation — enabling consistent SARIF export and MCP integration
122
152
  - **AI-powered analysis** — send redacted scan results to OpenAI or Claude (your keys, your choice) for vulnerability assessments and remediation guidance
123
- - **Risk-scored prioritization (Pro)** — findings carry a composite risk score (CVSS weighted by verification status, with an uplift for initial-access techniques) and a status field, and an operator suppression workflow (accepted-risk / false-positive with expiry) keeps triaged findings out of the report until they expire
153
+ - **Risk-scored prioritization (Pro/Enterprise)** — findings carry a composite risk score (CVSS weighted by verification status, with an uplift for initial-access techniques) and a status field, and an operator suppression workflow (accepted-risk / false-positive with expiry) keeps triaged findings out of the report until they expire
124
154
  - **Continuous monitoring (CTEM)** — watch mode rescans on a schedule, diffs against previous results, and fires webhook alerts on changes
125
155
  - **MCP integration** — expose scanning tools to AI assistants like Claude Code via Model Context Protocol
126
156
  - **CI/CD ready** — SARIF output with `--fail-on` severity gating for pipeline integration
@@ -172,11 +202,12 @@ How Marketplace fulfillment works (ZDE and air-gap preserved — no runtime AWS
172
202
  | AI analysis (OpenAI, Claude, Ollama — your keys) | ✅ basic | ✅ enriched | ✅ enriched |
173
203
  | Structured findings + SARIF + CSV export | ✅ | ✅ | ✅ |
174
204
  | CTEM watch mode | ✅ basic | ✅ advanced | ✅ advanced |
175
- | **Pro features (vulnerability assessment)** | | | |
205
+ | **Pro features** | | | |
176
206
  | CVE matching + MITRE ATT&CK mapping | — | ✅ | ✅ |
177
207
  | Risk scoring + prioritization | — | ✅ | ✅ |
178
208
  | Exploit intelligence — **CISA KEV** + **FIRST EPSS** joined onto the CVE matches, exploit-first ordering (a KEV-listed MEDIUM outranks an unexploited CRITICAL); stores are operator-populated — no feed data ships | — | ✅ | ✅ |
179
209
  | Parallel analysis agents | — | ✅ | ✅ |
210
+ | **Client reporting** — `report --format executive` renders a completed run as a self-contained, print-ready HTML report with optional cover-page branding (`--brand`); `--format jira` writes a Jira-importer CSV. ⚠️ The Jira import mapping is done in Jira and has **not been verified against a live Jira instance**. | — | ✅ | ✅ |
180
211
  | **Enterprise — cloud scanning** | | | |
181
212
  | 29 enterprise plugins — 28 cloud (AWS / Azure / GCP) + 1 network-scan zero-trust check | — | — | ✅ |
182
213
  | Zero Trust assessment | — | — | ✅ |
@@ -761,6 +792,7 @@ nsauditor-ai validate
761
792
  nsauditor-ai feed bundle --from <dir-of-NVD-feeds> --out <bundle.json.gz> [--kev <f>] [--epss <f>]
762
793
  nsauditor-ai feed import --file <feed-or-bundle> [--cache-dir <d>] [--extras-dir <d>] [--append] # the feeds you downloaded
763
794
  nsauditor-ai compliance <attest|suppress|review|renew|keygen|sign-pack|verify-pack> (Enterprise)
795
+ nsauditor-ai report --from <dir> --format executive|jira [--run <id>] [--brand <brand.json>] [--out <path>] [--allow-partial] (Pro/Enterprise)
764
796
  nsauditor-ai mcp
765
797
  nsauditor-ai --help (or -h, or `help`)
766
798
  nsauditor-ai --version (or -v, or `version`)
@@ -854,6 +886,82 @@ HEALTHCHECK --interval=60s --timeout=5s --start-period=10s --retries=3 \
854
886
  CMD nsauditor-ai validate --json | grep -q '"overall": "ok"' || exit 1
855
887
  ```
856
888
 
889
+ ### `report` command (Pro/Enterprise)
890
+
891
+ `nsauditor-ai report --from <dir> --format executive|jira` turns a completed scan run under `--from` into a client-facing deliverable — an HTML report a consultant sends to their customer, or a Jira-importer CSV.
892
+
893
+ **What it reads.** A scan record keeps findings in more than one place, and the report reads all of them: each plugin's `result.findings` (an array, or a dict of categories as the DNS auditor emits), zero-trust dimension findings, per-port TLS issues, and the **finding queue** (`scan_finding_queue.json`) that carries the CVE/KEV/EPSS-enriched entries. `result.data` is deliberately NOT read — on a network scan it holds probe telemetry, not findings. The container inventory is enforced by a census: a container holding findings that no reader opens fails the build rather than rendering as a clean report.
894
+
895
+ | Flag | Description | Default |
896
+ |---|---|---|
897
+ | `--from <dir>` | The scan `--out` directory holding the run's record and per-host evidence | *required* |
898
+ | `--format executive` | Self-contained, print-ready HTML report; no external network reference other than an `http(s)`/`mailto` `<a href>` | — |
899
+ | `--format jira` | Jira-importer CSV (`Summary`/`Description`/`Priority`/`Labels`/`External ID`); the import mapping is done in Jira and has not been verified against a live Jira instance. **`pass`-tier records are EXCLUDED** — a Jira issue is a work item and a passing check is not work; every other tier is kept, INFO included, because INFO carries the evidence gaps and scope boundaries. Passing checks appear in the `executive` report under their own **PASS** tier. | — |
900
+ | `--run <id>` | Report a specific run id instead of the newest one under `--from` | newest run |
901
+ | `--brand <brand.json>` | Cover-page branding (company name, prepared-by, contact, logo) — `--format executive` only | unbranded |
902
+ | `--out <path>` | Write to this path instead of `report_<runId>.<ext>` beside the run record | `report_<runId>.<ext>` |
903
+ | `--allow-partial` | Render even if some requested hosts were never written, or the run never recorded completion — the caveat is stated on the cover, never hidden | `false` |
904
+
905
+ A value-less `--from`/`--brand`/`--run`/`--out` (nothing after the flag, or a shell glob that swallowed the argument) is a fatal error, not a silent default.
906
+
907
+ **Exit contract** — `0` a report was rendered · `1` fix the RUN (no run record under `--from`, or an
908
+ incomplete run without `--allow-partial`) · `2` fix the REQUEST or its environment (an unknown or
909
+ missing flag value, an unwritable `--out`, a `--brand` file that is refused).
910
+
911
+ ⚠️ `--brand` with `--format jira` is **refused**, not ignored: a Jira CSV has nowhere to put branding,
912
+ and silently dropping a flag the caller passed is how a report goes out unbranded without anyone
913
+ noticing.
914
+
915
+ ```bash
916
+ nsauditor-ai report --from out/2026-08-26 --format executive --brand brand.json --out report.html
917
+ nsauditor-ai report --from out/2026-08-26 --format jira
918
+ ```
919
+
920
+ #### The `brand.json` file
921
+
922
+ `--brand` takes a small JSON object. Every field is optional; omit the file entirely and the report
923
+ renders unbranded with the default title.
924
+
925
+ ```json
926
+ {
927
+ "title": "Q3 External Perimeter Review",
928
+ "companyName": "Acme Manufacturing GmbH",
929
+ "preparedBy": "J. Rivera, Security Consulting LLC",
930
+ "contact": "security@example.com",
931
+ "logoPath": "acme-logo.png"
932
+ }
933
+ ```
934
+
935
+ | field | type | default | notes |
936
+ |---|---|---|---|
937
+ | `title` | string | `Network Scan Report` | Replaces the report's headline. |
938
+ | `companyName` | string | *(empty)* | The client the report is prepared **for**. |
939
+ | `preparedBy` | string | *(empty)* | The consultant or firm preparing it. |
940
+ | `contact` | string | *(empty)* | Free text — an address, an email, a phone number. |
941
+ | `logoPath` | string | *(none)* | A **local** PNG or JPEG, resolved relative to the brand file's own directory. Embedded into the HTML as a data URI. |
942
+
943
+ **`logoPath` is deliberately restrictive, and each refusal protects the report's core promise —
944
+ that it opens with no external network reference of any kind:**
945
+
946
+ - **A URL is refused and never fetched.** A remote logo is egress at render time and a tracking
947
+ pixel every time your client opens the file.
948
+ - **A UNC share (`\\host\share\...`) is refused** for the same reason: it is a network reference.
949
+ - **SVG is refused.** SVG is markup and can carry a script, which would break the report's
950
+ no-script guarantee from inside the image. Use PNG or JPEG.
951
+ - **The path must stay inside the brand file's own directory** — `../` escapes are refused, checked
952
+ both as typed and again after symlinks are resolved.
953
+ - **2 MB maximum**, and the format is detected by **magic bytes, not by file extension** — renaming
954
+ `logo.svg` to `logo.png` does not get it past the check.
955
+ - **An empty string is read as "no logo"**, the same as omitting the key, so a generated
956
+ `brand.json` that emits `""` is not an error.
957
+
958
+ A brand file that cannot be read, is not valid JSON, is not a JSON object, or whose `logoPath` is
959
+ refused is a **fatal error** — the report is not written. A flag you passed is never silently
960
+ dropped, because that is how a report goes out unbranded without anyone noticing.
961
+
962
+ ⚠️ `--brand` applies to `--format executive` only. Passing it with `--format jira` is **refused**,
963
+ not ignored: a CSV has nowhere to put a cover page.
964
+
857
965
  ---
858
966
 
859
967
  ## Configuration
@@ -1138,7 +1246,7 @@ No license key? Everything in this repository works perfectly without one. The C
1138
1246
 
1139
1247
  ## Tests
1140
1248
 
1141
- Run all 1308 tests:
1249
+ Run all 1582 tests:
1142
1250
 
1143
1251
  ```bash
1144
1252
  npm test