@slicedearth/whoisleuth-cli 1.43.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 +67 -10
- package/bin/whoisleuth.mjs +22 -9
- 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 +67 -31
- package/cli/bulk-command-runner.mjs +16 -6
- package/cli/bulk.mjs +18 -7
- package/cli/case-pack.mjs +819 -34
- package/cli/command-reference.mjs +48 -24
- package/cli/completion.mjs +50 -11
- package/cli/config-profile.mjs +15 -12
- package/cli/ct-event-intake.mjs +32 -2
- package/cli/discovery-observation-snapshot.mjs +8 -14
- package/cli/discovery-scan-command-runner.mjs +18 -6
- package/cli/discovery-snapshot.mjs +8 -15
- 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/errors.mjs +7 -1
- 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/json.mjs +12 -4
- package/cli/formatters/terminal.mjs +4 -1
- package/cli/http.mjs +2 -1
- 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/lookup-reconcile.mjs +1 -1
- package/cli/mail-review.mjs +5 -5
- package/cli/manual.mjs +1 -1
- 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-fixture-scaffold.mjs +4 -3
- 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 +150 -177
- package/cli/saved-lookup.mjs +26 -3
- package/cli/sharing-review.mjs +12 -6
- package/docs/cli-reference.md +467 -74
- package/docs/cli.md +25 -5
- package/frontend/src/lib/analysis/acquisition-decision-packet.js +4 -4
- package/frontend/src/lib/analysis/acquisition-due-diligence.js +1 -1
- package/frontend/src/lib/analysis/artifact-integrity.js +42 -0
- package/frontend/src/lib/analysis/brand-profile-model.js +33 -7
- 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 +9 -1
- 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-core.js +1 -1
- package/frontend/src/lib/analysis/case-record-model.js +2 -0
- package/frontend/src/lib/analysis/case-record-operations.js +43 -13
- 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-asset-graph.js +8 -8
- 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 +63 -8
- package/frontend/src/lib/analysis/lookup-presentation.js +70 -14
- package/frontend/src/lib/analysis/lookup-source-refresh.js +36 -63
- package/frontend/src/lib/analysis/opaque-reference-id.js +9 -0
- package/frontend/src/lib/analysis/utils.js +27 -4
- 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-crypto.js +1 -4
- package/frontend/src/lib/analysis/workspace-archive.js +105 -19
- package/lib/application-version.mjs +3 -0
- package/lib/availability.mjs +14 -12
- package/lib/bounded-file.mjs +82 -0
- package/lib/bounded-json-response.mjs +170 -0
- package/lib/bounded-json.mjs +249 -0
- package/lib/browser-library-profile.mjs +167 -38
- 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-cache.mjs +5 -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/rdap-transport.mjs +6 -6
- 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 +96 -42
- 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 +4 -13
- package/lib/threat-intelligence-types.mjs +18 -1
- package/lib/tls-intelligence.mjs +11 -5
- package/lib/tlsa-evidence.mjs +37 -7
- package/lib/website-technology.mjs +2 -6
- 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,28 +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
|
-
async function readStdinBounded(stream, limit = MAX_STDIN_BYTES) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
67
|
-
total += buffer.length;
|
|
68
|
-
if (total > limit)
|
|
69
|
-
throw new CliUsageError(`Standard input is limited to ${limit} bytes.`);
|
|
70
|
-
chunks.push(buffer);
|
|
71
|
-
}
|
|
72
|
-
const text = Buffer.concat(chunks).toString('utf8').trim();
|
|
63
|
+
async function readStdinBounded(stream, limit = MAX_STDIN_BYTES, signal) {
|
|
64
|
+
const text = (await readCliTextInput(null, stream, {
|
|
65
|
+
maximumBytes: limit,
|
|
66
|
+
label: 'Standard input',
|
|
67
|
+
...(signal ? { signal } : {}),
|
|
68
|
+
})).trim();
|
|
73
69
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
74
70
|
if (lines.length > 1)
|
|
75
71
|
throw new CliUsageError('Single-value commands accept one stdin line. Use the bulk command for multiple inputs.');
|
|
@@ -136,7 +132,30 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
136
132
|
};
|
|
137
133
|
const readSingleInput = async () => (dependencies.readStdin
|
|
138
134
|
? await dependencies.readStdin()
|
|
139
|
-
: await readStdinBounded(dependencies.stdin || process.stdin));
|
|
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
|
+
};
|
|
140
159
|
const commandContext = Object.freeze({
|
|
141
160
|
stdout,
|
|
142
161
|
stderr,
|
|
@@ -144,6 +163,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
144
163
|
writeStdout: (value) => write(stdout, value),
|
|
145
164
|
writeStderr: (value) => write(stderr, value),
|
|
146
165
|
readSingleInput,
|
|
166
|
+
readInput,
|
|
147
167
|
now: () => dependencies.now ? dependencies.now() : new Date().toISOString(),
|
|
148
168
|
beginProgress,
|
|
149
169
|
endProgress,
|
|
@@ -191,11 +211,16 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
191
211
|
if (args.action === 'manifest') {
|
|
192
212
|
failureLabel = 'Investigation manifest';
|
|
193
213
|
const artifacts = [];
|
|
214
|
+
let totalBytes = 0;
|
|
194
215
|
try {
|
|
195
216
|
for (const source of args.sources) {
|
|
196
217
|
const content = dependencies.readDiffInput
|
|
197
218
|
? await dependencies.readDiffInput(source)
|
|
198
|
-
: 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
|
+
}
|
|
199
224
|
artifacts.push({ content });
|
|
200
225
|
}
|
|
201
226
|
}
|
|
@@ -228,12 +253,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
228
253
|
try {
|
|
229
254
|
input = dependencies.readArtifactInput
|
|
230
255
|
? await dependencies.readArtifactInput(args.source)
|
|
231
|
-
: await
|
|
232
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
233
|
-
: dependencies.stdin || process.stdin, {
|
|
234
|
-
limit: MAX_EXTERNAL_OBSERVATION_MAPPING_BYTES,
|
|
235
|
-
label: mapping ? 'External observation mapping input' : 'Open Asset Model bridge input',
|
|
236
|
-
});
|
|
256
|
+
: await readInput(args.source, MAX_EXTERNAL_OBSERVATION_MAPPING_BYTES, mapping ? 'External observation mapping input' : 'Open Asset Model bridge input');
|
|
237
257
|
}
|
|
238
258
|
catch (error) {
|
|
239
259
|
if (error instanceof CliUsageError)
|
|
@@ -289,7 +309,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
289
309
|
}
|
|
290
310
|
if (args.action === 'registry-support') {
|
|
291
311
|
failureLabel = 'Registry support';
|
|
292
|
-
const readInput = dependencies.readStdin || (() => readStdinBounded(dependencies.stdin || process.stdin));
|
|
312
|
+
const readInput = dependencies.readStdin || (() => readStdinBounded(dependencies.stdin || process.stdin, MAX_STDIN_BYTES, dependencies.signal));
|
|
293
313
|
const requestedInput = args.target || await readInput();
|
|
294
314
|
if (!requestedInput)
|
|
295
315
|
throw new CliUsageError('registry-support requires one domain or suffix as an argument or on stdin.');
|
|
@@ -310,12 +330,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
310
330
|
try {
|
|
311
331
|
input = dependencies.readCompareInput
|
|
312
332
|
? await dependencies.readCompareInput(args.source)
|
|
313
|
-
: await
|
|
314
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
315
|
-
: dependencies.stdin || process.stdin, {
|
|
316
|
-
limit: MAX_SAVED_LOOKUP_INPUT_BYTES,
|
|
317
|
-
label: 'Registry doctor input',
|
|
318
|
-
});
|
|
333
|
+
: await readInput(args.source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Registry doctor input');
|
|
319
334
|
}
|
|
320
335
|
catch (error) {
|
|
321
336
|
if (error instanceof CliUsageError)
|
|
@@ -337,12 +352,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
337
352
|
try {
|
|
338
353
|
input = dependencies.readCompareInput
|
|
339
354
|
? await dependencies.readCompareInput(args.source)
|
|
340
|
-
: await
|
|
341
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
342
|
-
: dependencies.stdin || process.stdin, {
|
|
343
|
-
limit: MAX_REGISTRY_COHORT_INPUT_BYTES,
|
|
344
|
-
label: 'Registry cohort input',
|
|
345
|
-
});
|
|
355
|
+
: await readInput(args.source, MAX_REGISTRY_COHORT_INPUT_BYTES, 'Registry cohort input');
|
|
346
356
|
}
|
|
347
357
|
catch (error) {
|
|
348
358
|
if (error instanceof CliUsageError)
|
|
@@ -374,9 +384,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
374
384
|
try {
|
|
375
385
|
input = dependencies.readRiskCalibrationInput
|
|
376
386
|
? await dependencies.readRiskCalibrationInput(args.source)
|
|
377
|
-
: await
|
|
378
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
379
|
-
: dependencies.stdin || process.stdin, MAX_RISK_CALIBRATION_INPUT_BYTES);
|
|
387
|
+
: await readInput(args.source, MAX_RISK_CALIBRATION_INPUT_BYTES, 'Risk calibration input');
|
|
380
388
|
}
|
|
381
389
|
catch (error) {
|
|
382
390
|
if (error instanceof CliUsageError)
|
|
@@ -396,7 +404,11 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
396
404
|
} : {}),
|
|
397
405
|
});
|
|
398
406
|
if (!args.quiet)
|
|
399
|
-
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));
|
|
400
412
|
return EXIT_CODES.SUCCESS;
|
|
401
413
|
}
|
|
402
414
|
if (args.action === 'lookalike-calibrate') {
|
|
@@ -405,12 +417,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
405
417
|
try {
|
|
406
418
|
input = dependencies.readRiskCalibrationInput
|
|
407
419
|
? await dependencies.readRiskCalibrationInput(args.source)
|
|
408
|
-
: await
|
|
409
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
410
|
-
: dependencies.stdin || process.stdin, {
|
|
411
|
-
limit: MAX_LOOKALIKE_CALIBRATION_BYTES,
|
|
412
|
-
label: 'Lookalike calibration input',
|
|
413
|
-
});
|
|
420
|
+
: await readInput(args.source, MAX_LOOKALIKE_CALIBRATION_BYTES, 'Lookalike calibration input');
|
|
414
421
|
}
|
|
415
422
|
catch (error) {
|
|
416
423
|
if (error instanceof CliUsageError)
|
|
@@ -438,12 +445,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
438
445
|
try {
|
|
439
446
|
input = dependencies.readArtifactInput
|
|
440
447
|
? await dependencies.readArtifactInput(args.source)
|
|
441
|
-
: await
|
|
442
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
443
|
-
: dependencies.stdin || process.stdin, {
|
|
444
|
-
limit: MAX_OFFLINE_ARTIFACT_BYTES,
|
|
445
|
-
label: 'Artefact input',
|
|
446
|
-
});
|
|
448
|
+
: await readInput(args.source, MAX_OFFLINE_ARTIFACT_BYTES, 'Artefact input');
|
|
447
449
|
}
|
|
448
450
|
catch (error) {
|
|
449
451
|
if (error instanceof CliUsageError)
|
|
@@ -452,33 +454,58 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
452
454
|
}
|
|
453
455
|
if (!input.trim())
|
|
454
456
|
throw new CliUsageError('verify-artifact requires one JSON file or an artefact on stdin.');
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
457
|
+
const passphrase = args.passphraseSource ? await readPassphraseSource(args.passphraseSource) : null;
|
|
458
|
+
let manifest = null;
|
|
459
|
+
if (args.manifestSource && args.manifestEntryId) {
|
|
460
|
+
let raw;
|
|
458
461
|
try {
|
|
459
|
-
|
|
460
|
-
? await dependencies.
|
|
461
|
-
: await
|
|
462
|
-
limit: MAX_OFFLINE_PASSPHRASE_FILE_BYTES,
|
|
463
|
-
label: 'Passphrase file',
|
|
464
|
-
});
|
|
462
|
+
raw = dependencies.readArtifactInput
|
|
463
|
+
? await dependencies.readArtifactInput(args.manifestSource)
|
|
464
|
+
: await readInput(args.manifestSource, MAX_OFFLINE_ARTIFACT_BYTES, 'Investigation manifest input');
|
|
465
465
|
}
|
|
466
466
|
catch (error) {
|
|
467
467
|
if (error instanceof CliUsageError)
|
|
468
468
|
throw error;
|
|
469
|
-
throw new CliUsageError(`Could not read
|
|
470
|
-
}
|
|
471
|
-
passphrase = passphraseText.replace(/\r?\n$/u, '');
|
|
472
|
-
if (!passphrase || /[\r\n\u0000]/u.test(passphrase)) {
|
|
473
|
-
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')}`);
|
|
474
470
|
}
|
|
471
|
+
if (!raw.trim())
|
|
472
|
+
throw new CliUsageError('The investigation manifest input is empty.');
|
|
473
|
+
manifest = Object.freeze({ raw, entryId: args.manifestEntryId });
|
|
475
474
|
}
|
|
476
|
-
const report = await verifyOfflineArtifact(input, { passphrase });
|
|
475
|
+
const report = await verifyOfflineArtifact(input, { passphrase, manifest });
|
|
477
476
|
if (!args.quiet) {
|
|
478
477
|
write(stdout, args.output === 'json'
|
|
479
478
|
? formatJsonDocument(report)
|
|
480
479
|
: terminal(formatOfflineArtifactVerification(report), args.color));
|
|
481
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));
|
|
482
509
|
return EXIT_CODES.SUCCESS;
|
|
483
510
|
}
|
|
484
511
|
if (isEvidenceCommand(args)) {
|
|
@@ -494,6 +521,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
494
521
|
readPrivateKeyFile: dependencies.readPrivateKeyFile,
|
|
495
522
|
readPublicKeyFile: dependencies.readPublicKeyFile,
|
|
496
523
|
now: dependencies.now,
|
|
524
|
+
signal: dependencies.signal,
|
|
497
525
|
});
|
|
498
526
|
}
|
|
499
527
|
if (args.action === 'source-report') {
|
|
@@ -502,12 +530,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
502
530
|
try {
|
|
503
531
|
input = dependencies.readSourceReliabilityInput
|
|
504
532
|
? await dependencies.readSourceReliabilityInput(args.source)
|
|
505
|
-
: await
|
|
506
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
507
|
-
: dependencies.stdin || process.stdin, {
|
|
508
|
-
limit: MAX_SOURCE_RELIABILITY_INPUT_BYTES,
|
|
509
|
-
label: 'Source reliability input',
|
|
510
|
-
});
|
|
533
|
+
: await readInput(args.source, MAX_SOURCE_RELIABILITY_INPUT_BYTES, 'Source reliability input');
|
|
511
534
|
}
|
|
512
535
|
catch (error) {
|
|
513
536
|
if (error instanceof CliUsageError)
|
|
@@ -530,9 +553,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
530
553
|
try {
|
|
531
554
|
input = dependencies.readCompareInput
|
|
532
555
|
? await dependencies.readCompareInput(args.source)
|
|
533
|
-
: await
|
|
534
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
535
|
-
: dependencies.stdin || process.stdin, MAX_COMPARE_INPUT_BYTES);
|
|
556
|
+
: await readInput(args.source, MAX_COMPARE_INPUT_BYTES, 'Comparison input');
|
|
536
557
|
}
|
|
537
558
|
catch (error) {
|
|
538
559
|
if (error instanceof CliUsageError)
|
|
@@ -553,10 +574,8 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
553
574
|
}
|
|
554
575
|
if (args.action === 'page-compare') {
|
|
555
576
|
failureLabel = 'Static page comparison';
|
|
556
|
-
const readDiffInput = dependencies.readDiffInput
|
|
557
|
-
|
|
558
|
-
label: 'Page comparison input',
|
|
559
|
-
})));
|
|
577
|
+
const readDiffInput = dependencies.readDiffInput
|
|
578
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Page comparison input'));
|
|
560
579
|
let leftInput;
|
|
561
580
|
let rightInput;
|
|
562
581
|
try {
|
|
@@ -583,12 +602,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
583
602
|
try {
|
|
584
603
|
input = dependencies.readMailReviewInput
|
|
585
604
|
? await dependencies.readMailReviewInput(args.source)
|
|
586
|
-
: await
|
|
587
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
588
|
-
: dependencies.stdin || process.stdin, {
|
|
589
|
-
limit: MAX_MAIL_REVIEW_INPUT_BYTES,
|
|
590
|
-
label: 'Mail review input',
|
|
591
|
-
});
|
|
605
|
+
: await readInput(args.source, MAX_MAIL_REVIEW_INPUT_BYTES, 'Mail review input');
|
|
592
606
|
}
|
|
593
607
|
catch (error) {
|
|
594
608
|
if (error instanceof CliUsageError)
|
|
@@ -608,12 +622,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
608
622
|
try {
|
|
609
623
|
input = dependencies.readArtifactInput
|
|
610
624
|
? await dependencies.readArtifactInput(args.source)
|
|
611
|
-
: await
|
|
612
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
613
|
-
: dependencies.stdin || process.stdin, {
|
|
614
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
615
|
-
label: 'Offline evidence input',
|
|
616
|
-
});
|
|
625
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Offline evidence input');
|
|
617
626
|
}
|
|
618
627
|
catch (error) {
|
|
619
628
|
if (error instanceof CliUsageError)
|
|
@@ -651,12 +660,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
651
660
|
try {
|
|
652
661
|
input = dependencies.readArtifactInput
|
|
653
662
|
? await dependencies.readArtifactInput(args.source)
|
|
654
|
-
: await
|
|
655
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
656
|
-
: dependencies.stdin || process.stdin, {
|
|
657
|
-
limit: isBrief ? MAX_SAVED_LOOKUP_INPUT_BYTES : 4 * 1024 * 1024,
|
|
658
|
-
label: isBrief ? 'Lookup brief input' : 'Case-pack input',
|
|
659
|
-
});
|
|
663
|
+
: await readInput(args.source, isBrief ? MAX_SAVED_LOOKUP_INPUT_BYTES : 4 * 1024 * 1024, isBrief ? 'Lookup brief input' : 'Case-pack input');
|
|
660
664
|
}
|
|
661
665
|
catch (error) {
|
|
662
666
|
if (error instanceof CliUsageError)
|
|
@@ -687,12 +691,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
687
691
|
try {
|
|
688
692
|
input = dependencies.readArtifactInput
|
|
689
693
|
? await dependencies.readArtifactInput(args.source)
|
|
690
|
-
: await
|
|
691
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
692
|
-
: dependencies.stdin || process.stdin, {
|
|
693
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
694
|
-
label: 'Domain control input',
|
|
695
|
-
});
|
|
694
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Domain control input');
|
|
696
695
|
}
|
|
697
696
|
catch (error) {
|
|
698
697
|
if (error instanceof CliUsageError)
|
|
@@ -701,11 +700,21 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
701
700
|
}
|
|
702
701
|
if (!input.trim())
|
|
703
702
|
throw new CliUsageError('domain-control requires one JSON file or a document on stdin.');
|
|
703
|
+
const normalizedDomainControlInput = input.replace(/^\uFEFF/u, '');
|
|
704
704
|
let parsed;
|
|
705
705
|
try {
|
|
706
|
-
|
|
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);
|
|
707
712
|
}
|
|
708
|
-
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
|
+
}
|
|
709
718
|
throw new CliUsageError('Domain control input is not valid JSON.');
|
|
710
719
|
}
|
|
711
720
|
const schema = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
@@ -741,19 +750,11 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
741
750
|
try {
|
|
742
751
|
manifestInput = dependencies.readArtifactInput
|
|
743
752
|
? await dependencies.readArtifactInput(args.source)
|
|
744
|
-
: await
|
|
745
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
746
|
-
: dependencies.stdin || process.stdin, {
|
|
747
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
748
|
-
label: 'Domain-control manifest input',
|
|
749
|
-
});
|
|
753
|
+
: await readInput(args.source, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Domain-control manifest input');
|
|
750
754
|
if (args.previousSource) {
|
|
751
755
|
previousInput = dependencies.readDiffInput
|
|
752
756
|
? await dependencies.readDiffInput(args.previousSource)
|
|
753
|
-
: await
|
|
754
|
-
limit: MAX_OFFLINE_EVIDENCE_INPUT_BYTES,
|
|
755
|
-
label: 'Prior monitor snapshot',
|
|
756
|
-
});
|
|
757
|
+
: await readInput(args.previousSource, MAX_OFFLINE_EVIDENCE_INPUT_BYTES, 'Prior monitor snapshot');
|
|
757
758
|
}
|
|
758
759
|
}
|
|
759
760
|
catch (error) {
|
|
@@ -796,12 +797,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
796
797
|
try {
|
|
797
798
|
input = dependencies.readArtifactInput
|
|
798
799
|
? await dependencies.readArtifactInput(args.source)
|
|
799
|
-
: await
|
|
800
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
801
|
-
: dependencies.stdin || process.stdin, {
|
|
802
|
-
limit: MAX_ASSURANCE_INPUT_BYTES,
|
|
803
|
-
label: 'Domain assurance input',
|
|
804
|
-
});
|
|
800
|
+
: await readInput(args.source, MAX_ASSURANCE_INPUT_BYTES, 'Domain assurance input');
|
|
805
801
|
}
|
|
806
802
|
catch (error) {
|
|
807
803
|
if (error instanceof CliUsageError)
|
|
@@ -836,12 +832,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
836
832
|
try {
|
|
837
833
|
input = dependencies.readArtifactInput
|
|
838
834
|
? await dependencies.readArtifactInput(args.source)
|
|
839
|
-
: await
|
|
840
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
841
|
-
: dependencies.stdin || process.stdin, {
|
|
842
|
-
limit: MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES,
|
|
843
|
-
label: 'Domain change packet input',
|
|
844
|
-
});
|
|
835
|
+
: await readInput(args.source, MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES, 'Domain change packet input');
|
|
845
836
|
}
|
|
846
837
|
catch (error) {
|
|
847
838
|
if (error instanceof CliUsageError)
|
|
@@ -876,12 +867,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
876
867
|
try {
|
|
877
868
|
input = dependencies.readArtifactInput
|
|
878
869
|
? await dependencies.readArtifactInput(args.source)
|
|
879
|
-
: await
|
|
880
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
881
|
-
: dependencies.stdin || process.stdin, {
|
|
882
|
-
limit: MAX_SHARING_REVIEW_BYTES,
|
|
883
|
-
label: 'Sharing review input',
|
|
884
|
-
});
|
|
870
|
+
: await readInput(args.source, MAX_SHARING_REVIEW_BYTES, 'Sharing review input');
|
|
885
871
|
}
|
|
886
872
|
catch (error) {
|
|
887
873
|
if (error instanceof CliUsageError)
|
|
@@ -926,10 +912,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
926
912
|
try {
|
|
927
913
|
resumeInput = dependencies.readDiffInput
|
|
928
914
|
? await dependencies.readDiffInput(args.resumeSource)
|
|
929
|
-
: await
|
|
930
|
-
limit: 24 * 1024 * 1024,
|
|
931
|
-
label: 'Investigation resume state',
|
|
932
|
-
});
|
|
915
|
+
: await readInput(args.resumeSource, MAX_INVESTIGATION_RUN_BYTES, 'Investigation resume state');
|
|
933
916
|
}
|
|
934
917
|
catch (error) {
|
|
935
918
|
if (error instanceof CliUsageError)
|
|
@@ -959,11 +942,9 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
959
942
|
return document.state === 'step_failed' ? EXIT_CODES.PARTIAL_FAILURE : EXIT_CODES.SUCCESS;
|
|
960
943
|
}
|
|
961
944
|
if (args.action === 'diff') {
|
|
962
|
-
failureLabel = '
|
|
963
|
-
const readDiffInput = dependencies.readDiffInput
|
|
964
|
-
|
|
965
|
-
label: 'Lookup diff input',
|
|
966
|
-
})));
|
|
945
|
+
failureLabel = 'Retained artifact diff';
|
|
946
|
+
const readDiffInput = dependencies.readDiffInput
|
|
947
|
+
|| ((source) => readInput(source, MAX_RETAINED_ARTIFACT_DIFF_BYTES, 'Retained diff input'));
|
|
967
948
|
let leftInput;
|
|
968
949
|
let rightInput;
|
|
969
950
|
try {
|
|
@@ -975,21 +956,19 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
975
956
|
catch (error) {
|
|
976
957
|
if (error instanceof CliUsageError)
|
|
977
958
|
throw error;
|
|
978
|
-
throw new CliUsageError(`Could not read
|
|
959
|
+
throw new CliUsageError(`Could not read retained diff input: ${boundedCliErrorMessage(error, 'Input could not be read')}`);
|
|
979
960
|
}
|
|
980
|
-
const document =
|
|
961
|
+
const document = buildCliRetainedArtifactDiff(leftInput, rightInput, { leftSessionId: args.leftSessionId, rightSessionId: args.rightSessionId }, dependencies.now ? dependencies.now() : new Date().toISOString());
|
|
981
962
|
if (!args.quiet)
|
|
982
963
|
write(stdout, args.output === 'json'
|
|
983
964
|
? formatJsonDocument(document)
|
|
984
|
-
: terminal(
|
|
965
|
+
: terminal(formatCliRetainedArtifactDiff(document), args.color));
|
|
985
966
|
return EXIT_CODES.SUCCESS;
|
|
986
967
|
}
|
|
987
968
|
if (args.action === 'reconcile') {
|
|
988
969
|
failureLabel = 'Lookup observation reconciliation';
|
|
989
|
-
const readReconciliationInput = dependencies.readDiffInput
|
|
990
|
-
|
|
991
|
-
label: 'Lookup reconciliation input',
|
|
992
|
-
})));
|
|
970
|
+
const readReconciliationInput = dependencies.readDiffInput
|
|
971
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Lookup reconciliation input'));
|
|
993
972
|
const inputs = [];
|
|
994
973
|
let totalBytes = 0;
|
|
995
974
|
try {
|
|
@@ -1016,10 +995,8 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1016
995
|
}
|
|
1017
996
|
if (args.action === 'timeline') {
|
|
1018
997
|
failureLabel = 'Lookup observation timeline';
|
|
1019
|
-
const readTimelineInput = dependencies.readDiffInput
|
|
1020
|
-
|
|
1021
|
-
label: 'Lookup timeline input',
|
|
1022
|
-
})));
|
|
998
|
+
const readTimelineInput = dependencies.readDiffInput
|
|
999
|
+
|| ((source) => readInput(source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Lookup timeline input'));
|
|
1023
1000
|
const inputs = [];
|
|
1024
1001
|
let totalBytes = 0;
|
|
1025
1002
|
try {
|
|
@@ -1050,12 +1027,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1050
1027
|
try {
|
|
1051
1028
|
input = dependencies.readExportInput
|
|
1052
1029
|
? await dependencies.readExportInput(args.source)
|
|
1053
|
-
: await
|
|
1054
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
1055
|
-
: dependencies.stdin || process.stdin, {
|
|
1056
|
-
limit: MAX_SAVED_LOOKUP_INPUT_BYTES,
|
|
1057
|
-
label: 'Evidence export input',
|
|
1058
|
-
});
|
|
1030
|
+
: await readInput(args.source, MAX_SAVED_LOOKUP_INPUT_BYTES, 'Evidence export input');
|
|
1059
1031
|
}
|
|
1060
1032
|
catch (error) {
|
|
1061
1033
|
if (error instanceof CliUsageError)
|
|
@@ -1069,9 +1041,9 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1069
1041
|
const now = dependencies.now ? dependencies.now() : new Date().toISOString();
|
|
1070
1042
|
const document = buildCliEvidenceExport(input, evidenceModule, now);
|
|
1071
1043
|
const output = args.format === 'markdown'
|
|
1072
|
-
? formatLookupEvidenceMarkdown(document)
|
|
1044
|
+
? formatLookupEvidenceMarkdown(document, { includeAttribution: args.includeAttribution })
|
|
1073
1045
|
: args.format === 'html'
|
|
1074
|
-
? formatLookupEvidenceHtml(document)
|
|
1046
|
+
? formatLookupEvidenceHtml(document, { includeAttribution: args.includeAttribution })
|
|
1075
1047
|
: formatCliEvidenceExport(document, args.compact);
|
|
1076
1048
|
write(stdout, output);
|
|
1077
1049
|
return EXIT_CODES.SUCCESS;
|
|
@@ -1097,12 +1069,7 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1097
1069
|
try {
|
|
1098
1070
|
input = dependencies.readArtifactInput
|
|
1099
1071
|
? await dependencies.readArtifactInput(args.source)
|
|
1100
|
-
: await
|
|
1101
|
-
? createReadStream(args.source, { highWaterMark: 64 * 1024 })
|
|
1102
|
-
: dependencies.stdin || process.stdin, {
|
|
1103
|
-
limit: MAX_CT_EVENT_INPUT_BYTES,
|
|
1104
|
-
label: 'Certificate event input',
|
|
1105
|
-
});
|
|
1072
|
+
: await readInput(args.source, MAX_CT_EVENT_INPUT_BYTES, 'Certificate event input');
|
|
1106
1073
|
}
|
|
1107
1074
|
catch (error) {
|
|
1108
1075
|
if (error instanceof CliUsageError)
|
|
@@ -1134,14 +1101,20 @@ async function runParsedCli(args, dependencies = {}) {
|
|
|
1134
1101
|
if (args.action === 'ct-search'
|
|
1135
1102
|
|| args.action === 'posture'
|
|
1136
1103
|
|| args.action === 'http'
|
|
1137
|
-
|| args.action === 'tls'
|
|
1104
|
+
|| args.action === 'tls'
|
|
1105
|
+
|| args.action === 'dnssec-validate'
|
|
1106
|
+
|| args.action === 'mail-transport') {
|
|
1138
1107
|
failureLabel = args.action === 'ct-search'
|
|
1139
1108
|
? 'Certificate Transparency search'
|
|
1140
1109
|
: args.action === 'posture'
|
|
1141
1110
|
? 'Domain posture audit'
|
|
1142
1111
|
: args.action === 'http'
|
|
1143
1112
|
? 'HTTP probe'
|
|
1144
|
-
:
|
|
1113
|
+
: args.action === 'tls'
|
|
1114
|
+
? 'TLS intelligence'
|
|
1115
|
+
: args.action === 'dnssec-validate'
|
|
1116
|
+
? 'DNSSEC chain validation'
|
|
1117
|
+
: 'Mail transport review';
|
|
1145
1118
|
const { runNetworkCommand } = await import("./network-command-runner.mjs");
|
|
1146
1119
|
return await runNetworkCommand(args, dependencies, commandContext);
|
|
1147
1120
|
}
|