@slicedearth/whoisleuth-cli 2.1.0 → 2.3.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.
- package/README.md +2 -1
- package/cli/arguments.mjs +389 -1745
- package/cli/artifact-validation/case-response.mjs +55 -30
- package/cli/artifact-validation/signed-review.mjs +30 -12
- package/cli/bulk-checkpoint.mjs +34 -3
- package/cli/case-pack.mjs +39 -92
- package/cli/command-argument-grammar.mjs +211 -0
- package/cli/command-reference.mjs +200 -213
- package/cli/completion.mjs +5 -1
- package/cli/discovery-observation-snapshot.mjs +16 -3
- package/cli/discovery-scan-command-runner.mjs +19 -0
- package/cli/discovery-scan.mjs +6 -0
- package/cli/domain-control-observations.mjs +1 -1
- package/cli/inline-command-families.mjs +1 -0
- package/cli/input.mjs +116 -0
- package/cli/interchange-report.mjs +14 -0
- package/cli/lookalike-calibration.mjs +7 -2
- package/cli/lookup-brief.mjs +4 -2
- package/cli/lookup-browser-view.mjs +1 -1
- package/cli/mail-header-review.mjs +467 -0
- package/cli/review-command-runner.mjs +25 -0
- package/cli/risk-calibration.mjs +19 -17
- package/cli/runner.mjs +7 -1
- package/docs/cli-reference.md +8 -1
- package/docs/cli.md +24 -1
- package/lib/bounded-json.mjs +9 -6
- package/lib/dns-convergence-review.mjs +1 -0
- package/lib/dns-intelligence.mjs +37 -3
- package/lib/dnssec-chain-validation.mjs +6 -0
- package/lib/domain-change-packet.mjs +42 -14
- package/lib/domain-control-flight-recorder.mjs +4 -1
- package/lib/domain-control-manifest.mjs +16 -16
- package/lib/domain-posture-parsers.mjs +114 -3
- package/lib/domain-posture.mjs +34 -3
- package/lib/evidence-export.mjs +63 -13
- package/lib/evidence-report.mjs +2 -2
- package/lib/html-signals.mjs +39 -33
- package/lib/local-geoip-evidence.mjs +19 -3
- package/lib/lookup-response.mjs +5 -4
- package/lib/lookup-source-progress.mjs +27 -4
- package/lib/nameserver-preflight-review.mjs +1 -0
- package/lib/rdap-capabilities.mjs +1 -1
- package/lib/registry-insights.mjs +35 -22
- package/lib/risk-calibration-summary.mjs +1 -3
- package/lib/security-txt.mjs +33 -1
- package/lib/static-html-analysis.mjs +69 -13
- package/lib/website-technology.mjs +79 -11
- package/lib/zone-intent-review.mjs +16 -6
- package/package.json +1 -1
- package/packages/cases/case-migration-model.mjs +71 -22
- package/packages/cases/case-record-contracts.mjs +5 -20
- package/packages/cases/case-record-core.mjs +10 -21
- package/packages/cases/case-record-decisions.mjs +72 -0
- package/packages/cases/case-record-model.mjs +1 -0
- package/packages/cases/case-record-operations.mjs +240 -3
- package/packages/cases/case-record-projection.mjs +218 -0
- package/packages/cases/case-report.mjs +11 -6
- package/packages/cases/case-response-model.mjs +43 -6
- package/packages/cases/case-response-packet.mjs +78 -27
- package/packages/cases/case-storage-model.mjs +6 -2
- package/packages/comparison/comparison-ledger-bulk.mjs +9 -10
- package/packages/comparison/page-similarity.mjs +3 -1
- package/packages/contracts/case-portability.mjs +183 -53
- package/packages/contracts/cli-command-semantics.mjs +93 -0
- package/packages/contracts/risk-calibration.mjs +15 -10
- package/packages/contracts/workspace-portability.mjs +44 -7
- package/packages/evidence/domain-control-runtime.mjs +46 -6
- package/packages/interchange/external-findings-import.mjs +115 -46
- package/packages/investigation/lookup-asset-graph.mjs +35 -27
- package/packages/workspace/brand-profile-model.mjs +118 -2
- package/packages/workspace/bulk-review-model.mjs +13 -7
- package/packages/workspace/bulk-session-model.mjs +5 -4
- package/packages/workspace/detection-rule-model.mjs +70 -22
- package/packages/workspace/relationship-observation-model.mjs +4 -1
- package/packages/workspace/website-snapshot-model.mjs +106 -8
- package/packages/workspace/workspace-archive.mjs +2 -0
- package/cli/evidence-command-arguments.mjs +0 -156
|
@@ -296,14 +296,89 @@ export function mergeWebsiteSnapshots(localRaw, incomingRaw) {
|
|
|
296
296
|
const snapshots = normalizeWebsiteSnapshotStore([...byId.values()]).snapshots;
|
|
297
297
|
return { snapshots, added, updated, skipped: Math.max(0, incoming.length - added - updated) };
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
const MAX_RECONCILED_WEBSITE_SOURCES = 16;
|
|
300
|
+
const UNAVAILABLE_WEBSITE_SOURCE_STATES = new Set([
|
|
301
|
+
'blocked', 'error', 'not_found', 'rate_limited', 'unavailable', 'unsupported',
|
|
302
|
+
]);
|
|
303
|
+
export function canonicalWebsiteSourceState(value) {
|
|
304
|
+
return value.trim().toLowerCase().replace(/[\s-]+/gu, '_');
|
|
305
|
+
}
|
|
306
|
+
function websiteSourceStateSeverity(value) {
|
|
307
|
+
if (UNAVAILABLE_WEBSITE_SOURCE_STATES.has(value))
|
|
308
|
+
return 2;
|
|
309
|
+
return ['complete', 'success'].includes(value) ? 0 : 1;
|
|
310
|
+
}
|
|
311
|
+
export function reconciledWebsiteSources(snapshot) {
|
|
312
|
+
const selected = new Map();
|
|
313
|
+
for (const sourceEntry of snapshot.sources.slice(0, MAX_RECONCILED_WEBSITE_SOURCES)) {
|
|
314
|
+
const sourceId = sourceEntry.source.trim().toLowerCase();
|
|
315
|
+
if (!sourceId)
|
|
316
|
+
continue;
|
|
317
|
+
const state = canonicalWebsiteSourceState(sourceEntry.state);
|
|
318
|
+
const severity = websiteSourceStateSeverity(state);
|
|
319
|
+
const current = selected.get(sourceId);
|
|
320
|
+
if (!current || severity > current.severity || (severity === current.severity && state.localeCompare(current.state) < 0)) {
|
|
321
|
+
selected.set(sourceId, { state, severity });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return [...selected.entries()]
|
|
325
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
326
|
+
.map(([sourceName, value]) => ({ source: sourceName, state: value.state }));
|
|
327
|
+
}
|
|
328
|
+
export function websiteWithReconciledSources(snapshot) {
|
|
329
|
+
return { ...snapshot, sources: reconciledWebsiteSources(snapshot) };
|
|
330
|
+
}
|
|
331
|
+
export function reconciledWebsiteSourceState(snapshot, sourceId) {
|
|
332
|
+
const canonicalId = sourceId.trim().toLowerCase();
|
|
333
|
+
return reconciledWebsiteSources(snapshot)
|
|
334
|
+
.find((sourceEntry) => sourceEntry.source === canonicalId)?.state ?? null;
|
|
335
|
+
}
|
|
336
|
+
function completeWebsiteSourceState(value) {
|
|
337
|
+
const state = canonicalWebsiteSourceState(value);
|
|
338
|
+
return state === 'complete' || state === 'success';
|
|
339
|
+
}
|
|
340
|
+
export function websiteSnapshotFieldSource(field) {
|
|
341
|
+
if (field.startsWith('certificate.'))
|
|
342
|
+
return 'tls';
|
|
343
|
+
if (field.startsWith('source.'))
|
|
344
|
+
return field.slice('source.'.length);
|
|
345
|
+
if (field.startsWith('dependency.')) {
|
|
346
|
+
const recordType = field.slice('dependency.'.length).split(':')[0];
|
|
347
|
+
return recordType === 'HTTP' ? 'http' : 'dns';
|
|
348
|
+
}
|
|
349
|
+
if (['technology', 'posture', 'identity'].some((family) => field.startsWith(family)))
|
|
350
|
+
return 'http';
|
|
351
|
+
return '';
|
|
352
|
+
}
|
|
353
|
+
export function websiteSnapshotFieldComplete(snapshot, field) {
|
|
354
|
+
const sourceName = websiteSnapshotFieldSource(field);
|
|
355
|
+
const retainedSource = sourceName ? reconciledWebsiteSourceState(snapshot, sourceName) : null;
|
|
356
|
+
const retainedSourceComplete = !retainedSource || completeWebsiteSourceState(retainedSource);
|
|
357
|
+
if (field.startsWith('certificate.')) {
|
|
358
|
+
return Boolean(snapshot.certificate?.complete && !snapshot.certificate.truncated && retainedSourceComplete);
|
|
359
|
+
}
|
|
360
|
+
return snapshot.complete && !snapshot.truncated && retainedSourceComplete;
|
|
361
|
+
}
|
|
362
|
+
export function websiteSnapshotComparisonEvidenceComplete(snapshot) {
|
|
363
|
+
return websiteSnapshotFieldComplete(snapshot, 'technology')
|
|
364
|
+
&& websiteSnapshotFieldComplete(snapshot, 'posture')
|
|
365
|
+
&& websiteSnapshotFieldComplete(snapshot, 'identity')
|
|
366
|
+
&& websiteSnapshotFieldComplete(snapshot, 'dependency.CNAME')
|
|
367
|
+
&& (!snapshot.certificate || websiteSnapshotFieldComplete(snapshot, 'certificate.observation'));
|
|
368
|
+
}
|
|
369
|
+
function compareMap(field, before, after, options = {}) {
|
|
300
370
|
const changes = [];
|
|
301
371
|
for (const key of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
302
372
|
const left = before.get(key) ?? null;
|
|
303
373
|
const right = after.get(key) ?? null;
|
|
304
374
|
if (left === right)
|
|
305
375
|
continue;
|
|
306
|
-
|
|
376
|
+
const state = left === null
|
|
377
|
+
? options.beforeComplete?.(key) === false ? 'incomparable' : 'added'
|
|
378
|
+
: right === null
|
|
379
|
+
? options.afterComplete?.(key) === false ? 'incomparable' : 'removed'
|
|
380
|
+
: 'changed';
|
|
381
|
+
changes.push({ field: `${field}.${key}`, state, before: left, after: right });
|
|
307
382
|
}
|
|
308
383
|
return changes;
|
|
309
384
|
}
|
|
@@ -313,6 +388,7 @@ export function compareWebsiteSnapshots(beforeRaw, afterRaw) {
|
|
|
313
388
|
if (!before || !after || before.domain !== after.domain) {
|
|
314
389
|
return {
|
|
315
390
|
compatible: false,
|
|
391
|
+
complete: false,
|
|
316
392
|
changes: [{ field: 'snapshot', state: 'incomparable', before: before?.domain ?? null, after: after?.domain ?? null }],
|
|
317
393
|
dependencyTransitions: [],
|
|
318
394
|
};
|
|
@@ -328,20 +404,29 @@ export function compareWebsiteSnapshots(beforeRaw, afterRaw) {
|
|
|
328
404
|
? 'legacy_unknown'
|
|
329
405
|
: postureVersionBefore === postureVersionAfter ? 'comparable' : 'detector_changed';
|
|
330
406
|
const changes = [
|
|
331
|
-
...(technologyComparability === 'comparable' ? compareMap('technology', new Map(before.technologies.map((item) => [item.id, `${item.name}|${item.category}|${item.confidence}|${item.roles.join(',')}`])), new Map(after.technologies.map((item) => [item.id, `${item.name}|${item.category}|${item.confidence}|${item.roles.join(',')}`]))
|
|
407
|
+
...(technologyComparability === 'comparable' ? compareMap('technology', new Map(before.technologies.map((item) => [item.id, `${item.name}|${item.category}|${item.confidence}|${item.roles.join(',')}`])), new Map(after.technologies.map((item) => [item.id, `${item.name}|${item.category}|${item.confidence}|${item.roles.join(',')}`])), {
|
|
408
|
+
beforeComplete: () => websiteSnapshotFieldComplete(before, 'technology'),
|
|
409
|
+
afterComplete: () => websiteSnapshotFieldComplete(after, 'technology'),
|
|
410
|
+
}) : [{
|
|
332
411
|
field: 'technology.profileVersion',
|
|
333
412
|
state: technologyComparability === 'detector_changed' ? 'changed' : 'incomparable',
|
|
334
413
|
before: technologyVersionBefore === null ? null : String(technologyVersionBefore),
|
|
335
414
|
after: technologyVersionAfter === null ? null : String(technologyVersionAfter),
|
|
336
415
|
}]),
|
|
337
|
-
...(postureComparability === 'comparable' ? compareMap('posture', new Map(before.posture.map((item) => [item.id, item.state])), new Map(after.posture.map((item) => [item.id, item.state]))
|
|
416
|
+
...(postureComparability === 'comparable' ? compareMap('posture', new Map(before.posture.map((item) => [item.id, item.state])), new Map(after.posture.map((item) => [item.id, item.state])), {
|
|
417
|
+
beforeComplete: () => websiteSnapshotFieldComplete(before, 'posture'),
|
|
418
|
+
afterComplete: () => websiteSnapshotFieldComplete(after, 'posture'),
|
|
419
|
+
}) : [{
|
|
338
420
|
field: 'posture.profileVersion',
|
|
339
421
|
state: postureComparability === 'detector_changed' ? 'changed' : 'incomparable',
|
|
340
422
|
before: postureVersionBefore === null ? null : String(postureVersionBefore),
|
|
341
423
|
after: postureVersionAfter === null ? null : String(postureVersionAfter),
|
|
342
424
|
}]),
|
|
343
425
|
...compareMap('source', new Map(before.sources.map((item) => [item.source, item.state])), new Map(after.sources.map((item) => [item.source, item.state]))),
|
|
344
|
-
...compareMap('dependency', new Map(before.dependencies.map((item) => [`${item.recordType}:${item.target}`, `${item.state}|${item.qualification}`])), new Map(after.dependencies.map((item) => [`${item.recordType}:${item.target}`, `${item.state}|${item.qualification}`]))
|
|
426
|
+
...compareMap('dependency', new Map(before.dependencies.map((item) => [`${item.recordType}:${item.target}`, `${item.state}|${item.qualification}`])), new Map(after.dependencies.map((item) => [`${item.recordType}:${item.target}`, `${item.state}|${item.qualification}`])), {
|
|
427
|
+
beforeComplete: (key) => websiteSnapshotFieldComplete(before, `dependency.${key}`),
|
|
428
|
+
afterComplete: (key) => websiteSnapshotFieldComplete(after, `dependency.${key}`),
|
|
429
|
+
}),
|
|
345
430
|
];
|
|
346
431
|
const dependencyTransitions = [];
|
|
347
432
|
const beforeDependencies = new Map(before.dependencies.map((item) => [`${item.recordType}:${item.target}`, item]));
|
|
@@ -365,10 +450,10 @@ export function compareWebsiteSnapshots(beforeRaw, afterRaw) {
|
|
|
365
450
|
detail: 'An earlier active dependency is unresolved in the later retained observation. Resolver or collection failure remains possible.',
|
|
366
451
|
});
|
|
367
452
|
}
|
|
368
|
-
else if (!left && right) {
|
|
453
|
+
else if (!left && right && websiteSnapshotFieldComplete(before, `dependency.${key}`)) {
|
|
369
454
|
dependencyTransitions.push({ target: right.target, recordType: right.recordType, state: 'added', detail: 'This dependency first appears in the later retained snapshot.' });
|
|
370
455
|
}
|
|
371
|
-
else if (left && !right && after
|
|
456
|
+
else if (left && !right && websiteSnapshotFieldComplete(after, `dependency.${key}`)) {
|
|
372
457
|
dependencyTransitions.push({ target: left.target, recordType: left.recordType, state: 'removed', detail: 'This dependency is not represented in the later complete snapshot. It may have been intentionally removed or replaced.' });
|
|
373
458
|
}
|
|
374
459
|
if (dependencyTransitions.length >= 20)
|
|
@@ -381,7 +466,16 @@ export function compareWebsiteSnapshots(beforeRaw, afterRaw) {
|
|
|
381
466
|
continue;
|
|
382
467
|
changes.push({ field: `identity.${key}`, state: left === null || right === null ? 'unavailable' : 'changed', before: left, after: right });
|
|
383
468
|
}
|
|
384
|
-
changes.push(...compareMap('identityValues.resourceHosts', new Map(before.identityValues.resourceHosts.map((item) => [item, item])), new Map(after.identityValues.resourceHosts.map((item) => [item, item]))
|
|
469
|
+
changes.push(...compareMap('identityValues.resourceHosts', new Map(before.identityValues.resourceHosts.map((item) => [item, item])), new Map(after.identityValues.resourceHosts.map((item) => [item, item])), {
|
|
470
|
+
beforeComplete: () => websiteSnapshotFieldComplete(before, 'identityValues.resourceHosts'),
|
|
471
|
+
afterComplete: () => websiteSnapshotFieldComplete(after, 'identityValues.resourceHosts'),
|
|
472
|
+
}), ...compareMap('identityValues.trackingIdentifiers', new Map(before.identityValues.trackingIdentifiers.map((item) => [`${item.type}:${item.value}`, item.value])), new Map(after.identityValues.trackingIdentifiers.map((item) => [`${item.type}:${item.value}`, item.value])), {
|
|
473
|
+
beforeComplete: () => websiteSnapshotFieldComplete(before, 'identityValues.trackingIdentifiers'),
|
|
474
|
+
afterComplete: () => websiteSnapshotFieldComplete(after, 'identityValues.trackingIdentifiers'),
|
|
475
|
+
}), ...compareMap('identityValues.formActionOrigins', new Map(before.identityValues.formActionOrigins.map((item) => [item, item])), new Map(after.identityValues.formActionOrigins.map((item) => [item, item])), {
|
|
476
|
+
beforeComplete: () => websiteSnapshotFieldComplete(before, 'identityValues.formActionOrigins'),
|
|
477
|
+
afterComplete: () => websiteSnapshotFieldComplete(after, 'identityValues.formActionOrigins'),
|
|
478
|
+
}));
|
|
385
479
|
if (before.certificate || after.certificate) {
|
|
386
480
|
if (!before.certificate || !after.certificate) {
|
|
387
481
|
changes.push({
|
|
@@ -425,6 +519,10 @@ export function compareWebsiteSnapshots(beforeRaw, afterRaw) {
|
|
|
425
519
|
}
|
|
426
520
|
return {
|
|
427
521
|
compatible: true,
|
|
522
|
+
complete: websiteSnapshotComparisonEvidenceComplete(before)
|
|
523
|
+
&& websiteSnapshotComparisonEvidenceComplete(after)
|
|
524
|
+
&& technologyComparability === 'comparable'
|
|
525
|
+
&& postureComparability === 'comparable',
|
|
428
526
|
profileComparability: {
|
|
429
527
|
technology: technologyComparability,
|
|
430
528
|
securityPosture: postureComparability,
|
|
@@ -528,6 +528,7 @@ export async function previewWorkspaceArchive(raw, localInput, options = {}) {
|
|
|
528
528
|
skipped: result.skipped ?? 0,
|
|
529
529
|
pruned: result.pruned ?? 0,
|
|
530
530
|
brandProfileReferencesOmitted: result.brandProfileReferencesOmitted ?? 0,
|
|
531
|
+
authoredHistoryOmitted: result.authoredHistoryOmitted ?? 0,
|
|
531
532
|
selected,
|
|
532
533
|
normalizedSettings: result.settings || null,
|
|
533
534
|
});
|
|
@@ -567,6 +568,7 @@ export async function previewWorkspaceArchive(raw, localInput, options = {}) {
|
|
|
567
568
|
skipped: dependentSection.recordCount,
|
|
568
569
|
pruned: 0,
|
|
569
570
|
brandProfileReferencesOmitted: 0,
|
|
571
|
+
authoredHistoryOmitted: 0,
|
|
570
572
|
selected: false,
|
|
571
573
|
normalizedSettings: dependentId === 'settings' ? null : dependentSection.normalizedSettings ?? null,
|
|
572
574
|
};
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { CliUsageError } from "./errors.mjs";
|
|
2
|
-
export function parseInspectArchiveArguments(argv) {
|
|
3
|
-
let source = null;
|
|
4
|
-
let passphraseSource = null;
|
|
5
|
-
let search = null;
|
|
6
|
-
let reveal = false;
|
|
7
|
-
let requireMatch = false;
|
|
8
|
-
let expectedContentDigest = null;
|
|
9
|
-
let output = 'terminal';
|
|
10
|
-
let quiet = false;
|
|
11
|
-
let color = true;
|
|
12
|
-
for (let index = 0; index < argv.length; index++) {
|
|
13
|
-
const argument = argv[index];
|
|
14
|
-
if (argument === undefined)
|
|
15
|
-
break;
|
|
16
|
-
if (argument === '--json') {
|
|
17
|
-
if (output !== 'terminal')
|
|
18
|
-
throw new CliUsageError('--json may be supplied only once.');
|
|
19
|
-
output = 'json';
|
|
20
|
-
}
|
|
21
|
-
else if (argument === '--passphrase-file') {
|
|
22
|
-
if (passphraseSource !== null)
|
|
23
|
-
throw new CliUsageError('--passphrase-file may be supplied only once.');
|
|
24
|
-
const value = argv[++index];
|
|
25
|
-
if (!value || value.startsWith('-'))
|
|
26
|
-
throw new CliUsageError('--passphrase-file requires one bounded UTF-8 file.');
|
|
27
|
-
passphraseSource = value;
|
|
28
|
-
}
|
|
29
|
-
else if (argument === '--search') {
|
|
30
|
-
if (search !== null)
|
|
31
|
-
throw new CliUsageError('--search may be supplied only once.');
|
|
32
|
-
const value = argv[++index];
|
|
33
|
-
if (!value || value.startsWith('-'))
|
|
34
|
-
throw new CliUsageError('--search requires one exact bounded value.');
|
|
35
|
-
search = value;
|
|
36
|
-
}
|
|
37
|
-
else if (argument === '--reveal') {
|
|
38
|
-
if (reveal)
|
|
39
|
-
throw new CliUsageError('--reveal may be supplied only once.');
|
|
40
|
-
reveal = true;
|
|
41
|
-
}
|
|
42
|
-
else if (argument === '--require-match') {
|
|
43
|
-
if (requireMatch)
|
|
44
|
-
throw new CliUsageError('--require-match may be supplied only once.');
|
|
45
|
-
requireMatch = true;
|
|
46
|
-
}
|
|
47
|
-
else if (argument === '--expect-content-digest') {
|
|
48
|
-
if (expectedContentDigest !== null)
|
|
49
|
-
throw new CliUsageError('--expect-content-digest may be supplied only once.');
|
|
50
|
-
const value = argv[++index];
|
|
51
|
-
if (!value || !/^sha256:[a-f0-9]{64}$/u.test(value)) {
|
|
52
|
-
throw new CliUsageError('--expect-content-digest requires sha256 followed by 64 lowercase hexadecimal characters.');
|
|
53
|
-
}
|
|
54
|
-
expectedContentDigest = value;
|
|
55
|
-
}
|
|
56
|
-
else if (argument === '--quiet')
|
|
57
|
-
quiet = true;
|
|
58
|
-
else if (argument === '--no-color')
|
|
59
|
-
color = false;
|
|
60
|
-
else if (argument.startsWith('-'))
|
|
61
|
-
throw new CliUsageError(`Unknown option "${argument}".`);
|
|
62
|
-
else if (source === null)
|
|
63
|
-
source = argument;
|
|
64
|
-
else
|
|
65
|
-
throw new CliUsageError('inspect-archive accepts one optional JSON file. Otherwise pipe one archive on stdin.');
|
|
66
|
-
}
|
|
67
|
-
if (reveal && search === null)
|
|
68
|
-
throw new CliUsageError('--reveal requires --search.');
|
|
69
|
-
if (requireMatch && search === null)
|
|
70
|
-
throw new CliUsageError('--require-match requires --search.');
|
|
71
|
-
if (quiet && output !== 'terminal')
|
|
72
|
-
throw new CliUsageError('--quiet cannot be combined with machine-readable output.');
|
|
73
|
-
return {
|
|
74
|
-
action: 'inspect-archive',
|
|
75
|
-
source,
|
|
76
|
-
passphraseSource,
|
|
77
|
-
search,
|
|
78
|
-
reveal,
|
|
79
|
-
requireMatch,
|
|
80
|
-
expectedContentDigest,
|
|
81
|
-
output,
|
|
82
|
-
quiet,
|
|
83
|
-
color,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
export function parseSignArtifactArguments(argv) {
|
|
87
|
-
let source = null;
|
|
88
|
-
let privateKeySource = null;
|
|
89
|
-
for (let index = 0; index < argv.length; index++) {
|
|
90
|
-
const argument = argv[index];
|
|
91
|
-
if (argument === undefined)
|
|
92
|
-
break;
|
|
93
|
-
if (argument === '--private-key-file') {
|
|
94
|
-
if (privateKeySource !== null)
|
|
95
|
-
throw new CliUsageError('--private-key-file may be supplied only once.');
|
|
96
|
-
const value = argv[++index];
|
|
97
|
-
if (!value || value.startsWith('-'))
|
|
98
|
-
throw new CliUsageError('--private-key-file requires one bounded PEM file.');
|
|
99
|
-
privateKeySource = value;
|
|
100
|
-
}
|
|
101
|
-
else if (argument.startsWith('-'))
|
|
102
|
-
throw new CliUsageError(`Unknown option "${argument}".`);
|
|
103
|
-
else if (source === null)
|
|
104
|
-
source = argument;
|
|
105
|
-
else
|
|
106
|
-
throw new CliUsageError('sign-artifact accepts one optional JSON file. Otherwise pipe one artefact on stdin.');
|
|
107
|
-
}
|
|
108
|
-
if (!privateKeySource)
|
|
109
|
-
throw new CliUsageError('sign-artifact requires --private-key-file.');
|
|
110
|
-
return { action: 'sign-artifact', source, privateKeySource };
|
|
111
|
-
}
|
|
112
|
-
export function parseVerifySignatureArguments(argv) {
|
|
113
|
-
let source = null;
|
|
114
|
-
let publicKeySource = null;
|
|
115
|
-
let output = 'terminal';
|
|
116
|
-
let quiet = false;
|
|
117
|
-
let color = true;
|
|
118
|
-
for (let index = 0; index < argv.length; index++) {
|
|
119
|
-
const argument = argv[index];
|
|
120
|
-
if (argument === undefined)
|
|
121
|
-
break;
|
|
122
|
-
if (argument === '--json') {
|
|
123
|
-
if (output !== 'terminal')
|
|
124
|
-
throw new CliUsageError('--json may be supplied only once.');
|
|
125
|
-
output = 'json';
|
|
126
|
-
}
|
|
127
|
-
else if (argument === '--public-key-file') {
|
|
128
|
-
if (publicKeySource !== null)
|
|
129
|
-
throw new CliUsageError('--public-key-file may be supplied only once.');
|
|
130
|
-
const value = argv[++index];
|
|
131
|
-
if (!value || value.startsWith('-'))
|
|
132
|
-
throw new CliUsageError('--public-key-file requires one bounded PEM file.');
|
|
133
|
-
publicKeySource = value;
|
|
134
|
-
}
|
|
135
|
-
else if (argument === '--quiet')
|
|
136
|
-
quiet = true;
|
|
137
|
-
else if (argument === '--no-color')
|
|
138
|
-
color = false;
|
|
139
|
-
else if (argument.startsWith('-'))
|
|
140
|
-
throw new CliUsageError(`Unknown option "${argument}".`);
|
|
141
|
-
else if (source === null)
|
|
142
|
-
source = argument;
|
|
143
|
-
else
|
|
144
|
-
throw new CliUsageError('verify-signature accepts one optional JSON file. Otherwise pipe one package on stdin.');
|
|
145
|
-
}
|
|
146
|
-
if (quiet && output !== 'terminal')
|
|
147
|
-
throw new CliUsageError('--quiet cannot be combined with machine-readable output.');
|
|
148
|
-
return {
|
|
149
|
-
action: 'verify-signature',
|
|
150
|
-
source,
|
|
151
|
-
publicKeySource,
|
|
152
|
-
output,
|
|
153
|
-
quiet,
|
|
154
|
-
color,
|
|
155
|
-
};
|
|
156
|
-
}
|