@slicedearth/whoisleuth-cli 1.45.0 → 1.47.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DISCLOSURE +7 -3
- package/NOTICE +5 -4
- package/README.md +59 -6
- package/bin/whoisleuth.mjs +5 -3
- package/cli/arguments.mjs +256 -9
- package/cli/artifact-structure.mjs +1833 -0
- package/cli/artifact-verify.mjs +242 -49
- package/cli/bounded-json.mjs +1 -0
- package/cli/bulk-checkpoint.mjs +2 -3
- package/cli/bulk-command-runner.mjs +2 -5
- package/cli/case-pack.mjs +819 -34
- package/cli/command-reference.mjs +48 -24
- package/cli/completion.mjs +16 -8
- package/cli/ct-event-intake.mjs +32 -2
- package/cli/discovery-scan-command-runner.mjs +4 -5
- package/cli/discovery-workflow.mjs +2 -3
- package/cli/doctor.mjs +2 -2
- package/cli/domain-control-monitor.mjs +21 -15
- package/cli/domain-control-observations.mjs +25 -2
- package/cli/evidence-command-runner.mjs +17 -11
- package/cli/evidence-signing.mjs +73 -45
- package/cli/export-evidence.mjs +11 -4
- package/cli/formatters/html.mjs +3 -3
- package/cli/formatters/terminal.mjs +3 -0
- package/cli/input.mjs +57 -0
- package/cli/interchange-report.mjs +226 -0
- package/cli/investigation-manifest.mjs +16 -17
- package/cli/investigation-run.mjs +71 -23
- package/cli/local-mmdb-review.mjs +45 -14
- package/cli/lookup-command-runner.mjs +2 -2
- package/cli/lookup-diff.mjs +9 -0
- package/cli/network-command-runner.mjs +78 -0
- package/cli/offline-evidence-review.mjs +28 -8
- package/cli/page-compare.mjs +8 -5
- package/cli/registry-cohort.mjs +385 -61
- package/cli/registry-support.mjs +2 -1
- package/cli/retained-artifact-diff.mjs +376 -0
- package/cli/risk-calibration.mjs +7 -5
- package/cli/runner.mjs +147 -185
- package/cli/saved-lookup.mjs +26 -3
- package/cli/sharing-review.mjs +12 -6
- package/docs/cli-reference.md +444 -70
- package/docs/cli.md +24 -5
- package/frontend/src/lib/analysis/acquisition-decision-packet.js +4 -4
- package/frontend/src/lib/analysis/artifact-integrity.js +42 -0
- package/frontend/src/lib/analysis/brand-profile-model.js +29 -5
- package/frontend/src/lib/analysis/bulk-domain-comparison.js +25 -5
- package/frontend/src/lib/analysis/bulk-mail-exposure.js +66 -15
- package/frontend/src/lib/analysis/bulk-retry-plan.js +1 -1
- package/frontend/src/lib/analysis/bulk-review-export.js +7 -6
- package/frontend/src/lib/analysis/bulk-review-model.js +3 -2
- package/frontend/src/lib/analysis/bulk-session-model.js +192 -26
- package/frontend/src/lib/analysis/bulk-sort.js +4 -0
- package/frontend/src/lib/analysis/case-brand-profile-references.js +85 -0
- package/frontend/src/lib/analysis/case-evidence-model.js +8 -0
- package/frontend/src/lib/analysis/case-investigation-branch-model.js +134 -0
- package/frontend/src/lib/analysis/case-migration-model.js +83 -31
- package/frontend/src/lib/analysis/case-record-contracts.js +4 -2
- package/frontend/src/lib/analysis/case-record-model.js +2 -0
- package/frontend/src/lib/analysis/case-record-operations.js +42 -12
- package/frontend/src/lib/analysis/case-report.js +39 -6
- package/frontend/src/lib/analysis/case-response-model.js +66 -7
- package/frontend/src/lib/analysis/case-response-packet.js +15 -5
- package/frontend/src/lib/analysis/comparison-ledger-bulk.js +366 -0
- package/frontend/src/lib/analysis/comparison-ledger-contract.js +241 -0
- package/frontend/src/lib/analysis/comparison-ledger-json.js +79 -0
- package/frontend/src/lib/analysis/comparison-ledger-serialization.js +51 -0
- package/frontend/src/lib/analysis/domain-control-manifest-core.js +145 -0
- package/frontend/src/lib/analysis/domain-control-records.js +88 -0
- package/frontend/src/lib/analysis/external-findings-import.js +70 -6
- package/frontend/src/lib/analysis/investigation-capsule.js +47 -13
- package/frontend/src/lib/analysis/investigation-guide.js +52 -10
- package/frontend/src/lib/analysis/investigation-template-model.js +9 -6
- package/frontend/src/lib/analysis/lookup-claim-passport.js +236 -0
- package/frontend/src/lib/analysis/lookup-claim-readiness.js +280 -0
- package/frontend/src/lib/analysis/lookup-decision-support.js +61 -6
- package/frontend/src/lib/analysis/lookup-presentation.js +62 -0
- package/frontend/src/lib/analysis/opaque-reference-id.js +9 -0
- package/frontend/src/lib/analysis/utils.js +26 -3
- package/frontend/src/lib/analysis/visualization-matrix.js +71 -28
- package/frontend/src/lib/analysis/visualization-models.js +63 -94
- package/frontend/src/lib/analysis/visualization-time-series.js +53 -12
- package/frontend/src/lib/analysis/website-snapshot-model.js +6 -0
- package/frontend/src/lib/analysis/workspace-archive.js +104 -14
- package/lib/application-version.mjs +3 -0
- package/lib/availability.mjs +14 -12
- package/lib/bounded-file.mjs +13 -0
- package/lib/bounded-json-response.mjs +17 -4
- package/lib/bounded-json.mjs +249 -0
- package/lib/certificate-extension-profile.mjs +2 -1
- package/lib/cryptographic-assurance.mjs +155 -0
- package/lib/ct-search.mjs +87 -47
- package/lib/dns-intelligence.mjs +3 -2
- package/lib/dns-resolver-selection.mjs +6 -4
- package/lib/dnssec-chain-validation.mjs +1053 -0
- package/lib/dnssec-evidence-validation.mjs +10 -3
- package/lib/domain-change-packet.mjs +7 -5
- package/lib/domain-control-manifest.mjs +17 -129
- package/lib/domain-posture.mjs +7 -4
- package/lib/evidence-export.mjs +751 -78
- package/lib/evidence-report-markdown.mjs +3 -0
- package/lib/evidence-report.mjs +5 -0
- package/lib/favicon.mjs +8 -5
- package/lib/http-evidence-bounds.mjs +3 -0
- package/lib/http-intelligence.mjs +2 -5
- package/lib/interchange-fidelity-registry.mjs +122 -0
- package/lib/local-geoip-evidence.mjs +2 -1
- package/lib/lookup-network-evidence-bounds.mjs +9 -0
- package/lib/lookup-response-contract.mjs +691 -3
- package/lib/lookup.mjs +2 -2
- package/lib/observation.mjs +7 -6
- package/lib/outbound-identity.mjs +2 -3
- package/lib/perceptual-hash.mjs +12 -4
- package/lib/portable-generator.mjs +21 -0
- package/lib/provider-policy-admission.mjs +9 -4
- package/lib/rdap-normalization.mjs +18 -5
- package/lib/rdap-registrar.mjs +5 -1
- package/lib/registry-capabilities.mjs +3 -0
- package/lib/registry-capability-catalogue.mjs +12 -2
- package/lib/registry-comparison.mjs +28 -11
- package/lib/risk-calibration-summary.mjs +338 -0
- package/lib/rpki-evidence.mjs +9 -8
- package/lib/safe-fetch.mjs +59 -10
- package/lib/security-txt.mjs +26 -3
- package/lib/service-binding-dns.mjs +6 -1
- package/lib/smtp-transport-review.mjs +784 -0
- package/lib/sslbl-certificates.generated.mjs +136 -134
- package/lib/threat-intelligence-runtime.mjs +3 -11
- package/lib/threat-intelligence-types.mjs +18 -1
- package/lib/tls-intelligence.mjs +11 -5
- package/lib/tlsa-evidence.mjs +37 -7
- package/package.json +1 -1
- package/third-party-notices.txt +95 -5817
package/cli/runner.mjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
-
import { createReadStream } from 'node:fs';
|
|
3
2
|
import { createRequire } from 'node:module';
|
|
4
3
|
import { abortable } from "../lib/abort.mjs";
|
|
4
|
+
import { scanBoundedJson } from "../lib/bounded-json.mjs";
|
|
5
5
|
import { REGISTRY_CAPABILITIES_VERSION, registryCapabilityFor } from "../lib/registry-capabilities.mjs";
|
|
6
6
|
import { explainRiskScore, explainRiskScoreV6, RISK_MODEL_VERSION, RISK_REVIEW_THRESHOLD } from "../lib/risk-scoring.mjs";
|
|
7
|
+
import { buildRiskCalibrationSummaryReport } from "../lib/risk-calibration-summary.mjs";
|
|
7
8
|
import { CLI_COMMANDS, parseCliArguments } from "./arguments.mjs";
|
|
8
9
|
import { buildCliCommandCatalogue, formatCliCommandCatalogue } from "./command-catalogue.mjs";
|
|
9
10
|
import { COMMAND_COLLECTION, COMMAND_DETAILS, COMMAND_USAGE, HELP, commandHelp, } from "./command-reference.mjs";
|
|
10
11
|
import { buildShellCompletion } from "./completion.mjs";
|
|
11
12
|
import { buildDoctorReport, formatDoctorReport } from "./doctor.mjs";
|
|
12
|
-
import { MAX_COMPARE_INPUT_BYTES, compareLookupDocument, parseCliLookupDocument,
|
|
13
|
+
import { MAX_COMPARE_INPUT_BYTES, compareLookupDocument, parseCliLookupDocument, } from "./compare.mjs";
|
|
13
14
|
import { boundedCliErrorMessage, CliUsageError } from "./errors.mjs";
|
|
14
15
|
import { evidenceCommandFailureLabel, isEvidenceCommand, runEvidenceCommand, } from "./evidence-command-runner.mjs";
|
|
15
16
|
import { buildCliEvidenceExport, formatCliEvidenceExport } from "./export-evidence.mjs";
|
|
@@ -18,7 +19,7 @@ import { formatLookupEvidenceHtml } from "./formatters/html.mjs";
|
|
|
18
19
|
import { buildCliCompareDocument, formatJsonDocument, } from "./formatters/json.mjs";
|
|
19
20
|
import { formatLookupEvidenceMarkdown } from "./formatters/markdown.mjs";
|
|
20
21
|
import { formatTerminalCompare, formatTerminalRegistrySupport, formatTerminalRiskCalibration, } from "./formatters/terminal.mjs";
|
|
21
|
-
import {
|
|
22
|
+
import { MAX_RETAINED_ARTIFACT_DIFF_BYTES, buildCliRetainedArtifactDiff, formatCliRetainedArtifactDiff, } from "./retained-artifact-diff.mjs";
|
|
22
23
|
import { MAX_LOOKUP_RECONCILIATION_INPUT_BYTES, buildCliLookupReconciliation, formatCliLookupReconciliation, } from "./lookup-reconcile.mjs";
|
|
23
24
|
import { MAX_SHARING_REVIEW_BYTES, buildSharingReview, formatSharingReview, } from "./sharing-review.mjs";
|
|
24
25
|
import { MAX_LOOKUP_TIMELINE_INPUT_BYTES, buildCliLookupTimeline, formatCliLookupTimeline, } from "./lookup-timeline.mjs";
|
|
@@ -27,19 +28,20 @@ import { MAX_MAIL_REVIEW_INPUT_BYTES, buildCliMailReview, formatCliMailReview, }
|
|
|
27
28
|
import { MAX_OFFLINE_EVIDENCE_INPUT_BYTES, buildOfflineEvidenceReview, buildOfflineEvidenceReviewWithLocalResources, formatOfflineEvidenceReview, } from "./offline-evidence-review.mjs";
|
|
28
29
|
import { DOMAIN_CONTROL_MANIFEST_INPUT_SCHEMA, DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, buildDomainControlManifest, formatDomainControlResult, reviewDomainControlManifest, } from "../lib/domain-control-manifest.mjs";
|
|
29
30
|
import { DOMAIN_CONTROL_FLIGHT_RECORDER_INPUT_SCHEMA, buildDomainControlFlightRecorder, formatDomainControlFlightRecorder, } from "../lib/domain-control-flight-recorder.mjs";
|
|
30
|
-
import { CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, buildCliDomainControlReview, formatCliDomainControlReview, } from "./domain-control-observations.mjs";
|
|
31
|
+
import { CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, MAX_DOMAIN_CONTROL_REVIEW_JSON_DEPTH, MAX_DOMAIN_CONTROL_REVIEW_JSON_KEYS, MAX_DOMAIN_CONTROL_REVIEW_JSON_VALUES, buildCliDomainControlReview, formatCliDomainControlReview, } from "./domain-control-observations.mjs";
|
|
31
32
|
import { buildCliLookupBrief, formatCliLookupBrief } from "./lookup-brief.mjs";
|
|
32
33
|
import { buildCliCasePack, formatCliCasePack } from "./case-pack.mjs";
|
|
33
34
|
import { formatDomainControlMonitor, runDomainControlMonitor } from "./domain-control-monitor.mjs";
|
|
34
35
|
import { MAX_ASSURANCE_INPUT_BYTES, buildDomainAssurance, formatDomainAssurance, } from "../lib/domain-assurance.mjs";
|
|
35
36
|
import { MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES, buildDomainChangePacket, formatDomainChangePacket, } from "../lib/domain-change-packet.mjs";
|
|
36
37
|
import { buildCliManual } from "./manual.mjs";
|
|
37
|
-
import { MAX_INVESTIGATION_MANIFEST_ARTIFACT_BYTES, buildInvestigationManifest, formatInvestigationManifest, } from "./investigation-manifest.mjs";
|
|
38
|
+
import { MAX_INVESTIGATION_MANIFEST_ARTIFACT_BYTES, MAX_INVESTIGATION_MANIFEST_TOTAL_BYTES, buildInvestigationManifest, formatInvestigationManifest, } from "./investigation-manifest.mjs";
|
|
38
39
|
import { MAX_EXTERNAL_OBSERVATION_MAPPING_BYTES, mapExternalObservations, formatExternalObservationMapping, } from "./external-observation-mapping.mjs";
|
|
39
40
|
import { buildOpenAssetModelBridge, formatOpenAssetModelBridge, } from "./open-asset-model-bridge.mjs";
|
|
40
41
|
import { MAX_CT_EVENT_INPUT_BYTES, buildCtEventFindings, formatCtEventFindings, } from "./ct-event-intake.mjs";
|
|
41
42
|
import { buildInvestigationPlan, formatInvestigationPlan } from "./investigation-plan.mjs";
|
|
42
|
-
import { formatInvestigationRun, runInvestigationRecipe } from "./investigation-run.mjs";
|
|
43
|
+
import { MAX_INVESTIGATION_RUN_BYTES, formatInvestigationRun, runInvestigationRecipe } from "./investigation-run.mjs";
|
|
44
|
+
import { readCliTextInput } from "./input.mjs";
|
|
43
45
|
import { evaluateCliFailPolicies, formatFailPolicyNotice } from "./fail-policy.mjs";
|
|
44
46
|
import { formatCliJunit } from "./ci-report.mjs";
|
|
45
47
|
import { createBufferedOutput, writePrivateFile } from "./output-file.mjs";
|
|
@@ -48,39 +50,22 @@ import { buildRegistrySupportDocument } from "./registry-support.mjs";
|
|
|
48
50
|
import { buildRegistryDoctorReport, formatRegistryDoctorReport } from "./registry-doctor.mjs";
|
|
49
51
|
import { MAX_REGISTRY_COHORT_INPUT_BYTES, buildRegistryCohortReport, formatRegistryCohortReport, } from "./registry-cohort.mjs";
|
|
50
52
|
import { buildRegistryFixtureScaffold } from "./registry-fixture-scaffold.mjs";
|
|
51
|
-
import { MAX_OFFLINE_ARTIFACT_BYTES, MAX_OFFLINE_PASSPHRASE_FILE_BYTES, formatOfflineArtifactVerification, verifyOfflineArtifact, } from "./artifact-verify.mjs";
|
|
53
|
+
import { MAX_OFFLINE_ARTIFACT_BYTES, MAX_OFFLINE_PASSPHRASE_FILE_BYTES, formatOfflineArtifactVerification, isCompleteOfflineArtifactVerification, verifyOfflineArtifact, } from "./artifact-verify.mjs";
|
|
54
|
+
import { buildInterchangeFidelityReport, formatInterchangeFidelityReport, } from "./interchange-report.mjs";
|
|
52
55
|
import { MAX_SOURCE_RELIABILITY_INPUT_BYTES, buildSourceReliabilityReport, formatSourceReliabilityReport, } from "./source-reliability.mjs";
|
|
53
|
-
import { MAX_RISK_CALIBRATION_INPUT_BYTES, buildRiskCalibrationReport, parseRiskCalibrationDataset,
|
|
56
|
+
import { MAX_RISK_CALIBRATION_INPUT_BYTES, buildRiskCalibrationReport, parseRiskCalibrationDataset, } from "./risk-calibration.mjs";
|
|
54
57
|
import { MAX_LOOKALIKE_CALIBRATION_BYTES, buildLookalikeCalibration, formatLookalikeCalibration, } from "./lookalike-calibration.mjs";
|
|
55
|
-
import { MAX_SAVED_LOOKUP_INPUT_BYTES
|
|
58
|
+
import { MAX_SAVED_LOOKUP_INPUT_BYTES } from "./saved-lookup.mjs";
|
|
56
59
|
import { presentTerminalOutput, terminalPresentation, } from "./terminal-presentation.mjs";
|
|
57
60
|
const require = createRequire(import.meta.url);
|
|
58
61
|
const { version: VERSION } = require('../package.json');
|
|
59
62
|
const MAX_STDIN_BYTES = 4096;
|
|
60
63
|
async function readStdinBounded(stream, limit = MAX_STDIN_BYTES, signal) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
signal?.addEventListener('abort', abort, { once: true });
|
|
67
|
-
const chunks = [];
|
|
68
|
-
let total = 0;
|
|
69
|
-
try {
|
|
70
|
-
for await (const chunk of stream) {
|
|
71
|
-
if (signal?.aborted)
|
|
72
|
-
throw new DOMException('Aborted', 'AbortError');
|
|
73
|
-
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
74
|
-
total += buffer.length;
|
|
75
|
-
if (total > limit)
|
|
76
|
-
throw new CliUsageError(`Standard input is limited to ${limit} bytes.`);
|
|
77
|
-
chunks.push(buffer);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
signal?.removeEventListener('abort', abort);
|
|
82
|
-
}
|
|
83
|
-
const text = Buffer.concat(chunks).toString('utf8').trim();
|
|
64
|
+
const text = (await readCliTextInput(null, stream, {
|
|
65
|
+
maximumBytes: limit,
|
|
66
|
+
label: 'Standard input',
|
|
67
|
+
...(signal ? { signal } : {}),
|
|
68
|
+
})).trim();
|
|
84
69
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
85
70
|
if (lines.length > 1)
|
|
86
71
|
throw new CliUsageError('Single-value commands accept one stdin line. Use the bulk command for multiple inputs.');
|
|
@@ -148,6 +133,29 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
148
133
|
const readSingleInput = async () => (dependencies.readStdin
|
|
149
134
|
? await dependencies.readStdin()
|
|
150
135
|
: await readStdinBounded(dependencies.stdin || process.stdin, MAX_STDIN_BYTES, dependencies.signal));
|
|
136
|
+
const readInput = async (source, maximumBytes, label) => (readCliTextInput(source, dependencies.stdin || process.stdin, {
|
|
137
|
+
maximumBytes,
|
|
138
|
+
label,
|
|
139
|
+
...(dependencies.signal ? { signal: dependencies.signal } : {}),
|
|
140
|
+
}));
|
|
141
|
+
const readPassphraseSource = async (source) => {
|
|
142
|
+
let passphraseText;
|
|
143
|
+
try {
|
|
144
|
+
passphraseText = dependencies.readPassphraseFile
|
|
145
|
+
? await dependencies.readPassphraseFile(source)
|
|
146
|
+
: await readInput(source, MAX_OFFLINE_PASSPHRASE_FILE_BYTES, 'Passphrase file');
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (error instanceof CliUsageError)
|
|
150
|
+
throw error;
|
|
151
|
+
throw new CliUsageError(`Could not read passphrase file: ${boundedCliErrorMessage(error, 'File could not be read')}`);
|
|
152
|
+
}
|
|
153
|
+
const passphrase = passphraseText.replace(/\r?\n$/u, '');
|
|
154
|
+
if (!passphrase || /[\r\n\u0000]/u.test(passphrase)) {
|
|
155
|
+
throw new CliUsageError('Passphrase file must contain exactly one non-empty UTF-8 line.');
|
|
156
|
+
}
|
|
157
|
+
return passphrase;
|
|
158
|
+
};
|
|
151
159
|
const commandContext = Object.freeze({
|
|
152
160
|
stdout,
|
|
153
161
|
stderr,
|
|
@@ -155,6 +163,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
155
163
|
writeStdout: (value) => write(stdout, value),
|
|
156
164
|
writeStderr: (value) => write(stderr, value),
|
|
157
165
|
readSingleInput,
|
|
166
|
+
readInput,
|
|
158
167
|
now: () => dependencies.now ? dependencies.now() : new Date().toISOString(),
|
|
159
168
|
beginProgress,
|
|
160
169
|
endProgress,
|
|
@@ -202,11 +211,16 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
202
211
|
if (args.action === 'manifest') {
|
|
203
212
|
failureLabel = 'Investigation manifest';
|
|
204
213
|
const artifacts = [];
|
|
214
|
+
let totalBytes = 0;
|
|
205
215
|
try {
|
|
206
216
|
for (const source of args.sources) {
|
|
207
217
|
const content = dependencies.readDiffInput
|
|
208
218
|
? await dependencies.readDiffInput(source)
|
|
209
|
-
: await
|
|
219
|
+
: await readInput(source, MAX_INVESTIGATION_MANIFEST_ARTIFACT_BYTES, 'Manifest artefact input');
|
|
220
|
+
totalBytes += Buffer.byteLength(content, 'utf8');
|
|
221
|
+
if (totalBytes > MAX_INVESTIGATION_MANIFEST_TOTAL_BYTES) {
|
|
222
|
+
throw new CliUsageError(`Manifest artefacts exceed the ${MAX_INVESTIGATION_MANIFEST_TOTAL_BYTES}-byte combined limit.`);
|
|
223
|
+
}
|
|
210
224
|
artifacts.push({ content });
|
|
211
225
|
}
|
|
212
226
|
}
|
|
@@ -239,12 +253,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
239
253
|
try {
|
|
240
254
|
input = dependencies.readArtifactInput
|
|
241
255
|
? await dependencies.readArtifactInput(args.source)
|
|
242
|
-
: await
|
|
243
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
244
|
-
: dependencies.stdin || process.stdin, {
|
|
245
|
-
limit: MAX_EXTERNAL_OBSERVATION_MAPPING_BYTES,
|
|
246
|
-
label: mapping ? 'External observation mapping input' : 'Open Asset Model bridge input',
|
|
247
|
-
});
|
|
256
|
+
: await readInput(args.source, MAX_EXTERNAL_OBSERVATION_MAPPING_BYTES, mapping ? 'External observation mapping input' : 'Open Asset Model bridge input');
|
|
248
257
|
}
|
|
249
258
|
catch (error) {
|
|
250
259
|
if (error instanceof CliUsageError)
|
|
@@ -321,12 +330,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
321
330
|
try {
|
|
322
331
|
input = dependencies.readCompareInput
|
|
323
332
|
? await dependencies.readCompareInput(args.source)
|
|
324
|
-
: await
|
|
325
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
326
|
-
: dependencies.stdin || process.stdin, {
|
|
327
|
-
limit: MAX_SAVED_LOOKUP_INPUT_BYTES,
|
|
328
|
-
label: 'Registry doctor input',
|
|
329
|
-
});
|
|
333
|
+
: await readInput(args.source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Registry doctor input');
|
|
330
334
|
}
|
|
331
335
|
catch (error) {
|
|
332
336
|
if (error instanceof CliUsageError)
|
|
@@ -348,12 +352,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
348
352
|
try {
|
|
349
353
|
input = dependencies.readCompareInput
|
|
350
354
|
? await dependencies.readCompareInput(args.source)
|
|
351
|
-
: await
|
|
352
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
353
|
-
: dependencies.stdin || process.stdin, {
|
|
354
|
-
limit: MAX_REGISTRY_COHORT_INPUT_BYTES,
|
|
355
|
-
label: 'Registry cohort input',
|
|
356
|
-
});
|
|
355
|
+
: await readInput(args.source, MAX_REGISTRY_COHORT_INPUT_BYTES, 'Registry cohort input');
|
|
357
356
|
}
|
|
358
357
|
catch (error) {
|
|
359
358
|
if (error instanceof CliUsageError)
|
|
@@ -385,9 +384,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
385
384
|
try {
|
|
386
385
|
input = dependencies.readRiskCalibrationInput
|
|
387
386
|
? await dependencies.readRiskCalibrationInput(args.source)
|
|
388
|
-
: await
|
|
389
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
390
|
-
: dependencies.stdin || process.stdin, MAX_RISK_CALIBRATION_INPUT_BYTES);
|
|
387
|
+
: await readInput(args.source, MAX_RISK_CALIBRATION_INPUT_BYTES, 'Risk calibration input');
|
|
391
388
|
}
|
|
392
389
|
catch (error) {
|
|
393
390
|
if (error instanceof CliUsageError)
|
|
@@ -407,7 +404,11 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
407
404
|
} : {}),
|
|
408
405
|
});
|
|
409
406
|
if (!args.quiet)
|
|
410
|
-
write(stdout, args.output === '
|
|
407
|
+
write(stdout, args.output === 'summary_json'
|
|
408
|
+
? formatJsonDocument(buildRiskCalibrationSummaryReport(report))
|
|
409
|
+
: args.output === 'json'
|
|
410
|
+
? formatJsonDocument(report)
|
|
411
|
+
: terminal(formatTerminalRiskCalibration(report), args.color));
|
|
411
412
|
return EXIT_CODES.SUCCESS;
|
|
412
413
|
}
|
|
413
414
|
if (args.action === 'lookalike-calibrate') {
|
|
@@ -416,12 +417,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
416
417
|
try {
|
|
417
418
|
input = dependencies.readRiskCalibrationInput
|
|
418
419
|
? await dependencies.readRiskCalibrationInput(args.source)
|
|
419
|
-
: await
|
|
420
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
421
|
-
: dependencies.stdin || process.stdin, {
|
|
422
|
-
limit: MAX_LOOKALIKE_CALIBRATION_BYTES,
|
|
423
|
-
label: 'Lookalike calibration input',
|
|
424
|
-
});
|
|
420
|
+
: await readInput(args.source, MAX_LOOKALIKE_CALIBRATION_BYTES, 'Lookalike calibration input');
|
|
425
421
|
}
|
|
426
422
|
catch (error) {
|
|
427
423
|
if (error instanceof CliUsageError)
|
|
@@ -449,12 +445,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
449
445
|
try {
|
|
450
446
|
input = dependencies.readArtifactInput
|
|
451
447
|
? await dependencies.readArtifactInput(args.source)
|
|
452
|
-
: await
|
|
453
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
454
|
-
: dependencies.stdin || process.stdin, {
|
|
455
|
-
limit: MAX_OFFLINE_ARTIFACT_BYTES,
|
|
456
|
-
label: 'Artefact input',
|
|
457
|
-
});
|
|
448
|
+
: await readInput(args.source, MAX_OFFLINE_ARTIFACT_BYTES, 'Artefact input');
|
|
458
449
|
}
|
|
459
450
|
catch (error) {
|
|
460
451
|
if (error instanceof CliUsageError)
|
|
@@ -463,33 +454,58 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
463
454
|
}
|
|
464
455
|
if (!input.trim())
|
|
465
456
|
throw new CliUsageError('verify-artifact requires one JSON file or an artefact on stdin.');
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
457
|
+
const passphrase = args.passphraseSource ? await readPassphraseSource(args.passphraseSource) : null;
|
|
458
|
+
let manifest = null;
|
|
459
|
+
if (args.manifestSource && args.manifestEntryId) {
|
|
460
|
+
let raw;
|
|
469
461
|
try {
|
|
470
|
-
|
|
471
|
-
? await dependencies.
|
|
472
|
-
: await
|
|
473
|
-
limit: MAX_OFFLINE_PASSPHRASE_FILE_BYTES,
|
|
474
|
-
label: 'Passphrase file',
|
|
475
|
-
});
|
|
462
|
+
raw = dependencies.readArtifactInput
|
|
463
|
+
? await dependencies.readArtifactInput(args.manifestSource)
|
|
464
|
+
: await readInput(args.manifestSource, MAX_OFFLINE_ARTIFACT_BYTES, 'Investigation manifest input');
|
|
476
465
|
}
|
|
477
466
|
catch (error) {
|
|
478
467
|
if (error instanceof CliUsageError)
|
|
479
468
|
throw error;
|
|
480
|
-
throw new CliUsageError(`Could not read
|
|
481
|
-
}
|
|
482
|
-
passphrase = passphraseText.replace(/\r?\n$/u, '');
|
|
483
|
-
if (!passphrase || /[\r\n\u0000]/u.test(passphrase)) {
|
|
484
|
-
throw new CliUsageError('Passphrase file must contain exactly one non-empty UTF-8 line.');
|
|
469
|
+
throw new CliUsageError(`Could not read investigation manifest input: ${boundedCliErrorMessage(error, 'Input could not be read')}`);
|
|
485
470
|
}
|
|
471
|
+
if (!raw.trim())
|
|
472
|
+
throw new CliUsageError('The investigation manifest input is empty.');
|
|
473
|
+
manifest = Object.freeze({ raw, entryId: args.manifestEntryId });
|
|
486
474
|
}
|
|
487
|
-
const report = await verifyOfflineArtifact(input, { passphrase });
|
|
475
|
+
const report = await verifyOfflineArtifact(input, { passphrase, manifest });
|
|
488
476
|
if (!args.quiet) {
|
|
489
477
|
write(stdout, args.output === 'json'
|
|
490
478
|
? formatJsonDocument(report)
|
|
491
479
|
: terminal(formatOfflineArtifactVerification(report), args.color));
|
|
492
480
|
}
|
|
481
|
+
return args.strictExit && !isCompleteOfflineArtifactVerification(report)
|
|
482
|
+
? EXIT_CODES.PARTIAL_FAILURE
|
|
483
|
+
: EXIT_CODES.SUCCESS;
|
|
484
|
+
}
|
|
485
|
+
if (args.action === 'interchange-report') {
|
|
486
|
+
failureLabel = 'Interchange fidelity report';
|
|
487
|
+
let input;
|
|
488
|
+
try {
|
|
489
|
+
input = dependencies.readArtifactInput
|
|
490
|
+
? await dependencies.readArtifactInput(args.source)
|
|
491
|
+
: await readInput(args.source, MAX_OFFLINE_ARTIFACT_BYTES, 'Interchange input');
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
if (error instanceof CliUsageError)
|
|
495
|
+
throw error;
|
|
496
|
+
throw new CliUsageError(`Could not read interchange input: ${boundedCliErrorMessage(error, 'Input could not be read')}`);
|
|
497
|
+
}
|
|
498
|
+
if (!input.trim())
|
|
499
|
+
throw new CliUsageError('interchange-report requires one JSON file or an artefact on stdin.');
|
|
500
|
+
const passphrase = args.passphraseSource ? await readPassphraseSource(args.passphraseSource) : null;
|
|
501
|
+
const report = await buildInterchangeFidelityReport(input, {
|
|
502
|
+
generatedAt: commandContext.now(),
|
|
503
|
+
passphrase,
|
|
504
|
+
});
|
|
505
|
+
if (!args.quiet)
|
|
506
|
+
write(stdout, args.output === 'json'
|
|
507
|
+
? formatJsonDocument(report)
|
|
508
|
+
: terminal(formatInterchangeFidelityReport(report), args.color));
|
|
493
509
|
return EXIT_CODES.SUCCESS;
|
|
494
510
|
}
|
|
495
511
|
if (isEvidenceCommand(args)) {
|
|
@@ -505,6 +521,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
505
521
|
readPrivateKeyFile: dependencies.readPrivateKeyFile,
|
|
506
522
|
readPublicKeyFile: dependencies.readPublicKeyFile,
|
|
507
523
|
now: dependencies.now,
|
|
524
|
+
signal: dependencies.signal,
|
|
508
525
|
});
|
|
509
526
|
}
|
|
510
527
|
if (args.action === 'source-report') {
|
|
@@ -513,12 +530,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
513
530
|
try {
|
|
514
531
|
input = dependencies.readSourceReliabilityInput
|
|
515
532
|
? await dependencies.readSourceReliabilityInput(args.source)
|
|
516
|
-
: await
|
|
517
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
518
|
-
: dependencies.stdin || process.stdin, {
|
|
519
|
-
limit: MAX_SOURCE_RELIABILITY_INPUT_BYTES,
|
|
520
|
-
label: 'Source reliability input',
|
|
521
|
-
});
|
|
533
|
+
: await readInput(args.source, MAX_SOURCE_RELIABILITY_INPUT_BYTES, 'Source reliability input');
|
|
522
534
|
}
|
|
523
535
|
catch (error) {
|
|
524
536
|
if (error instanceof CliUsageError)
|
|
@@ -541,9 +553,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
541
553
|
try {
|
|
542
554
|
input = dependencies.readCompareInput
|
|
543
555
|
? await dependencies.readCompareInput(args.source)
|
|
544
|
-
: await
|
|
545
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
546
|
-
: dependencies.stdin || process.stdin, MAX_COMPARE_INPUT_BYTES);
|
|
556
|
+
: await readInput(args.source, MAX_COMPARE_INPUT_BYTES, 'Comparison input');
|
|
547
557
|
}
|
|
548
558
|
catch (error) {
|
|
549
559
|
if (error instanceof CliUsageError)
|
|
@@ -564,10 +574,8 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
564
574
|
}
|
|
565
575
|
if (args.action === 'page-compare') {
|
|
566
576
|
failureLabel = 'Static page comparison';
|
|
567
|
-
const readDiffInput = dependencies.readDiffInput
|
|
568
|
-
|
|
569
|
-
label: 'Page comparison input',
|
|
570
|
-
})));
|
|
577
|
+
const readDiffInput = dependencies.readDiffInput
|
|
578
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Page comparison input'));
|
|
571
579
|
let leftInput;
|
|
572
580
|
let rightInput;
|
|
573
581
|
try {
|
|
@@ -594,12 +602,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
594
602
|
try {
|
|
595
603
|
input = dependencies.readMailReviewInput
|
|
596
604
|
? await dependencies.readMailReviewInput(args.source)
|
|
597
|
-
: await
|
|
598
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
599
|
-
: dependencies.stdin || process.stdin, {
|
|
600
|
-
limit: MAX_MAIL_REVIEW_INPUT_BYTES,
|
|
601
|
-
label: 'Mail review input',
|
|
602
|
-
});
|
|
605
|
+
: await readInput(args.source, MAX_MAIL_REVIEW_INPUT_BYTES, 'Mail review input');
|
|
603
606
|
}
|
|
604
607
|
catch (error) {
|
|
605
608
|
if (error instanceof CliUsageError)
|
|
@@ -619,12 +622,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
619
622
|
try {
|
|
620
623
|
input = dependencies.readArtifactInput
|
|
621
624
|
? await dependencies.readArtifactInput(args.source)
|
|
622
|
-
: await
|
|
623
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
624
|
-
: dependencies.stdin || process.stdin, {
|
|
625
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
626
|
-
label: 'Offline evidence input',
|
|
627
|
-
});
|
|
625
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Offline evidence input');
|
|
628
626
|
}
|
|
629
627
|
catch (error) {
|
|
630
628
|
if (error instanceof CliUsageError)
|
|
@@ -662,12 +660,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
662
660
|
try {
|
|
663
661
|
input = dependencies.readArtifactInput
|
|
664
662
|
? await dependencies.readArtifactInput(args.source)
|
|
665
|
-
: await
|
|
666
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
667
|
-
: dependencies.stdin || process.stdin, {
|
|
668
|
-
limit: isBrief ? MAX_SAVED_LOOKUP_INPUT_BYTES : 4 * 1024 * 1024,
|
|
669
|
-
label: isBrief ? 'Lookup brief input' : 'Case-pack input',
|
|
670
|
-
});
|
|
663
|
+
: await readInput(args.source, isBrief ? MAX_SAVED_LOOKUP_INPUT_BYTES : 4 * 1024 * 1024, isBrief ? 'Lookup brief input' : 'Case-pack input');
|
|
671
664
|
}
|
|
672
665
|
catch (error) {
|
|
673
666
|
if (error instanceof CliUsageError)
|
|
@@ -698,12 +691,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
698
691
|
try {
|
|
699
692
|
input = dependencies.readArtifactInput
|
|
700
693
|
? await dependencies.readArtifactInput(args.source)
|
|
701
|
-
: await
|
|
702
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
703
|
-
: dependencies.stdin || process.stdin, {
|
|
704
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
705
|
-
label: 'Domain control input',
|
|
706
|
-
});
|
|
694
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Domain control input');
|
|
707
695
|
}
|
|
708
696
|
catch (error) {
|
|
709
697
|
if (error instanceof CliUsageError)
|
|
@@ -712,11 +700,21 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
712
700
|
}
|
|
713
701
|
if (!input.trim())
|
|
714
702
|
throw new CliUsageError('domain-control requires one JSON file or a document on stdin.');
|
|
703
|
+
const normalizedDomainControlInput = input.replace(/^\uFEFF/u, '');
|
|
715
704
|
let parsed;
|
|
716
705
|
try {
|
|
717
|
-
|
|
706
|
+
scanBoundedJson(normalizedDomainControlInput, {
|
|
707
|
+
maximumDepth: MAX_DOMAIN_CONTROL_REVIEW_JSON_DEPTH,
|
|
708
|
+
maximumKeys: MAX_DOMAIN_CONTROL_REVIEW_JSON_KEYS,
|
|
709
|
+
maximumValues: MAX_DOMAIN_CONTROL_REVIEW_JSON_VALUES,
|
|
710
|
+
});
|
|
711
|
+
parsed = JSON.parse(normalizedDomainControlInput);
|
|
718
712
|
}
|
|
719
|
-
catch {
|
|
713
|
+
catch (cause) {
|
|
714
|
+
const detail = cause instanceof Error ? cause.message : '';
|
|
715
|
+
if (detail.startsWith('Artefact JSON ')) {
|
|
716
|
+
throw new CliUsageError(`Domain control input ${detail.slice('Artefact JSON '.length)}`);
|
|
717
|
+
}
|
|
720
718
|
throw new CliUsageError('Domain control input is not valid JSON.');
|
|
721
719
|
}
|
|
722
720
|
const schema = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
@@ -752,19 +750,11 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
752
750
|
try {
|
|
753
751
|
manifestInput = dependencies.readArtifactInput
|
|
754
752
|
? await dependencies.readArtifactInput(args.source)
|
|
755
|
-
: await
|
|
756
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
757
|
-
: dependencies.stdin || process.stdin, {
|
|
758
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
759
|
-
label: 'Domain-control manifest input',
|
|
760
|
-
});
|
|
753
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Domain-control manifest input');
|
|
761
754
|
if (args.previousSource) {
|
|
762
755
|
previousInput = dependencies.readDiffInput
|
|
763
756
|
? await dependencies.readDiffInput(args.previousSource)
|
|
764
|
-
: await
|
|
765
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
766
|
-
label: 'Prior monitor snapshot',
|
|
767
|
-
});
|
|
757
|
+
: await readInput(args.previousSource, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Prior monitor snapshot');
|
|
768
758
|
}
|
|
769
759
|
}
|
|
770
760
|
catch (error) {
|
|
@@ -807,12 +797,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
807
797
|
try {
|
|
808
798
|
input = dependencies.readArtifactInput
|
|
809
799
|
? await dependencies.readArtifactInput(args.source)
|
|
810
|
-
: await
|
|
811
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
812
|
-
: dependencies.stdin || process.stdin, {
|
|
813
|
-
limit: MAX_ASSURANCE_INPUT_BYTES,
|
|
814
|
-
label: 'Domain assurance input',
|
|
815
|
-
});
|
|
800
|
+
: await readInput(args.source, MAX_ASSURANCE_INPUT_BYTES, 'Domain assurance input');
|
|
816
801
|
}
|
|
817
802
|
catch (error) {
|
|
818
803
|
if (error instanceof CliUsageError)
|
|
@@ -847,12 +832,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
847
832
|
try {
|
|
848
833
|
input = dependencies.readArtifactInput
|
|
849
834
|
? await dependencies.readArtifactInput(args.source)
|
|
850
|
-
: await
|
|
851
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
852
|
-
: dependencies.stdin || process.stdin, {
|
|
853
|
-
limit: MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES,
|
|
854
|
-
label: 'Domain change packet input',
|
|
855
|
-
});
|
|
835
|
+
: await readInput(args.source, MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES, 'Domain change packet input');
|
|
856
836
|
}
|
|
857
837
|
catch (error) {
|
|
858
838
|
if (error instanceof CliUsageError)
|
|
@@ -887,12 +867,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
887
867
|
try {
|
|
888
868
|
input = dependencies.readArtifactInput
|
|
889
869
|
? await dependencies.readArtifactInput(args.source)
|
|
890
|
-
: await
|
|
891
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
892
|
-
: dependencies.stdin || process.stdin, {
|
|
893
|
-
limit: MAX_SHARING_REVIEW_BYTES,
|
|
894
|
-
label: 'Sharing review input',
|
|
895
|
-
});
|
|
870
|
+
: await readInput(args.source, MAX_SHARING_REVIEW_BYTES, 'Sharing review input');
|
|
896
871
|
}
|
|
897
872
|
catch (error) {
|
|
898
873
|
if (error instanceof CliUsageError)
|
|
@@ -937,10 +912,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
937
912
|
try {
|
|
938
913
|
resumeInput = dependencies.readDiffInput
|
|
939
914
|
? await dependencies.readDiffInput(args.resumeSource)
|
|
940
|
-
: await
|
|
941
|
-
limit: 24 * 1024 * 1024,
|
|
942
|
-
label: 'Investigation resume state',
|
|
943
|
-
});
|
|
915
|
+
: await readInput(args.resumeSource, MAX_INVESTIGATION_RUN_BYTES, 'Investigation resume state');
|
|
944
916
|
}
|
|
945
917
|
catch (error) {
|
|
946
918
|
if (error instanceof CliUsageError)
|
|
@@ -970,11 +942,9 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
970
942
|
return document.state === 'step_failed' ? EXIT_CODES.PARTIAL_FAILURE : EXIT_CODES.SUCCESS;
|
|
971
943
|
}
|
|
972
944
|
if (args.action === 'diff') {
|
|
973
|
-
failureLabel = '
|
|
974
|
-
const readDiffInput = dependencies.readDiffInput
|
|
975
|
-
|
|
976
|
-
label: 'Lookup diff input',
|
|
977
|
-
})));
|
|
945
|
+
failureLabel = 'Retained artifact diff';
|
|
946
|
+
const readDiffInput = dependencies.readDiffInput
|
|
947
|
+
|| ((source) => readInput(source, MAX_RETAINED_ARTIFACT_DIFF_BYTES, 'Retained diff input'));
|
|
978
948
|
let leftInput;
|
|
979
949
|
let rightInput;
|
|
980
950
|
try {
|
|
@@ -986,21 +956,19 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
986
956
|
catch (error) {
|
|
987
957
|
if (error instanceof CliUsageError)
|
|
988
958
|
throw error;
|
|
989
|
-
throw new CliUsageError(`Could not read
|
|
959
|
+
throw new CliUsageError(`Could not read retained diff input: ${boundedCliErrorMessage(error, 'Input could not be read')}`);
|
|
990
960
|
}
|
|
991
|
-
const document =
|
|
961
|
+
const document = buildCliRetainedArtifactDiff(leftInput, rightInput, { leftSessionId: args.leftSessionId, rightSessionId: args.rightSessionId }, dependencies.now ? dependencies.now() : new Date().toISOString());
|
|
992
962
|
if (!args.quiet)
|
|
993
963
|
write(stdout, args.output === 'json'
|
|
994
964
|
? formatJsonDocument(document)
|
|
995
|
-
: terminal(
|
|
965
|
+
: terminal(formatCliRetainedArtifactDiff(document), args.color));
|
|
996
966
|
return EXIT_CODES.SUCCESS;
|
|
997
967
|
}
|
|
998
968
|
if (args.action === 'reconcile') {
|
|
999
969
|
failureLabel = 'Lookup observation reconciliation';
|
|
1000
|
-
const readReconciliationInput = dependencies.readDiffInput
|
|
1001
|
-
|
|
1002
|
-
label: 'Lookup reconciliation input',
|
|
1003
|
-
})));
|
|
970
|
+
const readReconciliationInput = dependencies.readDiffInput
|
|
971
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Lookup reconciliation input'));
|
|
1004
972
|
const inputs = [];
|
|
1005
973
|
let totalBytes = 0;
|
|
1006
974
|
try {
|
|
@@ -1027,10 +995,8 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1027
995
|
}
|
|
1028
996
|
if (args.action === 'timeline') {
|
|
1029
997
|
failureLabel = 'Lookup observation timeline';
|
|
1030
|
-
const readTimelineInput = dependencies.readDiffInput
|
|
1031
|
-
|
|
1032
|
-
label: 'Lookup timeline input',
|
|
1033
|
-
})));
|
|
998
|
+
const readTimelineInput = dependencies.readDiffInput
|
|
999
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Lookup timeline input'));
|
|
1034
1000
|
const inputs = [];
|
|
1035
1001
|
let totalBytes = 0;
|
|
1036
1002
|
try {
|
|
@@ -1061,12 +1027,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1061
1027
|
try {
|
|
1062
1028
|
input = dependencies.readExportInput
|
|
1063
1029
|
? await dependencies.readExportInput(args.source)
|
|
1064
|
-
: await
|
|
1065
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
1066
|
-
: dependencies.stdin || process.stdin, {
|
|
1067
|
-
limit: MAX_SAVED_LOOKUP_INPUT_BYTES,
|
|
1068
|
-
label: 'Evidence export input',
|
|
1069
|
-
});
|
|
1030
|
+
: await readInput(args.source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Evidence export input');
|
|
1070
1031
|
}
|
|
1071
1032
|
catch (error) {
|
|
1072
1033
|
if (error instanceof CliUsageError)
|
|
@@ -1080,9 +1041,9 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1080
1041
|
const now = dependencies.now ? dependencies.now() : new Date().toISOString();
|
|
1081
1042
|
const document = buildCliEvidenceExport(input, evidenceModule, now);
|
|
1082
1043
|
const output = args.format === 'markdown'
|
|
1083
|
-
? formatLookupEvidenceMarkdown(document)
|
|
1044
|
+
? formatLookupEvidenceMarkdown(document, { includeAttribution: args.includeAttribution })
|
|
1084
1045
|
: args.format === 'html'
|
|
1085
|
-
? formatLookupEvidenceHtml(document)
|
|
1046
|
+
? formatLookupEvidenceHtml(document, { includeAttribution: args.includeAttribution })
|
|
1086
1047
|
: formatCliEvidenceExport(document, args.compact);
|
|
1087
1048
|
write(stdout, output);
|
|
1088
1049
|
return EXIT_CODES.SUCCESS;
|
|
@@ -1108,12 +1069,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1108
1069
|
try {
|
|
1109
1070
|
input = dependencies.readArtifactInput
|
|
1110
1071
|
? await dependencies.readArtifactInput(args.source)
|
|
1111
|
-
: await
|
|
1112
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
1113
|
-
: dependencies.stdin || process.stdin, {
|
|
1114
|
-
limit: MAX_CT_EVENT_INPUT_BYTES,
|
|
1115
|
-
label: 'Certificate event input',
|
|
1116
|
-
});
|
|
1072
|
+
: await readInput(args.source, MAX_CT_EVENT_INPUT_BYTES, 'Certificate event input');
|
|
1117
1073
|
}
|
|
1118
1074
|
catch (error) {
|
|
1119
1075
|
if (error instanceof CliUsageError)
|
|
@@ -1145,14 +1101,20 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1145
1101
|
if (args.action === 'ct-search'
|
|
1146
1102
|
|| args.action === 'posture'
|
|
1147
1103
|
|| args.action === 'http'
|
|
1148
|
-
|| args.action === 'tls'
|
|
1104
|
+
|| args.action === 'tls'
|
|
1105
|
+
|| args.action === 'dnssec-validate'
|
|
1106
|
+
|| args.action === 'mail-transport') {
|
|
1149
1107
|
failureLabel = args.action === 'ct-search'
|
|
1150
1108
|
? 'Certificate Transparency search'
|
|
1151
1109
|
: args.action === 'posture'
|
|
1152
1110
|
? 'Domain posture audit'
|
|
1153
1111
|
: args.action === 'http'
|
|
1154
1112
|
? 'HTTP probe'
|
|
1155
|
-
:
|
|
1113
|
+
: args.action === 'tls'
|
|
1114
|
+
? 'TLS intelligence'
|
|
1115
|
+
: args.action === 'dnssec-validate'
|
|
1116
|
+
? 'DNSSEC chain validation'
|
|
1117
|
+
: 'Mail transport review';
|
|
1156
1118
|
const { runNetworkCommand } = await import("./network-command-runner.mjs");
|
|
1157
1119
|
return await runNetworkCommand(args, dependencies, commandContext);
|
|
1158
1120
|
}
|