@slicedearth/whoisleuth-cli 1.45.0 → 2.0.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.
Files changed (268) hide show
  1. package/DISCLOSURE +7 -3
  2. package/NOTICE +5 -4
  3. package/README.md +74 -124
  4. package/SECURITY.md +6 -3
  5. package/bin/whoisleuth.mjs +7 -4
  6. package/cli/archive-inspect.mjs +28 -10
  7. package/cli/arguments.mjs +450 -173
  8. package/cli/artifact-structure.mjs +2507 -0
  9. package/cli/artifact-verify.mjs +286 -64
  10. package/cli/bounded-json.mjs +1 -0
  11. package/cli/bulk-checkpoint.mjs +35 -23
  12. package/cli/bulk-command-runner.mjs +2 -5
  13. package/cli/bulk.mjs +9 -2
  14. package/cli/case-pack.mjs +435 -46
  15. package/cli/ci-report.mjs +6 -1
  16. package/cli/collection-preflight.mjs +2 -2
  17. package/cli/command-catalogue.mjs +12 -3
  18. package/cli/command-reference.mjs +948 -106
  19. package/cli/completion.mjs +504 -218
  20. package/cli/config-profile.mjs +13 -3
  21. package/cli/ct-event-intake.mjs +32 -2
  22. package/cli/discover.mjs +7 -1
  23. package/cli/discovery-observation-snapshot.mjs +24 -28
  24. package/cli/discovery-scan-command-runner.mjs +13 -14
  25. package/cli/discovery-scan.mjs +17 -3
  26. package/cli/discovery-snapshot.mjs +15 -7
  27. package/cli/discovery-workflow.mjs +2 -3
  28. package/cli/doctor.mjs +2 -2
  29. package/cli/domain-control-monitor.mjs +215 -36
  30. package/cli/domain-control-observations.mjs +34 -17
  31. package/cli/errors.mjs +8 -3
  32. package/cli/evidence-command-runner.mjs +17 -11
  33. package/cli/evidence-signing.mjs +68 -50
  34. package/cli/export-evidence.mjs +11 -4
  35. package/cli/external-observation-mapping.mjs +3 -3
  36. package/cli/formatters/html.mjs +3 -3
  37. package/cli/formatters/json.mjs +20 -32
  38. package/cli/formatters/terminal.mjs +586 -22
  39. package/cli/input.mjs +62 -0
  40. package/cli/interactive-launcher.mjs +226 -0
  41. package/cli/interchange-report.mjs +226 -0
  42. package/cli/investigation-manifest.mjs +16 -17
  43. package/cli/investigation-plan.mjs +167 -16
  44. package/cli/investigation-run.mjs +80 -24
  45. package/cli/local-mmdb-review.mjs +45 -14
  46. package/cli/lookalike-calibration.mjs +3 -1
  47. package/cli/lookup-brief.mjs +13 -8
  48. package/cli/lookup-browser.mjs +844 -0
  49. package/cli/lookup-command-runner.mjs +96 -33
  50. package/cli/lookup-diff.mjs +11 -2
  51. package/cli/lookup-plan.mjs +1 -0
  52. package/cli/mail-review.mjs +206 -94
  53. package/cli/manual.mjs +5 -5
  54. package/cli/network-command-runner.mjs +78 -0
  55. package/cli/offline-evidence-review.mjs +45 -14
  56. package/cli/open-asset-model-bridge.mjs +1 -1
  57. package/cli/output-file.mjs +70 -14
  58. package/cli/page-compare.mjs +18 -10
  59. package/cli/progress-events.mjs +2 -1
  60. package/cli/progress.mjs +3 -3
  61. package/cli/registry-cohort.mjs +343 -61
  62. package/cli/registry-doctor.mjs +67 -28
  63. package/cli/registry-support.mjs +2 -1
  64. package/cli/retained-artifact-diff.mjs +375 -0
  65. package/cli/risk-calibration.mjs +89 -40
  66. package/cli/runner.mjs +322 -246
  67. package/cli/saved-lookup.mjs +439 -49
  68. package/cli/sharing-review.mjs +18 -7
  69. package/cli/source-reliability.mjs +75 -36
  70. package/cli/terminal-presentation.mjs +43 -18
  71. package/docs/cli-reference.md +125 -1334
  72. package/docs/cli.md +87 -236
  73. package/frontend/src/lib/analysis/domain-control-manifest-core.js +3 -0
  74. package/frontend/src/lib/analysis/domain-control-records.js +3 -0
  75. package/lib/application-version.mjs +3 -0
  76. package/lib/availability.mjs +72 -52
  77. package/lib/bounded-contract-normalizers.mjs +2 -4
  78. package/lib/bounded-file.mjs +91 -4
  79. package/lib/bounded-json.mjs +287 -0
  80. package/lib/browser-library-profile.mjs +1 -1
  81. package/lib/certificate-extension-profile.mjs +2 -1
  82. package/lib/classify.mjs +56 -5
  83. package/lib/client-behavior-profile.mjs +1 -1
  84. package/lib/credential-surface-profile.mjs +1 -1
  85. package/lib/cryptographic-assurance.mjs +173 -0
  86. package/lib/ct-query.mjs +3 -3
  87. package/lib/ct-search.mjs +120 -64
  88. package/lib/distributed-operation-budget.mjs +4 -2
  89. package/lib/dns-delegation-health.mjs +9 -6
  90. package/lib/dns-intelligence.mjs +4 -3
  91. package/lib/dns-resolver-selection.mjs +6 -4
  92. package/lib/dnssec-chain-validation.mjs +1052 -0
  93. package/lib/dnssec-evidence-validation.mjs +23 -10
  94. package/lib/domain-assurance.mjs +12 -12
  95. package/lib/domain-change-packet.mjs +7 -5
  96. package/lib/domain-control-flight-recorder.mjs +442 -78
  97. package/lib/domain-control-manifest.mjs +314 -171
  98. package/lib/domain-posture-analysis.mjs +5 -2
  99. package/lib/domain-posture.mjs +7 -4
  100. package/lib/encrypted-dns-contract.mjs +2 -3
  101. package/lib/evidence-export.mjs +1243 -88
  102. package/lib/evidence-report-markdown.mjs +3 -0
  103. package/lib/evidence-report.mjs +5 -0
  104. package/lib/external-intelligence-risk.mjs +26 -10
  105. package/lib/favicon.mjs +8 -5
  106. package/lib/feature-policy.mjs +1 -1
  107. package/lib/homepage-metadata-contract.mjs +290 -0
  108. package/lib/hostname.mjs +1 -1
  109. package/lib/html-signals.mjs +89 -5
  110. package/lib/http-evidence-bounds.mjs +3 -0
  111. package/lib/http-intelligence.mjs +332 -6
  112. package/lib/interchange-fidelity-registry.mjs +124 -0
  113. package/lib/local-geoip-evidence.mjs +2 -1
  114. package/lib/lookup-cache.mjs +6 -4
  115. package/lib/lookup-network-evidence-bounds.mjs +9 -0
  116. package/lib/lookup.mjs +27 -4
  117. package/lib/observed-network-context.mjs +1 -1
  118. package/lib/outbound-identity.mjs +2 -3
  119. package/lib/page-fingerprints.mjs +2 -2
  120. package/lib/page-role-profile.mjs +1 -1
  121. package/lib/perceptual-hash.mjs +12 -4
  122. package/lib/portable-generator.mjs +29 -0
  123. package/lib/provider-policy-admission.mjs +11 -4
  124. package/lib/rdap-bootstrap.mjs +76 -16
  125. package/lib/rdap-client.mjs +20 -12
  126. package/lib/rdap-normalization.mjs +324 -80
  127. package/lib/rdap-registrar.mjs +5 -1
  128. package/lib/rdap-transport.mjs +2 -2
  129. package/lib/rdap-validation.mjs +65 -14
  130. package/lib/rdap.mjs +2 -2
  131. package/lib/registrable-domain.mjs +36 -0
  132. package/lib/registry-capabilities.mjs +3 -0
  133. package/lib/registry-capability-catalogue.mjs +12 -2
  134. package/lib/registry-comparison.mjs +28 -11
  135. package/lib/registry-insights.mjs +7 -0
  136. package/lib/response-policy.mjs +27 -4
  137. package/lib/risk-calibration-summary.mjs +340 -0
  138. package/lib/risk-scoring.mjs +4 -3
  139. package/lib/rpki-evidence.mjs +9 -8
  140. package/lib/safe-fetch.mjs +121 -50
  141. package/lib/security-txt.mjs +27 -4
  142. package/lib/service-binding-dns.mjs +6 -1
  143. package/lib/smtp-transport-review.mjs +787 -0
  144. package/lib/sslbl-certificates.generated.mjs +136 -134
  145. package/lib/sslbl-intelligence.mjs +6 -8
  146. package/lib/static-html-analysis.mjs +301 -4
  147. package/lib/structured-data-identity.mjs +51 -19
  148. package/lib/threat-intelligence-fixtures.mjs +2 -4
  149. package/lib/threat-intelligence-manifests.mjs +2 -7
  150. package/lib/threat-intelligence-runtime.mjs +5 -15
  151. package/lib/threat-intelligence-types.mjs +21 -1
  152. package/lib/threatfox-intelligence.mjs +7 -3
  153. package/lib/tls-intelligence.mjs +15 -9
  154. package/lib/tlsa-evidence.mjs +37 -7
  155. package/lib/urlhaus-intelligence.mjs +4 -2
  156. package/lib/urlscan-intelligence.mjs +6 -5
  157. package/lib/website-security-posture.mjs +1 -1
  158. package/lib/website-technology.mjs +1 -1
  159. package/lib/whois-authority.mjs +43 -8
  160. package/lib/whois-chain.mjs +25 -3
  161. package/lib/whois-normalization.mjs +3 -1
  162. package/lib/whois-transport.mjs +12 -3
  163. package/lib/zone-intent-review.mjs +1 -1
  164. package/package.json +12 -4
  165. package/packages/cases/case-brand-profile-references.mjs +85 -0
  166. package/{frontend/src/lib/analysis/case-evidence-model.js → packages/cases/case-evidence-model.mjs} +43 -14
  167. package/packages/cases/case-investigation-branch-model.mjs +132 -0
  168. package/packages/cases/case-migration-model.mjs +476 -0
  169. package/{frontend/src/lib/analysis/case-model.js → packages/cases/case-model.mjs} +3 -3
  170. package/{frontend/src/lib/analysis/case-record-contracts.js → packages/cases/case-record-contracts.mjs} +3 -19
  171. package/{frontend/src/lib/analysis/case-record-core.js → packages/cases/case-record-core.mjs} +58 -31
  172. package/packages/cases/case-record-model.mjs +9 -0
  173. package/{frontend/src/lib/analysis/case-record-operations.js → packages/cases/case-record-operations.mjs} +106 -33
  174. package/{frontend/src/lib/analysis/case-report.js → packages/cases/case-report.mjs} +143 -16
  175. package/packages/cases/case-response-model.mjs +1604 -0
  176. package/packages/cases/case-response-packet.mjs +1312 -0
  177. package/{frontend/src/lib/analysis/case-storage-model.js → packages/cases/case-storage-model.mjs} +2 -2
  178. package/{frontend/src/lib/analysis/http-summary.js → packages/cases/http-summary.mjs} +1 -1
  179. package/packages/cases/opaque-reference-id.mjs +9 -0
  180. package/packages/comparison/comparison-ledger-bulk.mjs +366 -0
  181. package/packages/comparison/comparison-ledger-contract.mjs +241 -0
  182. package/packages/comparison/comparison-ledger-json.mjs +80 -0
  183. package/packages/comparison/comparison-ledger-serialization.mjs +52 -0
  184. package/packages/comparison/favicon-similarity.mjs +78 -0
  185. package/{frontend/src/lib/analysis/page-similarity.js → packages/comparison/page-similarity.mjs} +4 -3
  186. package/{frontend/src/lib/analysis/relationship-evidence.js → packages/comparison/relationship-evidence.mjs} +6 -7
  187. package/packages/contracts/analyst-review-state-contract.mjs +61 -0
  188. package/packages/contracts/analyst-review-state.mjs +50 -0
  189. package/packages/contracts/case-portability.mjs +1310 -0
  190. package/packages/contracts/cli-command-catalogue.mjs +2 -0
  191. package/packages/contracts/cli-lookup.mjs +394 -0
  192. package/packages/contracts/domain-control-flight-recorder.mjs +461 -0
  193. package/packages/contracts/domain-control-manifest.mjs +1027 -0
  194. package/packages/contracts/domain-control-monitor.mjs +310 -0
  195. package/packages/contracts/domain-control-review.mjs +828 -0
  196. package/packages/contracts/domain-name.mjs +4 -0
  197. package/packages/contracts/external-observation-interchange.mjs +224 -0
  198. package/packages/contracts/extracted-domain-lifecycle.mjs +218 -0
  199. package/packages/contracts/investigation-portability.mjs +331 -0
  200. package/packages/contracts/offline-comparison.mjs +160 -0
  201. package/packages/contracts/risk-calibration.mjs +1288 -0
  202. package/packages/contracts/schema-compatibility.mjs +71 -0
  203. package/packages/contracts/schema-lifecycle.mjs +1702 -0
  204. package/packages/contracts/sslbl-snapshot.mjs +17 -0
  205. package/packages/contracts/workspace-portability.mjs +1347 -0
  206. package/packages/evidence/artifact-integrity.mjs +65 -0
  207. package/packages/evidence/decision-fact.mjs +735 -0
  208. package/packages/evidence/domain-control-runtime.mjs +547 -0
  209. package/packages/evidence/domain-name.mjs +41 -0
  210. package/packages/evidence/observation.mjs +384 -0
  211. package/{frontend/src/lib/analysis/external-findings-import.js → packages/interchange/external-findings-import.mjs} +86 -20
  212. package/packages/interchange/retained-text.mjs +8 -0
  213. package/{frontend/src/lib/analysis/acquisition-decision-packet.js → packages/investigation/acquisition-decision-packet.mjs} +11 -8
  214. package/{frontend/src/lib/analysis/bulk-domain-comparison.js → packages/investigation/bulk-domain-comparison.mjs} +28 -9
  215. package/{frontend/src/lib/analysis/bulk-mail-exposure.js → packages/investigation/bulk-mail-exposure.mjs} +67 -18
  216. package/{frontend/src/lib/analysis/bulk-review-export.js → packages/investigation/bulk-review-export.mjs} +10 -9
  217. package/packages/investigation/bulk-review-policy.mjs +1 -0
  218. package/{frontend/src/lib/analysis/investigation-capsule.js → packages/investigation/investigation-capsule.mjs} +50 -18
  219. package/packages/investigation/lookup-artefact-inputs.mjs +1 -0
  220. package/{frontend/src/lib/analysis/lookup-asset-graph.js → packages/investigation/lookup-asset-graph.mjs} +4 -2
  221. package/packages/investigation/lookup-claim-passport.mjs +232 -0
  222. package/packages/investigation/lookup-claim-readiness.mjs +287 -0
  223. package/packages/investigation/lookup-investigation-brief.mjs +172 -0
  224. package/packages/monitoring/analyst-review-state.mjs +680 -0
  225. package/{frontend/src/lib/analysis/brand-profile-model.js → packages/workspace/brand-profile-model.mjs} +97 -50
  226. package/{frontend/src/lib/analysis/bulk-review-model.js → packages/workspace/bulk-review-model.mjs} +15 -15
  227. package/{frontend/src/lib/analysis/bulk-session-model.js → packages/workspace/bulk-session-model.mjs} +179 -39
  228. package/{frontend/src/lib/analysis/bulk-sort.js → packages/workspace/bulk-sort.mjs} +12 -5
  229. package/{frontend/src/lib/analysis/campaign-model.js → packages/workspace/campaign-model.mjs} +20 -22
  230. package/{frontend/src/lib/analysis/detection-rule-model.js → packages/workspace/detection-rule-model.mjs} +15 -17
  231. package/packages/workspace/hostile-input.mjs +172 -0
  232. package/{frontend/src/lib/analysis/investigation-guide.js → packages/workspace/investigation-guide.mjs} +51 -46
  233. package/{frontend/src/lib/analysis/investigation-template-model.js → packages/workspace/investigation-template-model.mjs} +15 -15
  234. package/{frontend/src/lib/analysis/page-baseline.js → packages/workspace/page-baseline.mjs} +6 -13
  235. package/{frontend/src/lib/analysis/relationship-observation-model.js → packages/workspace/relationship-observation-model.mjs} +13 -17
  236. package/{frontend/src/lib/analysis/shortlist-model.js → packages/workspace/shortlist-model.mjs} +20 -18
  237. package/{frontend/src/lib/analysis/watchlist-history.js → packages/workspace/watchlist-history.mjs} +9 -16
  238. package/{frontend/src/lib/analysis/watchlist-store.js → packages/workspace/watchlist-store.mjs} +24 -17
  239. package/{frontend/src/lib/analysis/website-snapshot-model.js → packages/workspace/website-snapshot-model.mjs} +18 -12
  240. package/{frontend/src/lib/analysis/workspace-archive-crypto.js → packages/workspace/workspace-archive-crypto.mjs} +49 -19
  241. package/{frontend/src/lib/analysis/workspace-archive.js → packages/workspace/workspace-archive.mjs} +195 -84
  242. package/third-party-notices.txt +112 -5834
  243. package/frontend/src/lib/analysis/artifact-integrity.js +0 -21
  244. package/frontend/src/lib/analysis/bulk-retry-plan.js +0 -79
  245. package/frontend/src/lib/analysis/bulk-source-coverage.js +0 -76
  246. package/frontend/src/lib/analysis/case-migration-model.js +0 -253
  247. package/frontend/src/lib/analysis/case-record-model.js +0 -7
  248. package/frontend/src/lib/analysis/case-response-model.js +0 -669
  249. package/frontend/src/lib/analysis/case-response-packet.js +0 -573
  250. package/frontend/src/lib/analysis/lookup-decision-support.js +0 -487
  251. package/frontend/src/lib/analysis/lookup-investigation-brief.js +0 -153
  252. package/frontend/src/lib/analysis/lookup-presentation.js +0 -58
  253. package/frontend/src/lib/analysis/lookup-response.js +0 -2
  254. package/frontend/src/lib/analysis/lookup-source-refresh.js +0 -277
  255. package/frontend/src/lib/analysis/lookup-summary-model.js +0 -398
  256. package/frontend/src/lib/analysis/scoring.js +0 -55
  257. package/frontend/src/lib/analysis/utils.js +0 -232
  258. package/frontend/src/lib/analysis/visualization-bounds.js +0 -26
  259. package/frontend/src/lib/analysis/visualization-force-graph.js +0 -352
  260. package/frontend/src/lib/analysis/visualization-matrix.js +0 -88
  261. package/frontend/src/lib/analysis/visualization-models.js +0 -369
  262. package/frontend/src/lib/analysis/visualization-time-series.js +0 -144
  263. package/lib/bounded-json-response.mjs +0 -157
  264. package/lib/lookup-response-contract.mjs +0 -346
  265. package/lib/observation.mjs +0 -114
  266. /package/{frontend/src/lib/analysis/acquisition-due-diligence.js → packages/investigation/acquisition-due-diligence.mjs} +0 -0
  267. /package/{frontend/src/lib/analysis/evidence-coverage-ledger.js → packages/investigation/evidence-coverage-ledger.mjs} +0 -0
  268. /package/{frontend/src/lib/analysis/dns-record-normalization.js → packages/workspace/dns-record-normalization.mjs} +0 -0
@@ -1,25 +1,18 @@
1
1
  # WHOISleuth CLI reference
2
2
 
3
- This complete reference documents every supported command contract. For a
4
- short installation and first-use path, start with the [CLI guide](cli.md).
3
+ The WHOISleuth CLI runs locally. Installed `whoisleuth <command> --help`,
4
+ `whoisleuth commands` and `whoisleuth manual` are the exact grammar, option and
5
+ command authorities for that installed version. The public
6
+ [CLI reference](https://whoisleuth.com/cli) provides a searchable view generated
7
+ from the same registry.
5
8
 
6
- The first-party command-line interface runs the same local classification and
7
- lookup modules as the Express and serverless adapters. It does not call the
8
- hosted WHOISleuth deployment.
9
-
10
- `whoisleuth --help` displays the copyright, AGPL-3.0-only licence, and official
11
- source location. It groups commands by investigation, discovery, saved-evidence,
12
- integrity, and calibration workflows. `whoisleuth <command> --help` displays the
13
- command's purpose, focused invocation, example, and collection boundary without
14
- printing the full command list. `whoisleuth commands --json` exposes those same
15
- contracts as a stable local catalogue for wrappers and terminal tooling.
16
- Packaged copies include `LICENSE`, `NOTICE`, and
17
- `TRADEMARKS.md` alongside the CLI documentation.
9
+ This page records the common interfaces and the boundaries that matter across
10
+ commands. The generated [privacy/data-flow catalogue](https://github.com/slicedearth/whoisleuth/blob/main/docs/privacy-data-flow-catalogue.md)
11
+ contains the exhaustive recipient, retention and export metadata.
18
12
 
19
13
  ## Installation
20
14
 
21
- Public releases require Node.js 24 or later and install the `whoisleuth`
22
- command:
15
+ Public releases require Node.js 24 or later:
23
16
 
24
17
  ```bash
25
18
  npm exec --yes --ignore-scripts --package=@slicedearth/whoisleuth-cli -- whoisleuth --help
@@ -27,1329 +20,127 @@ npm install --global --ignore-scripts @slicedearth/whoisleuth-cli
27
20
  whoisleuth doctor
28
21
  ```
29
22
 
30
- Update and verify an existing global installation with:
31
-
32
- ```bash
33
- npm install --global --ignore-scripts @slicedearth/whoisleuth-cli@latest
34
- whoisleuth --version
35
- ```
36
-
37
- The scoped package and application share one semantic version. The package runs
38
- locally and does not call the hosted WHOISleuth deployment. Networked commands
39
- contact only the sources described by their collection profile; offline review,
40
- comparison, verification, completion, and manual commands remain local.
41
-
42
- ## Commands
23
+ The scoped package and application share one semantic version. The package
24
+ requires no dependency lifecycle scripts and does not call the hosted
25
+ WHOISleuth deployment. From a repository checkout, replace `whoisleuth` with
26
+ `node bin/whoisleuth.mts`.
43
27
 
44
- ```bash
45
- node bin/whoisleuth.mts lookup example.com
46
- node bin/whoisleuth.mts lookup AS13335 --json
47
- printf 'example.com\n' | node bin/whoisleuth.mts lookup --json
48
- node bin/whoisleuth.mts lookup example.com --deep
49
- node bin/whoisleuth.mts lookup example.com --deep --plan --json
50
- node bin/whoisleuth.mts lookup example.com --deep --summary
51
- node bin/whoisleuth.mts lookup example.com --deep --verbose
52
- node bin/whoisleuth.mts lookup example.com --deep --markdown --output lookup.md
53
- node bin/whoisleuth.mts lookup example.com --deep --json --strict-exit --events
54
- node bin/whoisleuth.mts lookup example.test --deep --observer workstation-a --vantage office-egress --json > office.json
55
- cat domains.txt | node bin/whoisleuth.mts bulk --jsonl
56
- node bin/whoisleuth.mts bulk domains.txt --csv --registered-only
57
- node bin/whoisleuth.mts bulk domains.txt --domains --inconclusive-only
58
- node bin/whoisleuth.mts bulk domains.txt --queries --errors-only
59
- node bin/whoisleuth.mts bulk domains.txt --concurrency 4
60
- node bin/whoisleuth.mts bulk domains.txt --deep --checkpoint bulk-checkpoint.json
61
- node bin/whoisleuth.mts bulk domains.txt --deep --checkpoint bulk-checkpoint.json --resume
62
- node bin/whoisleuth.mts ct-search 'example brand' --json
63
- node bin/whoisleuth.mts discover example.com --preset common --jsonl
64
- node bin/whoisleuth.mts discover example.test --dictionary private-terms.txt --snapshot discovery-state.json --json
65
- node bin/whoisleuth.mts discover-scan example.test --scan-limit 50 --checkpoint candidate-scan.json --json
66
- node bin/whoisleuth.mts discover-scan example.test --deep --scan-limit 20 --resolver 192.0.2.53 --observation-snapshot observed-candidates.json --csv
67
- node bin/whoisleuth.mts posture example.com --selectors selector1 --retired-selectors selector0 --mail-profile defensive-no-mail --json
68
- node bin/whoisleuth.mts http example.com --json
69
- node bin/whoisleuth.mts tls example.com --json
70
- node bin/whoisleuth.mts registry-support example.uk --json
71
- node bin/whoisleuth.mts registry-doctor lookup.json --json
72
- node bin/whoisleuth.mts registry-cohort saved-lookups.jsonl --json
73
- node bin/whoisleuth.mts registry-scaffold --profile example-profile --suffix test --scenario registered
74
- node bin/whoisleuth.mts risk-calibrate calibration.json --json
75
- node bin/whoisleuth.mts lookalike-calibrate reviewed-candidates.json --json
76
- node bin/whoisleuth.mts verify-artifact workspace.json --json
77
- node bin/whoisleuth.mts verify-artifact lookup.json --json
78
- node bin/whoisleuth.mts verify-artifact workspace-encrypted.json --passphrase-file passphrase.txt --json
79
- node bin/whoisleuth.mts source-report lookup.json --json
80
- node bin/whoisleuth.mts inspect-archive workspace.json --json
81
- node bin/whoisleuth.mts inspect-archive workspace.json --search example.invalid --json
82
- node bin/whoisleuth.mts sign-artifact response-packet.json --private-key-file analyst-private.pem > response-packet.signed.json
83
- node bin/whoisleuth.mts ct-intake certificate-events.json --json > external-findings.json
84
- node bin/whoisleuth.mts map-observations observation-mapping.json --json > external-findings.json
85
- node bin/whoisleuth.mts oam-export external-findings.json --json > asset-bridge.json
86
- node bin/whoisleuth.mts manifest lookup.json comparison.json --workflow 'domain review' --json > investigation-manifest.json
87
- node bin/whoisleuth.mts verify-signature response-packet.signed.json --public-key-file analyst-public.pem
88
- node bin/whoisleuth.mts lookup example.com --deep --json > lookup.json
89
- node bin/whoisleuth.mts compare lookup.json --json
90
- node bin/whoisleuth.mts page-compare official.json candidate.json --json
91
- node bin/whoisleuth.mts mail-review bulk.json --json
92
- node bin/whoisleuth.mts review-evidence dnssec-evidence.json --json
93
- node bin/whoisleuth.mts review-evidence trust-store-comparison.json --json
94
- node bin/whoisleuth.mts domain-control domain-control-input.json --json
95
- node bin/whoisleuth.mts assurance domain-assurance-input.json --json
96
- node bin/whoisleuth.mts change-packet domain-change-packet-input.json --json
97
- node bin/whoisleuth.mts sharing-review response-packet.json --marking amber --recipient-scope organization --purpose 'Reviewed incident handoff' --human-reviewed --personal-data-reviewed --redactions-confirmed --json
98
- node bin/whoisleuth.mts workflow-plan domain-triage example.test --json
99
- node bin/whoisleuth.mts workflow-run domain-triage example.test --approve-network --json --output run.json
100
- node bin/whoisleuth.mts brief lookup.json
101
- node bin/whoisleuth.mts case-pack cases.json --audience trusted --reviewed --json
102
- node bin/whoisleuth.mts monitor-once control-manifest.json --previous prior-control.json --junit
103
- node bin/whoisleuth.mts diff first-lookup.json second-lookup.json --json
104
- node bin/whoisleuth.mts reconcile office.json mobile.json external.json --json
105
- node bin/whoisleuth.mts timeline first-observation.json second-observation.json latest-observation.json --json
106
- node bin/whoisleuth.mts export lookup.json > evidence.json
107
- node bin/whoisleuth.mts export lookup.json --markdown > evidence.md
108
- node bin/whoisleuth.mts export lookup.json --html > evidence.html
109
- node bin/whoisleuth.mts doctor
110
- node bin/whoisleuth.mts doctor --network --json
111
- node bin/whoisleuth.mts commands --json
112
- node bin/whoisleuth.mts completion zsh
113
- node bin/whoisleuth.mts completion powershell
114
- node bin/whoisleuth.mts manual | man -l -
115
- ```
116
-
117
- These examples run from a checked-out repository; replace
118
- `node bin/whoisleuth.mts` with `whoisleuth` after installation. The root
119
- application package remains private. A separate scoped CLI archive is assembled
120
- from the exact executable dependency closure, installed in a temporary
121
- directory, and smoke tested with:
28
+ ## Find and inspect commands
122
29
 
123
30
  ```bash
124
- npm run cli:package:check
125
- ```
126
-
127
- The check includes only the executable, reachable TypeScript modules, CLI
128
- guide, licence, notices, and trademark terms. It excludes application routes,
129
- deployment adapters, tests, and development tools. Direct runtime dependencies
130
- are pinned to the exact versions exercised by the reviewed repository lockfile.
131
- The package and its dependencies require no lifecycle scripts, so the install
132
- examples disable them explicitly.
133
- Its generated manifest stays private. Release-candidate assembly is a separate
134
- explicit operation and never publishes from a developer checkout. Use the
135
- scoped package name; an unqualified `npx whoisleuth` is not this project.
136
-
137
- Lookup defaults to the conservative fast profile. `--deep` must be requested
138
- explicitly and can add bounded WHOIS, DNS, website, TLS, registrar RDAP, and
139
- observed-network IP RDAP work for a domain. The browser Console's optional
140
- security.txt and external intelligence selections are not CLI flags; the CLI
141
- does not run those actions implicitly.
142
-
143
- For a directly entered public IP address, `lookup --deep` can also run one
144
- bounded reverse-DNS query. Terminal output shows the explicit source state and
145
- up to five normalised PTR names; JSON retains up to eight. PTR names are
146
- operator-published routing context, not proof of hosting control or ownership.
147
- Fast lookups do not run this query.
148
-
149
- `lookup --plan` performs classification and prints a versioned preflight without
150
- starting collection. It lists the normalised target, selected fast or deep
151
- mode, planned source families, conditional operations, and the data each family
152
- may receive. The plan cannot predict live feature configuration, cache state,
153
- redirects, referrals, source availability, or an exact request count. It can be
154
- combined with `--json`, but not with report, detail, strict-exit, progress-event,
155
- or quiet options.
156
-
157
- Only one query is accepted by `lookup`. Multiple-input processing belongs to
158
- the explicit `bulk` command rather than being silently inferred by `lookup`.
159
- Standard input is capped at 4 KiB and must contain one non-empty line.
160
-
161
- `registry-support` is an offline catalogue view. It accepts one domain, bare
162
- suffix, or leading-dot suffix as an argument or on stdin and makes no network
163
- request. Its output is described below.
164
-
165
- `doctor` is offline by default. It checks the Node runtime, platform, terminal
166
- capabilities, and availability of offline command families. `doctor --network`
167
- adds independent bounded public-DNS, HTTPS/RDAP bootstrap, and WHOIS port 43
168
- checks against fixed IANA diagnostic infrastructure. The three probes run
169
- within the same per-probe ceiling so one stalled transport does not block the
170
- others. The report retains only state, HTTP status, and a bounded explanation,
171
- not resolved addresses or response content. A failed optional network check
172
- returns the partial-failure exit code rather than claiming that all CLI
173
- collection is unavailable.
174
-
175
- `completion bash`, `completion zsh`, `completion fish`, and `completion
176
- powershell` print static shell completion scripts to stdout. The command does
177
- not edit a shell profile or make a network request. Review the generated script
178
- before sourcing it or placing it in the relevant shell completion directory.
179
- `manual` prints a generated roff manual page and likewise changes no local
180
- configuration.
181
-
182
- `commands` prints the installed command catalogue without running collection or
183
- reading evidence. `commands --json` emits version 1 of the
184
- `whoisleuth.cli.command-catalogue` schema, including each command's usage,
185
- example, declared collection mode, collection scope, and boundary. This is the
186
- supported discovery contract for local wrappers; it is not a permission grant
187
- or a substitute for focused help.
188
-
189
- Focused command help and the generated manual classify every operation as
190
- offline or networked and state the relevant target, input, and concurrency
191
- ceiling. These labels describe observable behaviour rather than granting
192
- authorisation. The packaged `DISCLOSURE` defines the intended defensive scope;
193
- operators remain responsible for law, provider terms, and authorisation.
194
-
195
- ## Deployment boundary
196
-
197
- The CLI runs locally. The serverless deployment publishes only `frontend/build`
198
- and packages functions only from `netlify/functions`, so `bin/` and `cli/` are
199
- not part of the hosted static site or function bundle. The application root and
200
- ordinary package-check candidate remain private. Explicitly reviewed CLI
201
- release candidates can be published under the scoped public package described
202
- in the installation section.
203
-
204
- Commands that query RDAP, WHOIS, DNS, HTTP, TLS, or Certificate Transparency do
205
- so directly from the machine running the CLI. They do not use the hosted login,
206
- hosted session, or deployment usage controls; upstream providers can see and
207
- rate-limit the local machine's network address. Offline `discover`, `compare`,
208
- `page-compare`, `mail-review`, `review-evidence`, `domain-control`, `assurance`, `change-packet`,
209
- `sharing-review`, `workflow-plan`, `brief`, `case-pack`, `registry-cohort`,
210
- `registry-scaffold`, `diff`, `reconcile`, `timeline`,
211
- `risk-calibrate`, `lookalike-calibrate`, `registry-doctor`, `verify-artifact`, `source-report`,
212
- `map-observations`, `oam-export`, `export`,
213
- `commands`, `completion`, and `manual` operations make no network requests. Commands write
214
- to stdout unless the analyst deliberately selects a local output file.
215
-
216
- ## Output
217
-
218
- Human-readable terminal output is the default. On an interactive terminal it
219
- uses restrained semantic colour, groups Lookup evidence by purpose, wraps
220
- prose to the detected terminal width, and shows transient progress on stderr
221
- for slower collection. State remains explicit in text, so colour is never the
222
- only distinction. Redirected terminal output, JSON, and JSONL contain no ANSI
223
- sequences or progress text. `--no-color` and a non-empty conventional
224
- `NO_COLOR` environment variable disable colour; `WHOISLEUTH_NO_PROGRESS=1`
225
- disables the transient indicator. Command examples remain one copyable line
226
- even when prose is wrapped for a narrow terminal.
227
-
228
- Every command accepts `--output <file>` as a safer alternative to shell
229
- redirection. WHOISleuth buffers bounded output, creates a private temporary file
230
- beside the destination, syncs it, and publishes it atomically with mode `0600`.
231
- An existing destination is refused. `--force` is valid only with `--output` and
232
- allows an intentional atomic replacement. A failed or cancelled command does
233
- not publish a partial output file. Output is capped at 32 MiB.
234
-
235
- `--config <file> --profile <name>` reads a strict version-1 local configuration
236
- document of at most 64 KiB. Without `--config`, the path is
237
- `$XDG_CONFIG_HOME/whoisleuth/config.json`. A profile may contain no more than
238
- 16 safe defaults drawn from `--no-color`, `--summary`, `--verbose`, `--fast`,
239
- `--concurrency`, `--observer`, and `--vantage`. It cannot supply a target,
240
- Deep mode, output path, network approval, failure policy, credential, or
241
- arbitrary argument. Explicit command options override profile defaults from
242
- the same group.
243
-
244
- Lookup, Bulk, and `monitor-once` can emit bounded JUnit XML. Owned-domain
245
- Posture can emit SARIF only when `--owned-domain` confirms the passive target
246
- boundary. The reports contain categorical source or posture findings rather
247
- than raw evidence. Supported network commands accept an explicit comma-
248
- separated `--fail-on` policy from `source-failure`, `inconclusive`, `danger`,
249
- and `material-drift`; a match returns the partial-result exit code after the
250
- normal output is emitted.
251
-
252
- `lookup --markdown` and `lookup --html` build the existing normalised evidence
253
- report directly after one completed domain lookup. They do not start a second
254
- collection. These report formats reject IP and ASN inputs before collection;
255
- JSON and terminal output remain available for those query types.
256
-
257
- Lookup terminal output supports three detail levels. The standard view keeps
258
- the normal bounded evidence summary. `--summary` keeps the source states and
259
- key findings while omitting endpoints and supporting detail. `--verbose` adds
260
- the document generation time and the existing bounded per-source collection
261
- timings. These switches are presentation-only and cannot be combined with
262
- `--json`; they do not change collection or the result document.
263
-
264
- `--json` writes one versioned document to standard output:
265
-
266
- ```json
267
- {
268
- "schema": "whoisleuth.cli.lookup",
269
- "version": 1,
270
- "generatedAt": "2026-07-14T00:00:00.000Z",
271
- "mode": "fast",
272
- "query": "example.com",
273
- "type": "domain"
274
- }
31
+ whoisleuth --help
32
+ whoisleuth commands --common
33
+ whoisleuth commands --group investigate --mode network
34
+ whoisleuth lookup --help
35
+ whoisleuth lookup example.test --deep --plan --json
275
36
  ```
276
37
 
277
- The complete document also carries the normalised `rdap`, `whois`,
278
- `availability`, and `diagnostics` sections returned by the shared lookup
279
- orchestrator. Machine output goes to stdout. Usage and lookup errors go to
280
- stderr, so redirected JSON is not mixed with diagnostics.
281
-
282
- Human-readable domain lookup output separately shows the registrar RDAP status
283
- and endpoint whenever the shared lookup diagnostics represent that follow-up.
284
- Deep mode may report success, unsupported, not found, or an explicit failure;
285
- fast mode reports the existing skipped state. IP, ASN, and lookup responses
286
- without registrar diagnostics remain unchanged. These source states are
287
- provenance only and do not decide availability or imply safety.
288
-
289
- When a deep domain response includes registry interpretation version 1, the
290
- terminal summary also shows the lifecycle label, separately attributed RDAP and
291
- WHOIS disclosure states, reconciliation state, and complete, partial, and
292
- unavailable publication counts. It does not print published contact routes.
293
- The JSON document retains the bounded interpretation and its limitations.
294
-
295
- A deep domain lookup can also show the status, selected public address, and
296
- registered network name from the bounded observed network context. It uses the
297
- same address and IP RDAP source represented in the JSON document. This is
298
- point-in-time edge or network-registration context, not proof of the origin
299
- host, hosting control, ownership, intent, or maliciousness. Fast and compact
300
- commands do not run the enrichment.
301
-
302
- The deep terminal summary also reports the website activity state, page title,
303
- DNS, HTTP, and TLS source states, bounded publisher-declared structured
304
- identity entities, up to six bounded technology indicators, a browser-library
305
- profile count, and the four passive security-posture counts.
306
- These are concise projections of the same evidence already present in the
307
- lookup response. The browser-library line counts apparent components and
308
- catalogue advisory matches without retaining script references or raw
309
- signatures. These summaries make no extra request, omit raw evidence
310
- descriptions, and do not turn a technology or advisory match, or a missing
311
- posture signal, into proof of exploitability, hosting control, ownership, or
312
- maliciousness. Use `--json` when the full bounded evidence, limitations, and
313
- source diagnostics are required.
314
-
315
- `lookup --strict-exit` is an opt-in automation policy. It still emits the
316
- ordinary complete output document, but returns exit code 4 when a requested
317
- diagnostic source is partial, unavailable, rate-limited, timed out, or failed.
318
- The default exit contract remains unchanged, so inconclusive source health does
319
- not silently break existing scripts.
320
-
321
- `lookup --events` and `bulk --events` write versioned
322
- `whoisleuth.cli.progress` version 1 JSONL lifecycle events to stderr while the
323
- ordinary final result stays on stdout. Events contain only the command,
324
- sequence, time, source state or Bulk item index, categorical failure reasons,
325
- and final exit status. They do not contain a target, query, endpoint, file
326
- path, error detail, or evidence value. Human progress and error text are
327
- suppressed while events are active. `--events` cannot be combined with
328
- `--output`, because the final event must describe the same completed stdout
329
- delivery observed by the caller.
330
-
331
- Pressing Ctrl-C asks an in-flight Lookup or Bulk run to stop, suppresses any
332
- partial final result, flushes an enabled Bulk checkpoint, and exits with code
333
- 130. SIGTERM follows the same graceful cleanup path and exits with code 143.
334
- Already started network operations remain subject to their existing hard
335
- timeouts while the shared in-process API unwinds; the executable terminates
336
- after CLI cleanup. A second Ctrl-C removes any known unpublished temporary
337
- output file on a best-effort basis before exiting immediately.
338
-
339
- Bulk can persist compact progress with `--checkpoint <file>`. A new checkpoint
340
- is private, bounded to 16 MiB, versioned, and tied to the exact ordered input
341
- and scan mode by SHA-256. It stores only compact per-item results, never full
342
- Lookup responses. Checkpoint schema 2 records a nullable per-row observation
343
- time. Schema 1 remains readable, but its resumed rows keep observation time
344
- unknown rather than inheriting the resume time. Reusing the same path is
345
- refused unless `--resume` is also
346
- specified. Resume revalidates the complete untrusted document and skips only
347
- the exact completed rows; changed input, mode, schema, digest, or malformed
348
- results fail closed.
349
-
350
- Bulk JSON, JSONL, and item documents use schema version 3. Each row includes
351
- `observedAt` and a `collectionOrigin` of `current_run` or
352
- `resumed_checkpoint`; the top-level `generatedAt` remains the report creation
353
- time. HTTP JSON uses schema version 2 and adds the explicit `assessment` field.
354
- The legacy `activityStatus` field remains for compatibility, but is `null`
355
- when collection is inconclusive rather than labelling the target unreachable.
356
- Consumers should use `assessment`; older version-1 `unreachable` values remain
357
- historical inconclusive labels, not proof that a target cannot be reached.
358
-
359
- If checkpoint persistence fails after collection, WHOISleuth still emits the
360
- completed final result, reports the checkpoint limitation, and exits with code
361
- 4. The last successfully published checkpoint remains available, but it may
362
- not contain the final completed items.
363
-
364
- `diff <left.json> <right.json>` compares two different saved domain Lookup
365
- documents entirely offline. It reuses the bounded Bulk comparison model for
366
- registration, DNS, page identity, mail, certificate, and relationship fields,
367
- keeps missing and unavailable evidence distinct, and makes no ownership or
368
- maliciousness inference. The output records both original observation times.
369
-
370
- `lookup --observer <label> --vantage <label>` can add two bounded analyst labels
371
- to a saved Lookup document. The labels identify the person or process that ran
372
- the observation and the collection context chosen by that analyst; they are
373
- not verified identities, network measurements, or proof of independent
374
- collection. They do not change which sources are queried.
375
-
376
- `reconcile <observation.json> <observation.json> [...]` accepts from 2 to 5
377
- saved Lookup documents for the same domain and compares their bounded fields
378
- offline. It keeps agreement, disagreement, and non-comparable evidence
379
- separate, retains observation times and optional analyst labels, and copies no
380
- filenames or raw registration payloads. Distinct complete label pairs are
381
- reported as labelled collection contexts only; majority agreement is not
382
- treated as truth or authority.
383
-
384
- `timeline <observation.json> <observation.json> [...]` accepts from 2 to 20
385
- saved Lookup documents for one domain, orders them by their validated
386
- observation times, and compares each adjacent pair offline. The 32 MiB aggregate
387
- input ceiling is enforced while files are read and again by the timeline
388
- builder. Output retains normalised field states and observation times but no
389
- input filenames or raw registry payloads. A difference can reflect a domain
390
- change or changed collection conditions, so the command makes no current-state,
391
- ownership, intent, safety, or maliciousness conclusion.
392
-
393
- When diagnostics version 5, 6, 7, or 8 reports a documented registry collection
394
- constraint, terminal output also shows the suffix, WHOIS and RDAP access
395
- profiles, and the bounded limitation. This is static access-policy context: it
396
- does not make another request, and restricted, unpublished, or unavailable
397
- machine access is not evidence that a domain is unregistered or safe.
398
-
399
- ## Exit codes
38
+ The command index groups work under Investigate, Respond, Assure and Utilities.
39
+ Filters combine by intersection. `commands --json` emits the versioned local
40
+ catalogue without reading evidence or running the selected commands.
41
+
42
+ An eligible domain, reserved documentation domain, IP address or ASN can occupy
43
+ command position as Lookup shorthand. Use explicit `lookup` where input needs
44
+ supported URL-like normalisation. Credentials, paths, queries, fragments, ports
45
+ and unsupported special-use targets are rejected by the shorthand.
46
+
47
+ `registry-scaffold` has a separate fixture contract: its `--profile` selects one
48
+ fixed fixture profile and shared `--config` profiles are rejected. It produces
49
+ sanitised local fixture material and makes no registry request.
50
+
51
+ ## Requests and authorisation
52
+
53
+ Offline commands read only supplied arguments, files, standard input and
54
+ installed catalogues. Networked commands contact the sources named by their
55
+ focused help; those sources can observe and rate-limit the operator's network
56
+ address. The CLI does not inherit hosted login, provider configuration or
57
+ hosted operation limits.
58
+
59
+ `lookup --plan` classifies a target and lists intended source families and
60
+ disclosures without collecting. Fast is the Lookup default. Deep adds the
61
+ applicable registration, DNS, HTTP, TLS, page, technology and network context.
62
+ Optional browser providers are not implicit CLI actions.
63
+
64
+ `dnssec-validate` and `mail-transport` are isolated authorised actions. Both
65
+ require a selected literal public resolver, a local trust-anchor document and
66
+ `--owned-or-authorized`; mail transport also requires `--active-probe`. Mail
67
+ transport handles at most three selected MX hosts sequentially, sends `EHLO`
68
+ and uses `STARTTLS` only when advertised. It does not send mail, authenticate,
69
+ test relay, enumerate recipients or retry automatically. DNSSEC, TLSA/DANE,
70
+ PKIX, STARTTLS and SMTP transport remain separate evidence states.
71
+
72
+ The repository-only rendered-capture package is outside hosted and distributable
73
+ collection. It executes remote page JavaScript only for an explicitly
74
+ authorised route set, and each admitted resource operator receives the exact
75
+ requested URL. Captures and screenshots remain local until the operator deletes
76
+ them.
77
+
78
+ ## Files, output and automation
79
+
80
+ File inputs are bounded before parsing; directories, devices and named pipes are
81
+ refused. Output goes to the terminal unless a command supports `--output`.
82
+ Private output is written atomically and an existing path is refused unless
83
+ replacement is explicit.
84
+
85
+ Terminal text is the default. JSON, JSONL, CSV, Markdown, HTML and domain-only
86
+ formats are available only where the installed command declares them.
87
+ Redirected and machine output contains no ANSI or progress text. Diagnostics
88
+ and optional target-free `--events` output use standard error.
89
+
90
+ `--fail-on` and `--strict-exit` expose selected evidence states to automation
91
+ without changing the result document. Review focused help for the policies a
92
+ command supports.
400
93
 
401
94
  | Code | Meaning |
402
95
  | ---: | --- |
403
- | 0 | Command completed. Individual sources may still be partial or inconclusive; inspect diagnostics. |
404
- | 2 | Invalid command, option, input, or stdin shape. |
405
- | 3 | The requested lookup, collection, or comparison operation could not run. |
406
- | 4 | A bounded operation completed partially, such as Bulk item failures or failed explicit Doctor network checks. |
407
- | 70 | Unexpected CLI bootstrap failure. |
408
- | 130 | The analyst cancelled the command. No partial final result was emitted. |
409
- | 143 | The process received SIGTERM. No partial final result was emitted. |
410
-
411
- This release supports `lookup`, `bulk`, `ct-search`, `ct-intake`, `map-observations`, `oam-export`, `discover`, `discover-scan`, `posture`,
412
- `http`, `tls`, `registry-support`, `registry-doctor`, `registry-cohort`, `registry-scaffold`, `risk-calibrate`,
413
- `lookalike-calibrate`, `verify-artifact`,
414
- `inspect-archive`, `manifest`, `sign-artifact`, `verify-signature`, `source-report`,
415
- `compare`, `page-compare`, `mail-review`, `review-evidence`, `brief`, `case-pack`, `domain-control`,
416
- `monitor-once`, `assurance`, `change-packet`, `sharing-review`, `workflow-plan`, `workflow-run`, `diff`, `reconcile`, `timeline`,
417
- `export`, `doctor`, `commands`, `completion`, and `manual`. Additional command families
418
- are added as separate bounded increments rather than exposing incomplete
419
- aliases.
420
-
421
- ## Registry capability coverage
422
-
423
- `registry-support` projects the embedded, versioned registry compatibility
424
- catalogue for one domain or suffix. It distinguishes an explicit
425
- fixture-backed or access-documented suffix profile from the generic IANA
426
- discovery profile and reports the RDAP and WHOIS discovery/access paths,
427
- WHOIS query and parser profiles, fixture scenarios,
428
- verification references, documentation references, and the catalogue's
429
- limitation. The same document includes a dated, official-source aggregate of
430
- generic, generic-restricted, sponsored, and infrastructure RDAP coverage. That
431
- snapshot is separate from the suffix profile and from live reachability.
432
-
433
- Terminal output is bounded and control-safe. `--json` emits version 3 of the
434
- `whoisleuth.cli.registry-support` schema. Unknown but syntactically valid
435
- suffixes retain the generic `discovery_only` profile; malformed input exits
436
- with code 2. The command never probes a registry or tests current reachability.
437
- Coverage is context only and cannot decide registration, availability,
438
- ownership, safety, or maliciousness.
439
-
440
- `registry-doctor [lookup.json]` compares one saved domain Lookup with the same
441
- reviewed local capability profile. It reports whether RDAP and WHOIS collection
442
- states align with allowed, permission-required, or unsupported access, counts
443
- bounded normalised publication fields, and reports publication-quality context
444
- for object identity, base conformance, redaction metadata, required self links,
445
- and event consistency. A missing identifier or metadata field is a publication
446
- omission, not a failed lookup. The command is offline, makes no retry, and
447
- cannot establish current registry reachability.
448
-
449
- `registry-cohort [lookups.json|lookups.jsonl]` aggregates from 1 to 500 saved
450
- Lookups into suffix and capability-profile cohorts. It retains only target-free
451
- counts for source alignment and publication-quality states. A cohort with
452
- fewer than five samples is labelled insufficient rather than treated as a
453
- quality result, and repeated observations from one environment are not assumed
454
- representative.
455
-
456
- `registry-scaffold --profile <id> --suffix <suffix> --scenario <state>` emits
457
- one bounded, sanitised synthetic fixture scaffold from the installed registry
458
- catalogue. The three supported states are `registered`, `not_found`, and
459
- `inconclusive`. It does not fetch a live response, include a real target, or
460
- alter the embedded catalogue.
461
-
462
- The offline RDAP supplied-evidence review implements the request shape defined
463
- by RFC 9536 for `resources`, `domains`, `nameservers`, and `entities`. It also
464
- validates a supplied server's `reverse_search_properties_mapping` response
465
- before preparing a request. Only registered IANA property paths and exact
466
- supported resource/property pairs are accepted. Preparing the request neither
467
- proves that a particular server supports it nor sends a reverse search; active
468
- execution remains gated on a reviewed server policy, privacy boundary, and
469
- deterministic fixtures.
470
-
471
- The separate maintenance command `npm run rdap-extensions:drift` compares the
472
- pinned official RDAP extension fixture with the reviewed local interpretation
473
- catalogue entirely offline. `--live` performs one bounded manual fetch from the
474
- fixed official CSV URL and reports added, removed, renamed, status-changed,
475
- unrecognized, and local-only identifiers. `--json` emits
476
- `whoisleuth.rdap-extension-drift-audit` version 1. Drift exits with status 1 and
477
- requires specification and fixture review; the command never enables an
478
- extension, changes authority or availability logic, or issues reverse search.
479
-
480
- `npm run service-dependencies:audit` validates the passive service-dependency
481
- catalogue entirely offline. It checks the catalogue digest, duplicate
482
- identifiers and target suffixes, evidence classes, source and licence
483
- treatment, source dates, and a fixed 180-day review age. `--json` emits
484
- `whoisleuth.service-dependency-signature-audit` version 1. A stale or changed
485
- signature requires manual provider and benign-fixture review; the command
486
- never resolves a target, checks an account, or tests claimability.
487
-
488
- ## Offline Risk calibration
489
-
490
- `risk-calibrate` replays a versioned analyst-labelled fixture dataset through
491
- the exact Risk model shared with the web application. It does not perform a
492
- lookup, contact the hosted deployment, persist the dataset, alter model weights,
493
- choose a threshold, or tune the model automatically. The report compares fixed
494
- thresholds from 40 through 90 and identifies 70 as the current review band. It
495
- also reports F1, balanced accuracy, Wilson 95% intervals, deliberately small
496
- scan-depth and review-reason strata, and a current-versus-previous model replay.
497
- Strata with fewer than 20 included labels are marked insufficient rather than
498
- presented as reliable performance estimates.
499
-
500
- The JSON report derives a bounded `interoperabilityTags` list from the
501
- analyst-owned disposition and review reason. The mapping uses reviewed MISP
502
- taxonomy terms only where the meaning is unambiguous. Tags do not change a
503
- score, disposition, or case, and no MISP service is contacted.
504
-
505
- Input is capped at 2 MiB and 500 records. Each record requires a unique bounded
506
- ID, an ASCII DNS hostname, one existing analyst disposition, and a strict
507
- whitelist of current scoring inputs. Unknown fields are discarded; arrays,
508
- strings, ages, booleans, provider records, and external findings are revalidated
509
- and bounded before scoring. The accepted dataset envelope is:
510
-
511
- ```json
512
- {
513
- "schema": "whoisleuth.risk-calibration-dataset",
514
- "version": 2,
515
- "records": [
516
- {
517
- "id": "fixture-1",
518
- "domain": "login.example.test",
519
- "analystDisposition": "confirmed_abuse",
520
- "reviewReasonCode": "confirmed_credential_abuse",
521
- "evidence": {
522
- "availability": "registered",
523
- "mutationTypes": ["dictionary"],
524
- "hasPasswordField": true
525
- }
526
- }
527
- ]
528
- }
529
- ```
530
-
531
- `confirmed_abuse` is treated as a positive calibration label; `false_positive`
532
- and `expected` are negative labels. `unreviewed`, `suspicious`, and
533
- `closed_no_action` remain contextual and are excluded from threshold quality
534
- metrics, as are records for which Risk is not applicable. Terminal output caps
535
- its record list at 100 while `--json` retains the complete bounded report,
536
- factor breakdowns, score bands, confidence intervals, bounded strata, model
537
- comparison counts, and per-threshold confusion metrics. Analyst
538
- dispositions and heuristic scores are review context: neither proves
539
- maliciousness or safety.
540
-
541
- The authenticated Monitor workspace can deliberately create the accepted
542
- dataset from explicitly selected cases. Selection is available only when a case
543
- has a reviewed disposition and retained normalised evidence. That local export
544
- contains the case ID, domain, disposition, optional reviewed reason code, and a
545
- bounded whitelist of current scoring inputs. A matched review-language signal
546
- is exported as a fixed indicator, not as captured page text. It excludes notes,
547
- tags, assertions, actions, contacts, raw
548
- source data, provider payloads, and stored Risk scores. Before download, a local
549
- review step shows the selected, included, and excluded counts, the domains and
550
- dispositions that will be written, and the excluded evidence classes. The CLI
551
- still validates every exported record and never trains, tunes, or changes the
552
- Risk model.
553
-
554
- ## Lookalike review-yield calibration
555
-
556
- `lookalike-calibrate [dataset.json]` summarises reviewed candidate outcomes by
557
- mutation family without retaining domains, candidate identifiers, analyst
558
- notes, or evidence values in its output. Input uses
559
- `whoisleuth.lookalike-calibration-input` version 1, is capped at 2 MiB and 5,000
560
- unique opaque records, and requires one reviewed disposition plus from 1 to 12
561
- bounded mutation-family identifiers per record.
562
-
563
- The report keeps exact disposition counts, review-lead rate, false-positive
564
- rate, and a per-family sample state. Fewer than 20 reviewed observations remains
565
- `insufficient`. The command is diagnostic only: it does not tune candidate
566
- generation, filtering, ranking, or Risk, and a useful historical yield does not
567
- establish that a current candidate is malicious or safe.
568
-
569
- ## Offline artefact verification
570
-
571
- `verify-artifact` validates a supported local artefact without printing its
572
- evidence contents. Input is capped at 15 MiB. It currently recognises ordinary
573
- and encrypted workspace archives, case-response packets, acquisition-decision
574
- exports, domain-comparison exports, Bulk mail-exposure exports, and Bulk review
575
- manifests. Reviewed CLI case packs are checked against their canonical digest,
576
- bounded browser-importable case collection, audience, and review marker. The
577
- command also verifies the internal digests of a complete investigation
578
- capsule, including its evidence, brief, graph, and optional analyst-record
579
- projections, and that capsule can be passed to `sign-artifact`. It also validates the bounded versioned structure of saved CLI
580
- Lookup JSON. Because saved Lookup documents do not embed a checksum or
581
- signature, that result is reported as `structure_valid` with content integrity
582
- explicitly unchecked. Saved Lookup validation retains its stricter 8 MiB
583
- document ceiling.
584
-
585
- For an ordinary workspace archive, the command validates the versioned
586
- structure, section byte counts, record counts, and per-section checksums. For a
587
- supported signed review artefact, it validates the declared SHA-256 digest. An
588
- encrypted archive without `--passphrase-file` can establish only that the
589
- envelope is structurally valid; it reports `envelope_valid` and explicitly
590
- leaves authenticated encryption and inner checksums unchecked.
591
-
592
- Supplying a separate passphrase file, capped at 1 KiB, allows authenticated
593
- decryption followed by the ordinary workspace checks. The passphrase is never
594
- accepted as a command-line value, printed, or retained. Verification detects
595
- changes against the artefact's declared contract; it does not authenticate the
596
- analyst or establish that an observation was accurate or remains current.
597
-
598
- ## Privacy-safe source reliability report
599
-
600
- `source-report` summarises source states, durations, truncation, and rate-limit
601
- counts from one version-1 CLI Lookup, Bulk, or Bulk-item document, a JSON array
602
- of up to 100 such documents, or an array containing only previously generated
603
- source-reliability reports. Lookup documents and reports cannot be mixed.
604
- Merged reports preserve exact state and sample totals and add bounded ranges
605
- for each input report's median and p95 duration, a bounded source timeline,
606
- fast/deep/unknown cohorts, and the earliest and latest valid report generation
607
- times. Exact duplicate reports are rejected so one saved report is not
608
- accidentally counted twice. Per-source failure, partial, truncation, and
609
- rate-limit rates remain separate. The command does not pretend that aggregate
610
- timing distributions can reconstruct the original target-level samples. Input
611
- is capped at 12 MiB and traversal, source, duration, and output counts are
612
- bounded.
613
-
614
- The report retains only fixed source identifiers and aggregate operational
615
- counts. It does not output targets, queries, endpoints, source limitations, raw
616
- evidence, or provider payloads. Observation-envelope duration and the
617
- potentially overlapping Lookup timing are reported separately and never added
618
- together. It is a local engineering diagnostic, not analytics, a source-quality
619
- score, or evidence that a collector is currently healthy.
620
-
621
- ## Workspace archive inspection
622
-
623
- `inspect-archive` verifies an ordinary or encrypted workspace archive and then
624
- reports its versioned sections, counts, byte sizes, and checksum states without
625
- printing stored records. An encrypted archive requires
626
- `--passphrase-file`; passphrases are never accepted on the command line.
627
-
628
- An optional `--search` is exact and case-insensitive across a fixed allowlist
629
- of target fields. Default matches disclose only the section, field name, and a
630
- SHA-256 digest. `--reveal` must be selected explicitly to print the matched
631
- value. Notes, contacts, raw evidence, arbitrary object fields, and partial text
632
- search are excluded. Unicode domain searches are canonicalized to their
633
- DNS-safe ASCII form before exact comparison. `--require-match` makes a
634
- no-match result fail for automation and is valid only with `--search`.
635
- Traversal, input size, matches, depth, arrays, and strings are bounded.
636
-
637
- Version 2 of the inspection report adds a content digest over the ordered
638
- section identifiers, schema versions, record counts, and normalised section
639
- content. It deliberately excludes JSON formatting and each section envelope's
640
- export time, so two separately exported archives with the same retained
641
- workspace content have the same identity. `--expect-content-digest <sha256:digest>`
642
- fails when that identity differs, which supports deliberate transfer checks
643
- without printing records. Matching digests detect equivalent retained content;
644
- they do not authenticate who created it or establish that its evidence is
645
- accurate or current. The report separately identifies the source archive
646
- version and the installed reader version.
647
-
648
- ## Optional evidence-package signing
649
-
650
- `sign-artifact` signs a locally verified case-response packet or supported
651
- review manifest with an externally managed Ed25519 private key:
652
-
653
- ```bash
654
- node bin/whoisleuth.mts sign-artifact packet.json --private-key-file analyst-private.pem > packet.signed.json
655
- node bin/whoisleuth.mts verify-signature packet.signed.json --public-key-file analyst-public.pem
656
- ```
657
-
658
- The signed package embeds the public key, key identifier, signature time, and
659
- original artefact. Verification first checks the exact package field set and
660
- signature, then the artefact's own checksums or manifest. A result is reported
661
- as `signature_valid`; signer trust is separately reported as `trusted_key` or
662
- `embedded_key_only`. Without a separately supplied trusted public key,
663
- verification establishes only that the package is internally self-consistent.
664
- WHOISleuth does not generate, store, recover, rotate, publish, or establish
665
- trust in signing keys.
666
-
667
- ## Reproducible investigation manifest
668
-
669
- `manifest <artefact.json> [...] --workflow <label>` reads from 1 to 16 ordered
670
- JSON artefacts and emits `whoisleuth.investigation-manifest` version 1. Each
671
- entry records its sequence, bounded schema and version metadata, exact UTF-8
672
- content digest, canonical JSON digest, and byte count. The manifest also records
673
- the installed CLI version and can include an externally calculated
674
- `--configuration-digest sha256:...` without copying configuration values.
675
-
676
- Source paths, filenames, command-line arguments, and artefact contents are not
677
- retained. Individual artefacts are capped at 15 MiB and the ordered set at
678
- 32 MiB. The manifest carries its own canonical integrity digest, works with
679
- `verify-artifact`, and can be passed to `sign-artifact`. Reproduction still
680
- requires the exact digested artefacts, compatible source services, and any
681
- separately held configuration; matching digests do not establish observation
682
- accuracy or freshness.
683
-
684
- ## Bulk lookup
685
-
686
- `bulk` accepts a newline-delimited file or stdin. It preserves input order,
687
- removes case-insensitive duplicates, and returns a result for every retained
688
- query. Input is capped at 1 MiB. Fast mode is capped at 500 queries with four
689
- workers by default. Deep mode is capped at 50 queries with two workers by
690
- default. Explicit concurrency cannot exceed eight in fast mode or three in
691
- deep mode.
692
-
693
- Bulk uses the shared compact lookup response, so it does not retain raw RDAP
694
- objects or WHOIS response bodies. `--json` returns one bounded collection;
695
- `--jsonl` emits one self-contained versioned item per line. `--domains` emits
696
- only successfully normalised domain names, while `--queries` preserves the
697
- selected bounded input queries and is suitable for an exact retry queue.
698
- Version 2 adds a
699
- bounded `dnsSummary` projection for observed A, AAAA, NS, and MX records plus
700
- null MX, SPF, and DMARC state. `--csv` writes fixed columns for automation,
701
- including the DNS summaries and explicit outcome.
702
-
703
- `--registered-only`, `--inconclusive-only`, and `--errors-only` are mutually
704
- exclusive output filters. The first retains registered, for-sale, and expiring
705
- authority-aware states. The second retains unknown authority states and failed
706
- rows. The third retains only rows whose lookup operation failed, which is useful
707
- for producing an exact retry queue without treating an inconclusive successful
708
- lookup as an operational error. Filtering does not change collection and never
709
- converts an unavailable or failed source into an unregistered result. Machine
710
- documents record collected and emitted counts. A mixture of successful and
711
- failed queries exits with code 4 while preserving every collected result before
712
- output filtering. For example, `bulk domains.txt --queries --errors-only`
713
- produces only the exact failed inputs while retaining the partial-failure exit.
714
-
715
- ## Certificate Transparency search
716
-
717
- `ct-search` accepts one keyword as an argument or on stdin and calls the same
718
- bounded Certificate Transparency module as the web application. It contacts
719
- the upstream public log search service directly from the local machine; it
720
- does not call the hosted WHOISleuth deployment. Quote a multi-word keyword so
721
- the shell passes it as one argument.
722
-
723
- Terminal output summarises certificate rows, observed hostnames, canonical
724
- registrable-domain matches, observation times, bounded certificate-issuance
725
- groups, and completeness. An issuance group contains names observed together
726
- in one public certificate record; a cross-domain group is a review lead, not
727
- an attribution or ownership finding. Terminal output shows at most 100 matches
728
- and five hostnames per match, with explicit omission notes. `--json` returns
729
- the complete bounded structured result in the versioned
730
- `whoisleuth.cli.ct-search` schema. The certificate-group cap is reported
731
- separately from the registrable-domain result cap. CT observations do not prove
732
- that a website is active or malicious.
733
-
734
- ## Local certificate event intake
735
-
736
- `ct-intake [events.json]` reads `whoisleuth.ct-event-batch` version 1 entirely
737
- offline. Each source-qualified event supplies a log identifier, observation
738
- time, certificate SHA-256 digest, one or more DNS names, completeness, and
739
- optional issuer, expiry, and limitations. Unknown fields, malformed names,
740
- unsupported completeness values, and oversized batches are rejected.
741
-
742
- JSON output uses the existing `whoisleuth.external-findings` version 3 contract
743
- and can be deliberately imported into the browser Console. Wildcard names are
744
- normalised to their base DNS name, exact event/domain duplicates are removed,
745
- and deterministic output is capped at 100 findings, 25 domains, and 20 findings
746
- per domain to match the browser import boundary. Omission is stated in each
747
- retained finding when the supplied batch exceeds those limits. The command
748
- makes no request and treats every certificate event as a review lead, not proof
749
- that the certificate was served, requested, or controlled by the named domain.
750
-
751
- ## Declarative observation interchange
752
-
753
- `map-observations [mapping.json]` reads
754
- `whoisleuth.external-observation-mapping` version 1 and applies one strict,
755
- declarative profile to at most 500 local records. The profile selects bounded
756
- dotted field paths for the domain, summary, observation time, optional
757
- reference, and optional completeness. It fixes one source, evidence class, and
758
- finding category for the batch. Profiles cannot contain scripts, templates,
759
- computed expressions, network endpoints, or executable callbacks. Prototype
760
- paths and unknown fields are rejected.
761
-
762
- The resulting JSON is the existing browser-compatible
763
- `whoisleuth.external-findings` version 3 contract. It retains source identity,
764
- observation time, completeness, and limitations, while stating that field
765
- semantics were not independently verified. Deterministic output is capped at
766
- 100 findings, 25 domains, and 20 findings per domain. The command makes no
767
- request and never interprets an omitted field as a negative observation.
768
-
769
- `oam-export [external-findings.json]` projects that strict findings document
770
- into `whoisleuth.open-asset-model-bridge` version 1. It uses the documented
771
- [OWASP Open Asset Model](https://github.com/owasp-amass/open-asset-model)
772
- vocabulary for bounded `FQDN`, `IPAddress`, and `TLSCertificate` assets plus
773
- `dns_record` and `san_dns_name` relations. Only typed A, AAAA, and SHA-256
774
- certificate observations create infrastructure assets or relations. Other
775
- findings remain represented by their FQDN asset.
776
-
777
- This bridge wrapper is not a claim that every receiving implementation accepts
778
- one universal native serialisation. Receivers must validate the projection
779
- against their supported model version. WHOISleuth preserves source and
780
- completeness as discovery metadata, does not invent a confidence score, and
781
- does not treat an edge as proof of ownership, control, coordination, intent,
782
- safety, or maliciousness.
783
-
784
- ## Lookalike discovery
785
-
786
- `discover` runs the same pure, bounded lookalike generator as the Discover
787
- tool without making network requests. It accepts a brand label or a
788
- domain with one suffix label. The default TLD set is `com,net,org`; replace it
789
- with `--tlds com,net` when narrower coverage is wanted.
790
-
791
- Generation presets are `common`, `impersonation`, and `all` (the default).
792
- Keyboard-aware mutations support `qwerty` (the default), `azerty`, and
793
- `qwertz`; `--keyboard all` uses their bounded combined neighbour set, including
794
- adjacent number-row keys. Supply a UTF-8 text file with
795
- `--dictionary terms.txt` to add up to 100 local terms when
796
- using the `impersonation` or `all` preset. Dictionary input is capped at 4,096
797
- bytes and individual terms at 32 characters. Machine output records accepted
798
- and rejected term counts but never copies the private terms into its metadata.
799
-
800
- Use `--families <ids>` instead of `--preset` to run an exact comma-separated
801
- selection. Supported IDs are `character_addition`, `character_omission`,
802
- `character_duplication`, `character_transposition`, `pluralization`,
803
- `tld_embedding`, `www_prefix`, `hyphenation`, `separator_omission`,
804
- `word_reordering`, `keyboard_substitution`, `keyboard_insertion`, `vowel_swap`,
805
- `bitsquatting`, `ascii_homoglyph`, `unicode_homoglyph`,
806
- `unicode_whole_label`, `unicode_homoglyph_depth_2`, `dictionary`,
807
- `dictionary_token_replacement`, `tld_typo`, and `tld_substitution`. Machine
808
- output records the normalised custom selection. A custom dictionary file
809
- requires `dictionary` or `dictionary_token_replacement` in that selection.
810
-
811
- `--domains` writes the unique candidate names only. `--snapshot <file>` keeps
812
- one private, versioned local observation of the normalised seed, generation
813
- configuration, custom-dictionary digest, and candidate set. The first run
814
- creates the snapshot; later runs report added and removed candidates before
815
- atomically replacing it. The snapshot never stores private dictionary terms.
816
- Use the same command from a local scheduler such as cron or a system timer to
817
- perform repeatable discovery runs. WHOISleuth does not install a scheduler,
818
- run a background daemon, or infer that an added candidate is registered,
819
- active, available, or malicious.
820
-
821
- Dotted subdomain permutations are intentionally excluded because the lookup
822
- pipeline validates a hostname's registrable parent. The CLI does not present
823
- authoritative parent registration evidence as proof that a generated hostname
824
- exists.
825
-
826
- Terminal output is capped at 200 candidates with an explicit notice. Versioned
827
- JSON and JSONL use `whoisleuth.cli.discover` schema version 2 and retain the
828
- complete bounded candidate set and mutation provenance. Internationalised
829
- candidates show the DNS-safe ASCII form and readable Unicode form together in
830
- terminal output. The Impersonation and All presets can add up to six
831
- deterministic whole-label Unicode candidates when every letter has a reviewed
832
- same-script replacement. The command generates candidates only. It does not
833
- claim that a domain is registered, active, or malicious.
834
-
835
- `unicode_homoglyph_depth_2` is an explicit `--families` option and is never
836
- enabled by a preset. It replaces exactly two ASCII letters with characters
837
- from the same reviewed script, ranks curated mappings first, and returns at
838
- most 256 candidates. JSON and terminal output report generated candidates,
839
- cross-script or invalid combinations omitted by policy, and lower-ranked
840
- label variants omitted by the family or overall generation budget.
841
-
842
- ## Supervised candidate scan
843
-
844
- `discover-scan` composes the same bounded generator with the compact Lookup
845
- collector. Unlike `discover`, it is an explicitly networked command. It selects
846
- the first deterministic candidates up to `--scan-limit`, processes fixed
847
- chunks sequentially, and retains each registration and DNS source state. Fast
848
- mode is the default and accepts at most 500 candidates. Explicit `--deep` mode
849
- is capped at 50 candidates and concurrency 3 because it can add WHOIS, DNS,
850
- HTTP, TLS, page, and technology work for every selected candidate.
851
-
852
- Use `--chunk-size 1-100`, `--concurrency 1-8`, and the existing private
853
- `--checkpoint <file> [--resume]` boundary to control a run. The checkpoint is
854
- tied to the exact ordered candidate set and scan mode. A new generation order,
855
- limit, or mode requires another checkpoint. `--resolver` accepts at most three
856
- literal IPv4 or IPv6 recursive-resolver addresses and applies them only to DNS
857
- observations in this local run. Resolver hostnames and automatic third-party
858
- resolver selection are not supported. The selected resolvers can observe the
859
- queried candidates and may apply their own logging and retention policies.
860
-
861
- An optional newline-delimited `--allowlist` accepts at most 500 domains and 64
862
- KiB. Matching candidates remain in evidence and are labelled `suppressed` in
863
- the review queue; the full list and unmatched entries are not copied into
864
- output, while each matching scanned candidate necessarily exposes that match.
865
- Allowlisting never deletes a result or asserts that it is safe. Output filters
866
- select registered, inconclusive, acquisition-review, or
867
- suppressed rows without changing whole-run counts or source health. JSON,
868
- JSONL, CSV, and domain-list forms retain mutation provenance and explicit
869
- review lanes. The queue provides next manual actions, not automatic lookup,
870
- acquisition, blocking, submission, or enforcement.
871
-
872
- Deep compact results can group exact shared addresses, nameservers, and mail
873
- servers observed across at least two candidates. These bounded relationships
874
- are pivot leads only. Common hosting, delivery, registrar, and mail services
875
- can produce the same relationship without common ownership or control.
876
-
877
- `--observation-snapshot <file>` keeps a private versioned local projection of
878
- registration state, confidence, and bounded A, AAAA, NS, MX, null-MX, SPF, and
879
- DMARC summaries for the exact candidate set, mode, and resolver selection.
880
- Version 2 records registration and DNS observation times and latest component
881
- states separately; version 1 is read and normalised on the next write. A later
882
- identical run reports material field changes only for components collected
883
- with enough completeness to support the comparison. If registration or DNS is
884
- partial or unavailable, the prior usable evidence for that component is
885
- preserved and the attempt is reported as unavailable rather than converting
886
- missing data into a removal. Raw registry
887
- records, contacts, page content, and request details are excluded. Snapshot
888
- differences are review prompts, not proof of ownership, control, intent,
889
- safety, or maliciousness.
890
-
891
- ## Domain posture audit
892
-
893
- `posture` runs the standard-profile form of the owned-domain DNS and
894
- email-security audit used by Brand Profiles. It queries registry status and
895
- DNSSEC evidence, nameserver delegation, SPF, DMARC, MX, CAA, MTA-STS, TLS-RPT,
896
- and BIMI directly from the local machine. Literal SPF include and redirect
897
- branches are expanded within fixed depth, policy-query, DNS-term, void-answer,
898
- cycle, and time bounds. External DMARC reporting authorisation and external
899
- nameserver, mail, SPF, and reporting dependencies are separately reported.
900
- Supply up to ten known active and retired DKIM selectors in total with
901
- `--selectors selector1,selector2` and `--retired-selectors selector0`;
902
- selectors cannot be reliably discovered from DNS, so no-selector output
903
- reports DKIM as not checked. Use `--mail-profile standard`,
904
- `--mail-profile defensive-no-mail`, or `--mail-profile parked` to make the
905
- intended mail posture explicit rather than inferring it from DNS.
906
-
907
- Terminal output shows each pass, review, action, or informational result and
908
- caps displayed records at five per check with an explicit omission notice.
909
- Versioned JSON retains the complete bounded report, including SPF traversal,
910
- DMARC authorisation, and dependency provenance. Warnings and dangers are
911
- findings rather than command failures; transient resolver or policy-fetch
912
- failures remain informational and should be retried before changing DNS.
913
-
914
- ## HTTP intelligence
915
-
916
- `http` runs the same bounded safe homepage probe used by a deep lookup. It
917
- tries HTTPS before HTTP, follows only validated public-network redirects, caps
918
- each attempt at six seconds, and captures at most 300,000 response bytes for
919
- hashing and metadata. A non-success HTTP response still proves that a web
920
- service answered; failure of both schemes remains inconclusive rather than
921
- evidence that no website exists.
922
-
923
- The command reports normalised redirect, response, content, selected security-
924
- header, body-hash, completeness, and attempt provenance. Captured homepage text
925
- is never written to terminal or JSON output. Query strings are removed by the
926
- shared HTTP evidence normalizer, and terminal values are additionally bounded
927
- and control-safe.
928
-
929
- ## TLS intelligence
930
-
931
- `tls` runs the same bounded one-connection TLS collector used by deep lookups.
932
- It resolves the hostname once through the public-address guard, validates every
933
- answer, connects directly to the first validated address on port 443, and keeps
934
- the original hostname for SNI and certificate identity checking. Resolution
935
- and handshake work share a five-second deadline.
936
-
937
- The report retains the negotiated protocol, ALPN and cipher, runtime trust and
938
- hostname checks, certificate validity, bounded subject and issuer names, SANs,
939
- SAN class counts, signature algorithm and OID, extended-key-usage purposes,
940
- classified Authority Information Access presence counts, SHA-256 certificate
941
- and public-key fingerprints, a bounded certificate chain, and neutral
942
- findings. AIA responder and issuer locations are classified as HTTP, HTTPS, or
943
- other and then discarded; they are not retained or followed. The collector
944
- stores no certificate bytes, session material, or application data and does
945
- not enumerate supported protocol or cipher suites.
946
- A failed collection is inconclusive rather than proof that no TLS service
947
- exists.
948
-
949
- ## Registry-source comparison
950
-
951
- `compare` reads one version-1 `whoisleuth.cli.lookup` domain document from a
952
- file or stdin and emits a version-3 `whoisleuth.cli.compare` document. Its
953
- primary comparison reconciles normalised registry RDAP and WHOIS fields. When
954
- the saved deep lookup also represents the optional registrar RDAP follow-up,
955
- an additional sibling comparison reconciles the portable registry and
956
- registrar RDAP publication fields. The command does not repeat the lookup,
957
- contact the hosted deployment, or treat a conflict as a command failure. Use a
958
- deep lookup when multiple sources are wanted; a fast lookup deliberately
959
- records WHOIS as skipped, and comparison preserves that state as unavailable
960
- rather than misreporting RDAP-only publication.
961
-
962
- Input is capped at 8 MiB and must retain the lookup schema, mode, source
963
- diagnostics, and normalised parsed source sections. Per-value, list, and event
964
- bounds are revalidated because saved JSON is treated as untrusted input. A
965
- successful registrar source must include a normalised object and agree with
966
- its diagnostic status. Raw RDAP JSON, registrar contacts and source-specific
967
- handles, WHOIS response bodies, availability evidence, and unrelated lookup
968
- fields are not copied into the comparison result.
969
-
970
- When the saved Lookup contains valid version-5, version-6, or version-7, context-only
971
- registry-access diagnostics, version 3 retains their bounded suffix, access profiles, and
972
- limitation. Terminal output labels the same collection context explicitly.
973
- It explains source reachability only and cannot decide registration,
974
- availability, ownership, safety, or maliciousness. Older documents and saved
975
- lookups without that context do not gain a registry-access field.
976
-
977
- Terminal and versioned JSON output cover domain identity, registry object ID,
978
- registrar, registrar IANA ID, lifecycle dates, DNSSEC, statuses, and name
979
- servers. The shared comparison model normalises harmless case, punctuation,
980
- ordering, and date-precision differences while distinguishing conflicts,
981
- one-source publication, redaction, incomplete sources, and unavailable
982
- sources. This is source reconciliation, not an availability, ownership, or
983
- maliciousness decision.
984
-
985
- ## Static page comparison
986
-
987
- `page-compare <left.json> <right.json>` reads two different version-1 saved
988
- Deep domain Lookup documents and compares the already-retained static page
989
- identity, exact and perceptual favicon evidence, technology identifiers, TLS
990
- issuer label, and TLS public-key fingerprint. DOM structure is compared first
991
- by its exact bounded tag-sequence digest, then, when both captures provide it,
992
- by a parse5-tokenized structural SimHash. It makes no request and requires
993
- complete supported static page-identity observations on both sides.
994
-
995
- Each page component remains independent. Exact, similar, overlapping,
996
- different, unavailable, and partial evidence are not collapsed into a score.
997
- Matching components are investigative relationships rather than proof of
998
- copying, common ownership, control, intent, safety, or maliciousness. Static
999
- comparison does not execute JavaScript; use the optional local rendered
1000
- capture package only when that additional active behaviour is authorised.
1001
-
1002
- ## Passive mail exposure review
1003
-
1004
- `mail-review [bulk.json|bulk.jsonl]` reads version-2 Bulk output locally and
1005
- summarises MX, null MX, SPF, DMARC, and mail-provider relationships. It keeps
1006
- authenticated mail, authentication gaps, incomplete authentication evidence,
1007
- no explicit MX, null MX, and incomplete DNS evidence as separate states.
1008
- Shared-provider relationships are based only on the registrable domain of an
1009
- observed MX hostname and do not establish shared ownership or control.
1010
-
1011
- The command makes no DNS or SMTP request and retains no source path. It does
1012
- not test message acceptance, relay behaviour, mailbox existence, catch-all
1013
- behaviour, SMTP banners, or whether a mail server is rogue, safe, or malicious.
1014
-
1015
- An analyst may add a bounded `tlsaEvidence` object to a version-2 Bulk item for
1016
- offline DANE review. It must name the exact `_25._tcp.<mx-host>` service, and
1017
- that host must occur in the same item's retained MX evidence. A certificate
1018
- association match is complete only when `dnssecState` is `validated`. TLSA
1019
- usages 0 and 1 additionally require `pkixValidationState: "validated"`.
1020
- Usages 0 and 2 compare against the bounded `authorityMaterials` array; usages
1021
- 1 and 3 compare against the supplied leaf certificate or SPKI. Mismatched
1022
- service names, missing certificate roles, unvalidated prerequisites, malformed
1023
- material, and truncation remain invalid, partial, or untrusted rather than
1024
- becoming a DANE match.
1025
-
1026
- ## Offline supplied-evidence review
1027
-
1028
- `review-evidence [evidence.json]` accepts one version-1 JSON input and performs
1029
- only deterministic local parsing, comparison, or request planning. Input is
1030
- capped at 16 MiB. The command never retrieves DNS, opens SMTP, contacts an
1031
- RDAP server, submits a resolver query, or looks up an address in a hosted
1032
- GeoIP service.
1033
-
1034
- Supported input schemas are:
1035
-
1036
- - `whoisleuth.dnssec-evidence-input`: compares bounded DS and DNSKEY records,
1037
- recalculates DNSKEY key tags and supported DS digests, and reviews supplied
1038
- RRSIG validity windows at `observedAt`. `consistent` describes only the
1039
- supplied DS/DNSKEY relationship. It does not authenticate a chain to a root
1040
- trust anchor, validate RRSIG cryptography, or prove that a missing record is
1041
- absent.
1042
- - `whoisleuth.tlsa-evidence-input`: binds TLSA records to one explicit
1043
- `_port._transport.hostname` service and compares supplied leaf or authority
1044
- certificate/SPKI bytes. `matched` requires independently validated DNSSEC;
1045
- PKIX-TA and PKIX-EE usages also require an independently validated PKIX path.
1046
- The command does not retrieve the certificate or negotiate STARTTLS.
1047
- - `whoisleuth.rdap-search-input`: normalises a supplied RDAP search-help
1048
- response and prepares an exact supported reverse-search request without
1049
- sending it. If the document also contains a previously obtained `response`,
1050
- the command checks its bounded property mappings against the reviewed
1051
- registration and reports omitted or unrecognised mappings without treating
1052
- the response as authoritative or complete.
1053
- - `whoisleuth.rpki-route-input`: compares a route prefix and origin ASN with a
1054
- bounded analyst-supplied VRP set.
1055
- - `whoisleuth.local-geoip-query`: queries an analyst-supplied bounded prefix
1056
- database whose source, version, and licence metadata remain in the result.
1057
- - `whoisleuth.local-mmdb-query`: with an explicit `--mmdb <database-file>`,
1058
- queries one analyst-supplied MaxMind DB file locally. The query document must
1059
- carry `address`, `sourceLabel`, `databaseVersion`, and `license`. WHOISleuth
1060
- does not bundle, download, update, license, transmit, or retain the database.
1061
- The nested result uses the same address, network, country, region, city, ASN,
1062
- source, and limitation fields as the bounded JSON-prefix path. This mode is
1063
- CLI-only because a hosted or browser deployment cannot open an analyst's
1064
- local file; its JSON result remains portable to website-compatible evidence
1065
- archives and reports.
1066
- - `whoisleuth.encrypted-dns-plan-input`: validates an explicitly reviewed
1067
- encrypted-DNS provider contract and prepares a bounded query plan. It does
1068
- not execute the plan.
1069
- - `whoisleuth.zone-intent.input`: parses either a deliberately supported,
1070
- bounded BIND master-file subset or normalised DNS records and compares it
1071
- with one separately attributed observation. TXT values are reduced to
1072
- SHA-256 digests, unsupported directives and records remain rejected, and an
1073
- incomplete observation never becomes a missing-record conclusion. The
1074
- review does not contact a resolver or apply a DNS change.
1075
- - `whoisleuth.domain-portfolio.input`: reviews up to 500 analyst-supplied
1076
- domain inventory rows for exact registrar, DNS, mail, certificate and
1077
- recovery concentration, renewal-review gaps and internal recovery-domain
1078
- dependencies. Account labels and provider assignments remain analyst
1079
- assertions, and the review makes no provider or account request.
1080
- - `whoisleuth.domain-change.input`: compares bounded, separately labelled
1081
- authority and resolver observations; reviews CDS, CDNSKEY and CSYNC
1082
- publication consistency; inventories supplied SRV services and ACME
1083
- dependencies; and records TLS key continuity, stapling, embedded timestamp,
1084
- and HSTS preload context. TXT values are retained only as SHA-256 digests.
1085
- The result is an offline review gate, not a DNSSEC validation, preload-list
1086
- lookup, certificate-authority request, or permission to apply a change.
1087
- - `whoisleuth.dns-convergence.input`: compares the latest supplied observation
1088
- from at least two labelled resolvers or network vantages. It preserves
1089
- converged, divergent, unexpected, incomplete, and insufficient record-set
1090
- states, can compare against optional expected values, and projects a simple
1091
- observation-time plus TTL cache horizon. It does not query DNS or decide
1092
- which divergent value is authoritative, and supplied TTLs do not reveal
1093
- actual cache age or resolver refresh policy.
1094
- - `whoisleuth.nameserver-preflight.input`: reviews an intended nameserver set
1095
- against separately attributed direct-service observations before a
1096
- delegation change. It checks authoritative service, the served NS set, SOA
1097
- evidence, public addresses and in-bailiwick glue readiness without querying
1098
- DNS, opening a socket or changing registry configuration.
1099
- - `whoisleuth.trust-store-comparison.input`: compares an already-observed,
1100
- bounded certificate-chain SHA-256 fingerprint set with up to 16
1101
- analyst-supplied trust-store snapshots. Each snapshot carries its own name,
1102
- version, source, review time, completeness, and no more than 2,048 anchor
1103
- fingerprints. Exact intersections, complete non-observations, and
1104
- inconclusive inputs remain separate. A match does not build or validate a
1105
- certificate path, and non-observation does not mean a client would reject
1106
- the chain because served chains commonly omit their root.
1107
-
1108
- The common output is `whoisleuth.cli.offline-evidence-review` version 1. It
1109
- retains the nested result's explicit state and limitations. A locally
1110
- consistent relationship is not converted into a claim about current
1111
- publication, ownership, safety, or maliciousness.
1112
-
1113
- `review-evidence --strict-exit` is an opt-in local automation boundary. It
1114
- returns the partial-failure exit code when an input family exposes an explicit
1115
- failed `gate`, or when a zone-intent comparison is incomplete or contains a
1116
- difference, missing value or unexpected value. Other evidence families retain
1117
- their ordinary exit behaviour; the flag does not invent a pass/fail policy for
1118
- them. JSON is still emitted before the exit status is selected.
1119
-
1120
- ## Domain control manifests
1121
-
1122
- `domain-control [input.json]` builds or reviews a bounded desired-state
1123
- manifest without making a request or changing configuration. A manifest input
1124
- uses `whoisleuth.domain-control-manifest-input` version 1, includes an expiry,
1125
- and may record expected nameservers, DS, MX, CAA, TLS issuer, TLS SPKI
1126
- fingerprint, registrar-lock preference, and a renewal-review date for up to 100
1127
- domains. Empty fields mean unconfigured; they do not require a record to be
1128
- absent.
1129
-
1130
- The emitted `whoisleuth.domain-control-manifest` version 1 is normalised and
1131
- protected by a canonical SHA-256 digest. It can also be passed to
1132
- `sign-artifact` for an optional local Ed25519 signature. Integrity and
1133
- signature verification detect changes and authenticate possession of the
1134
- selected key; neither establishes that the desired state is correct. Manifest
1135
- input and verification reject unknown fields, and verification rejects
1136
- non-canonical content rather than returning a shape that differs from the
1137
- normalised contract covered by the digest.
1138
-
1139
- A review input uses `whoisleuth.domain-control-review-input` version 1 and
1140
- contains one manifest plus separately attributed observations. Only a complete
1141
- `observed` field may produce `drift`. Partial, unavailable, unsupported, and
1142
- missing observations remain inconclusive, and unrelated observations are
1143
- counted but ignored. The review performs no DNS, RDAP, HTTP, TLS, SMTP, or
1144
- registrar request.
1145
-
1146
- ## Domain assurance review
1147
-
1148
- `assurance [input.json]` reviews one bounded analyst-authored workflow entirely
1149
- offline. Version 1 inputs remain supported. Version 2 adds optional
1150
- `customChecks` to retirement inputs and remains the current normalised output
1151
- version. The input uses `whoisleuth.domain-assurance.input` and one of three
1152
- fixed kinds:
1153
-
1154
- - `planned-change` records a bounded window, evidence-backed milestones,
1155
- rollback criteria, and post-change checks;
1156
- - `recovery-dependencies` reviews up to 100 domains across registrar, DNS,
1157
- mail, certificate, and recovery providers and highlights exact provider
1158
- concentration; and
1159
- - `retirement` checks the fixed decommissioning controls without treating an
1160
- unchecked item as complete. Version 2 can add up to 20 analyst-defined checks,
1161
- each with a bounded identifier, label, expected boolean, and true, false, or
1162
- null observed value.
1163
-
1164
- Provider labels, readiness confirmations, evidence references, and expected
1165
- states remain analyst assertions. The output preserves incomplete and
1166
- needs-review states and gives every negative state an explicit review reason.
1167
- The versioned input rejects unknown fields and contradictory evidence attached
1168
- to an unfinished check. It stores no credentials, makes no request, and changes
1169
- no registrar, DNS, mail, certificate, or recovery configuration.
1170
-
1171
- ## Domain change assurance packet
1172
-
1173
- `change-packet [input.json]` combines one pre-change domain review, one
1174
- post-change domain review, and one planned-change assurance input for the same
1175
- domain. The input uses `whoisleuth.domain-change-packet.input` version 1. The
1176
- command revalidates each nested contract, summarises changed authoritative
1177
- record sets, and emits `whoisleuth.domain-change-packet` version 1 with a
1178
- canonical SHA-256 integrity digest.
1179
-
1180
- The packet is ready only when both supplied observation reviews and the change
1181
- plan pass their own bounded gates. Partial or unavailable evidence remains a
1182
- review reason. Packet assembly performs no collection or configuration change,
1183
- and digest validity does not authenticate the analyst. A reviewed packet can be
1184
- passed to `sign-artifact` when the operator has an independently managed
1185
- Ed25519 signing-key lifecycle.
1186
-
1187
- ## Pre-sharing review
1188
-
1189
- `sharing-review [artifact.json]` performs a redacted local preflight before an
1190
- analyst deliberately shares an artefact. The analyst must select a TLP 2.0
1191
- marking, a recipient scope, and a bounded purpose. Optional confirmations record
1192
- human review, personal-data review, and redaction review. The command validates
1193
- supported artefact integrity where possible, detects stricter embedded TLP
1194
- markings, and reports only key-category counts plus bounded, control-free schema
1195
- and integer version metadata. It emits no content values and copies no raw
1196
- evidence.
1197
-
1198
- An imported stricter marking cannot be downgraded by the requested marking, and
1199
- recipient scope is checked against the effective marking. Evading this local
1200
- preflight remains possible, so the result is a review aid rather than access
1201
- control, legal advice, or recipient authorisation.
1202
-
1203
- ## Fixed investigation plans
1204
-
1205
- `workflow-plan <recipe> <domain|brand>` turns one of four fixed recipes into a
1206
- versioned `whoisleuth.cli.investigation-plan` document. Supported recipes are
1207
- `domain-triage`, `lookalike-review`, `owned-domain-review`, and
1208
- `historical-comparison`. Each step names an existing CLI command, carries its
1209
- arguments as a JSON array, declares whether it is offline or networked, and
1210
- marks network-disclosure or analyst-selection approval gates.
1211
-
1212
- The command is plan-only. It does not execute a step, construct a shell script,
1213
- interpret a placeholder as a file path, read an artefact, make a request,
1214
- change a case, or submit evidence. Analysts deliberately run selected commands
1215
- after reviewing their collection boundaries. This provides repeatable
1216
- domain-specific workflows without an arbitrary automation or plugin surface.
1217
-
1218
- ## Local handoffs and one-shot monitoring
1219
-
1220
- `brief [lookup.json]` reads one saved Lookup and emits version 2 of the bounded
1221
- `whoisleuth.cli.lookup-brief` contract. It separates retained facts,
1222
- contradictions, incomplete source states, and manual actions. Each action
1223
- states its evidence basis and expected outcome; it does not run the action or
1224
- create a case.
1225
-
1226
- `case-pack [cases.json] --audience <internal|trusted|public> --reviewed` reads a
1227
- browser case export containing at most 25 normalised cases, applies the selected
1228
- redaction boundary, and emits a browser-importable case collection with a
1229
- canonical SHA-256 digest and redaction manifest. It refuses an invalid,
1230
- duplicate, larger, or generated package above the browser's 2 MiB import limit
1231
- rather than silently omitting records or evidence. Trusted output removes notes,
1232
- recipient values, and manual-pivot targets. Public output additionally removes
1233
- actions and analyst assertions. The review flag records an explicit choice; it
1234
- does not prove recipient authorisation or factual correctness.
1235
-
1236
- `verify-artifact` recognises the complete case-pack envelope before browser
1237
- import. It checks the canonical digest, supported case-export schema, bounded
1238
- case count, report count, audience and explicit review marker without printing
1239
- case contents. This detects a changed hand-off file but does not authenticate
1240
- the analyst, recipient, source observations, or review decision.
1241
-
1242
- `monitor-once [manifest.json]` performs one bounded Deep control review for at
1243
- most 20 manifest domains with concurrency capped at three. An optional
1244
- `--previous` checkpoint adds local first/last-observed comparison. It is not a
1245
- daemon or scheduler, retains compact normalised observations rather than raw
1246
- payloads, and keeps failed collection incomplete. JSON, JUnit, and explicit
1247
- failure policies are supported.
1248
-
1249
- `workflow-run <recipe> <subject>` executes only concrete steps from the four
1250
- installed fixed recipes. Network steps require `--approve-network` for that
1251
- invocation. Analyst-selection placeholders always pause. A bounded `--resume`
1252
- state must match the exact recipe and subject, cannot add commands or shell
1253
- syntax, and is not evidence that earlier results remain current.
1254
-
1255
- ## Optional local rendered capture
1256
-
1257
- `packages/web-capture` is a private repo-local Playwright package, not part of
1258
- the distributable core CLI or hosted application. It requires an explicit
1259
- authorisation flag and one new output directory:
1260
-
1261
- ```bash
1262
- npm run capture:local -- https://example.test --output-dir ./capture-example --authorize-rendered-capture
1263
- npm run capture:compare -- ./official/manifest.json ./candidate/manifest.json --json
1264
- ```
1265
-
1266
- It writes a fixed 1024x768 PNG, screenshot SHA-256 and perceptual dHash, a DOM
1267
- digest containing hashes and bounded element counts rather than markup or page
1268
- text, and a version-2 `whoisleuth.web-capture-manifest` compatible with the
1269
- Cases importer. Version-1 manifests remain importable.
1270
-
1271
- Rendered capture executes page JavaScript. It caps HTTP(S) requests and request
1272
- hostnames, blocks downloads, service workers, WebSockets, WebRTC, WebTransport,
1273
- non-read methods, credentials, non-default ports, and private or reserved
1274
- addresses, and retains
1275
- no request path, query, headers, bodies, cookies, credentials, DOM markup, or
1276
- page text. Every browser request is intercepted, its hostname is resolved again,
1277
- and the bounded response is fetched through WHOISleuth's public-address-pinned
1278
- transport. Individual responses are capped at 4 MiB and all fetched response
1279
- bodies together are capped at 24 MiB. Redirect destinations pass through the
1280
- same interception and validation before collection continues. Use a disposable
1281
- network-restricted environment for untrusted targets because rendered page code
1282
- still executes inside the isolated browser process.
1283
-
1284
- The separate offline comparison command accepts two selected version-2 local
1285
- capture manifests. It first verifies each referenced screenshot and DOM digest
1286
- against its declared size, SHA-256, screenshot dimensions, and perceptual hash;
1287
- it also validates bounded source and limitation metadata and requires the DOM,
1288
- manifest, and source collection times to agree. It then
1289
- compares screenshot distance, exact rendered DOM and visible-text digests,
1290
- bounded element counts, page identity, technologies, and request-domain sets.
1291
- It does not recrawl either target, reveal the input paths, or collapse the
1292
- independent components into a similarity or maliciousness score. A missing
1293
- perceptual hash remains unavailable rather than becoming a visual difference.
1294
-
1295
- ## Lookup evidence export
1296
-
1297
- `export` converts one version-1 `whoisleuth.cli.lookup` domain document from a
1298
- file or stdin into the same versioned `whoisleuth.lookup-evidence` JSON package
1299
- produced by the web Lookup tool. It performs no lookup and writes only to
1300
- stdout, so use ordinary shell redirection when a file is wanted. Pretty JSON is
1301
- the default; `--compact` emits one compact JSON line for pipeline use, while
1302
- `--markdown` produces a readable source-attributed summary and `--html`
1303
- produces a self-contained printable report. Compact, Markdown, and HTML output
1304
- are mutually exclusive.
1305
-
1306
- The saved input is capped at 8 MiB and revalidated using the same schema,
1307
- source-status, parsed-data, scalar, list, and event boundaries as `compare`.
1308
- The export retains query context, source diagnostics, normalised registry data,
1309
- raw registry RDAP JSON, the raw WHOIS referral chain, availability analysis,
1310
- and the shared registry-source comparison. Version 23 can add the exact local
1311
- SSLBL comparison already represented by a deep full Lookup. Version 21 adds the bounded registry
1312
- lifecycle, disclosure, publication-quality, reconciliation, and abuse-routing
1313
- interpretation derived from the already-collected sources. Registrar RDAP raw
1314
- data, contacts, entities, links, notices, and source-specific handles remain
1315
- excluded. Schema version 20 replaces selected security-policy values in
1316
- retained HTTP evidence
1317
- with presence-only markers and can include fixed response-policy findings from
1318
- an already-represented deep lookup. Version 19 additionally retains the bounded credential-surface projection
1319
- when the saved deep lookup represents it. Version 18 retains the bounded structured identity projection
1320
- when the saved deep lookup represents it. Version 17 retains the normalised portable-field comparison, explicit
1321
- source-health states, a strict bounded projection of observed network
1322
- registration, an optional normalised security.txt disclosure source, HTTPS
1323
- service-binding publications, and the passive browser-library profile when the
1324
- saved deep lookup represents them. Raw IP RDAP payloads, security.txt response
1325
- bodies, script references, matched script content, and contact entities remain
1326
- excluded.
1327
-
1328
- Markdown output summarises query context, assessment state, registry sources,
1329
- source reconciliation, network observations, and collection diagnostics. It
1330
- escapes all upstream text as untrusted content, bounds displayed values and
1331
- lists, and deliberately omits raw RDAP JSON and full WHOIS response bodies.
1332
- Use JSON when the complete evidence package or machine processing is required.
1333
- The browser Console reuses this bounded Markdown renderer for domain results
1334
- after first reducing the typed Lookup response to the known normalised fields
1335
- needed by the report. It separately offers bounded IP and ASN summaries from
1336
- their normalised RDAP and source-health fields; IP reports can also include
1337
- bounded reverse-DNS context already collected by Lookup. The browser action
1338
- does not change the CLI input or output contract.
1339
- When a version-5, version-6, or version-7 lookup records a documented registry-access constraint, both
1340
- Markdown and HTML include that context in collection diagnostics without
1341
- changing its non-authoritative interpretation. Both formats also include the
1342
- selected address and bounded network registration when present, together with
1343
- the edge-versus-origin limitation.
1344
-
1345
- HTML uses the same bounded summary model as Markdown. The generated document
1346
- contains inline styling for screen and print, but no scripts, forms, active
1347
- links, or external resources. A restrictive embedded Content Security Policy
1348
- provides defence in depth when the local file is opened in a browser. All
1349
- registry values are HTML-escaped and displayed as text.
1350
-
1351
- This is a deliberately rich evidence package. Raw registry sources can contain
1352
- publicly published contact data, and deep availability evidence can contain
1353
- bounded website, DNS, mail, page-identity, and TLS observations. Review and
1354
- secure the output before sharing it. The CLI does not add browser-only IDN
1355
- profile analysis, so that optional evidence field is `null`.
96
+ | 0 | The command completed; individual sources can still be partial. |
97
+ | 2 | The command, option or input was invalid. |
98
+ | 3 | Collection, lookup or comparison failed. |
99
+ | 4 | The result was partial or a selected evidence policy was not met. |
100
+ | 70 | The CLI could not complete bootstrap. |
101
+ | 130 | The analyst cancelled; no partial final result was emitted. |
102
+ | 143 | SIGTERM stopped the process; no partial final result was emitted. |
103
+
104
+ ## Portable documents and compatibility
105
+
106
+ Readers accept only their declared public and current versions. Unknown,
107
+ unreleased historical and future schemas fail before partial interpretation;
108
+ an invalid import is not treated as an empty document.
109
+
110
+ `inspect-archive` reads current workspace archive v6 and exact public v5. It
111
+ reports section metadata and digest-only search results unless `--reveal` is
112
+ explicitly selected. It never searches notes, contacts or arbitrary raw fields.
113
+
114
+ `export` reads supported saved Lookup v1 or v2 and writes current Lookup
115
+ evidence schema 27. Exact public schema 26 remains readable and can contain
116
+ public contact fields; current schema 27 excludes raw registration payloads,
117
+ expanded contacts, credentials, complete query-bearing URLs and provider
118
+ payloads.
119
+
120
+ `verify-artifact` checks a recognised structure and its applicable integrity
121
+ contract. `interchange-report` describes retained and omitted fields.
122
+ `sign-artifact` and `verify-signature` keep artefact validity, signature
123
+ validity and signer trust separate. None of these checks establishes that
124
+ evidence is accurate, current, safe to share or attributable to a person.
125
+
126
+ ## Command-family boundaries
127
+
128
+ - Evidence collection commands retain separate source states. A failed or
129
+ missing supporting source is not converted into absence, availability or a
130
+ favourable score.
131
+ - Discover and Certificate Transparency commands produce review candidates.
132
+ Generation, publication and shared infrastructure do not establish ownership,
133
+ control, activity, intent or maliciousness.
134
+ - Bulk applies one declared collection contract per target. Fast accepts up to
135
+ 500 targets and Deep up to 50; each target remains a separate request.
136
+ - Respond commands prepare local Cases, packets and sharing reviews. They do not
137
+ submit, publish, notify or grant recipient authorisation.
138
+ - Assurance, comparison and calibration commands describe supplied or retained
139
+ evidence. They do not tune the running model, change infrastructure or turn an
140
+ analyst label into observed truth.
141
+ - `workflow-plan` lists fixed installed recipes without executing them.
142
+ `workflow-run` executes only installed steps, requires approval for network
143
+ work and pauses for analyst-selection placeholders.
144
+
145
+ Use the installed focused help for positional inputs, exact ceilings, options,
146
+ network effects, outputs and command-specific exit behaviour.