@slicedearth/whoisleuth-cli 2.4.0 → 2.6.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/DISCLOSURE +1 -1
- package/NOTICE +2 -2
- package/cli/argument-values.mjs +55 -0
- package/cli/arguments.mjs +24 -470
- package/cli/artifact-validation/case-response.mjs +67 -9
- package/cli/artifact-validation/lookup-evidence.mjs +18 -4
- package/cli/artifact-validation/signed-review.mjs +61 -64
- package/cli/artifact-verify.mjs +11 -2
- package/cli/assurance-arguments.mjs +56 -0
- package/cli/assurance-command-definitions.mjs +179 -0
- package/cli/assurance-command-runner.mjs +1 -1
- package/cli/bounded-json.mjs +1 -1
- package/cli/bulk-checkpoint.mjs +1 -1
- package/cli/bulk-command-runner.mjs +6 -8
- package/cli/bulk.mjs +2 -3
- package/cli/case-command.mjs +99 -6
- package/cli/case-pack.mjs +19 -4
- package/cli/ci-report.mjs +6 -3
- package/cli/collection-arguments.mjs +123 -0
- package/cli/collection-command-definitions.mjs +330 -0
- package/cli/collection-preflight.mjs +8 -1
- package/cli/command-argument-grammar.mjs +8 -210
- package/cli/command-definition.mjs +330 -0
- package/cli/command-reference.mjs +55 -1388
- package/cli/command-seeds.mjs +18 -0
- package/cli/compare.mjs +1 -1
- package/cli/config-profile.mjs +1 -1
- package/cli/ct-event-intake.mjs +4 -4
- package/cli/discover.mjs +2 -2
- package/cli/discovery-observation-snapshot.mjs +2 -2
- package/cli/discovery-scan-command-runner.mjs +7 -9
- package/cli/discovery-scan.mjs +1 -1
- package/cli/discovery-snapshot.mjs +2 -2
- package/cli/discovery-workflow.mjs +4 -4
- package/cli/domain-control-monitor.mjs +6 -6
- package/cli/domain-control-observations.mjs +2 -1
- package/cli/domain-feed.mjs +61 -0
- package/cli/errors.mjs +5 -6
- package/cli/evidence-arguments.mjs +46 -0
- package/cli/evidence-command-definitions.mjs +69 -0
- package/cli/evidence-command-runner.mjs +2 -3
- package/cli/evidence-signing.mjs +3 -2
- package/cli/external-observation-mapping.mjs +2 -2
- package/cli/formatters/json.mjs +1 -13
- package/cli/formatters/terminal-command-formats.mjs +6 -0
- package/cli/formatters/terminal-lookup.mjs +6 -0
- package/cli/history-arguments.mjs +39 -0
- package/cli/history-command-definitions.mjs +88 -0
- package/cli/indicator-set-command.mjs +32 -0
- package/cli/inline-command-families.mjs +6 -47
- package/cli/inline-command-runner.mjs +4 -31
- package/cli/input.mjs +2 -2
- package/cli/intake-command.mjs +147 -0
- package/cli/interchange-report.mjs +4 -2
- package/cli/investigation-artifacts.mjs +3 -4
- package/cli/investigation-package-review.mjs +2 -0
- package/cli/investigation-plan.mjs +32 -154
- package/cli/investigation-recipes.mjs +177 -0
- package/cli/investigation-run.mjs +78 -12
- package/cli/local-mmdb-review.mjs +220 -17
- package/cli/lookalike-calibration.mjs +1 -1
- package/cli/lookup-brief.mjs +2 -2
- package/cli/lookup-command-runner.mjs +19 -35
- package/cli/lookup-diff.mjs +10 -9
- package/cli/lookup-plan.mjs +10 -14
- package/cli/lookup-reconcile.mjs +6 -5
- package/cli/lookup-timeline.mjs +7 -6
- package/cli/mail-header-review.mjs +24 -247
- package/cli/mail-review.mjs +9 -7
- package/cli/network-arguments.mjs +51 -0
- package/cli/network-command-definitions.mjs +130 -0
- package/cli/network-command-runner.mjs +43 -31
- package/cli/offline-evidence-review.mjs +85 -6
- package/cli/posture.mjs +1 -1
- package/cli/registry-fixture-scaffold.mjs +1 -1
- package/cli/retained-artifact-diff.mjs +8 -7
- package/cli/review-arguments.mjs +132 -0
- package/cli/review-command-definitions.mjs +279 -0
- package/cli/review-command-runner.mjs +72 -159
- package/cli/risk-calibration.mjs +14 -12
- package/cli/runner.mjs +20 -32
- package/cli/saved-lookup.mjs +2 -2
- package/cli/selected-input-worker.mjs +73 -0
- package/cli/sharing-review.mjs +5 -64
- package/cli/source-reliability.mjs +2 -2
- package/cli/support-arguments.mjs +49 -0
- package/cli/support-command-definitions.mjs +209 -0
- package/cli/support-command-runner.mjs +4 -4
- package/cli/watchlist-review.mjs +43 -0
- package/cli/workflow-arguments.mjs +100 -0
- package/cli/workflow-command-definitions.mjs +103 -0
- package/cli/workflow-command-runner.mjs +40 -1
- package/docs/cli-reference.md +27 -0
- package/docs/cli.md +322 -4
- package/docs/contextual-reviews.md +178 -0
- package/docs/infrastructure-observations.md +126 -0
- package/docs/offline-intake-context.md +213 -0
- package/lib/analyst-taxonomy.mjs +2 -40
- package/lib/application-version.mjs +1 -1
- package/lib/availability.mjs +13 -789
- package/lib/bounded-contract-normalizers.mjs +4 -0
- package/lib/bounded-json.mjs +2 -330
- package/lib/browser-library-profile.mjs +62 -84
- package/lib/candidate-provenance-bounds.mjs +2 -0
- package/lib/classify.mjs +1 -1
- package/lib/credential-form-attribution.mjs +136 -0
- package/lib/credential-surface-profile.mjs +6 -2
- package/lib/ct-query.mjs +2 -27
- package/lib/ct-response-bounds.mjs +2 -9
- package/lib/ct-search.mjs +83 -47
- package/lib/dmarc-discovery.mjs +62 -0
- package/lib/dns-convergence-review.mjs +21 -8
- package/lib/dns-delegation-health.mjs +35 -15
- package/lib/dns-inheritance-review.mjs +53 -63
- package/lib/dns-intelligence.mjs +27 -11
- package/lib/dns-query-coverage.mjs +40 -0
- package/lib/domain-assurance.mjs +1 -1
- package/lib/domain-change-packet.mjs +12 -13
- package/lib/domain-change-review.mjs +32 -14
- package/lib/domain-control-flight-recorder.mjs +103 -27
- package/lib/domain-control-manifest.mjs +25 -17
- package/lib/domain-posture-analysis.mjs +75 -7
- package/lib/domain-posture-parsers.mjs +9 -0
- package/lib/domain-posture.mjs +45 -25
- package/lib/domain-registration.mjs +392 -0
- package/lib/evidence-export-privacy.mjs +27 -17
- package/lib/evidence-export.mjs +3 -3
- package/lib/evidence-report.mjs +5 -1
- package/lib/external-intelligence-risk.mjs +2 -124
- package/lib/favicon.mjs +13 -4
- package/lib/generated/cisa-kev-catalog.mjs +41 -3
- package/lib/generated/registrar-standing-catalogue.mjs +18 -10
- package/lib/generated/retire-browser-catalog.mjs +332 -19
- package/lib/generated/{unicode-confusables-17.mjs → unicode-confusables.mjs} +33 -33
- package/lib/html-signals.mjs +13 -2
- package/lib/http-evidence-bounds.mjs +2 -8
- package/lib/http-intelligence.mjs +13 -1
- package/lib/idn-confusable-policy.mjs +6 -4
- package/lib/idn-confusables.mjs +1 -1
- package/lib/interchange-fidelity-registry.mjs +10 -0
- package/lib/lookup-child-profile-contract.mjs +28 -11
- package/lib/lookup-contract-primitives.mjs +1 -1
- package/lib/lookup-diagnostics.mjs +1 -23
- package/lib/lookup-network-evidence-bounds.mjs +1 -10
- package/lib/lookup-progress.mjs +50 -1
- package/lib/lookup-response-contract.mjs +70 -40
- package/lib/lookup-response.mjs +5 -15
- package/lib/lookup-source-progress.mjs +8 -22
- package/lib/lookup.mjs +1 -1
- package/lib/operation-budget.mjs +4 -0
- package/lib/opportunity-scoring.mjs +2 -107
- package/lib/outbound-identity.mjs +1 -1
- package/lib/page-fingerprints.mjs +18 -1
- package/lib/perceptual-hash-comparison.mjs +2 -34
- package/lib/perceptual-hash.mjs +36 -10
- package/lib/portable-generator.mjs +2 -29
- package/lib/project-metadata.mjs +2 -8
- package/lib/rdap-client.mjs +11 -7
- package/lib/registrable-domain.mjs +2 -56
- package/lib/registrar-standing-contract.mjs +1 -1
- package/lib/registrar-standing.mjs +9 -13
- package/lib/registry-capabilities.mjs +2 -2
- package/lib/registry-capability-catalogue.mjs +27 -19
- package/lib/risk-calibration-summary.mjs +2 -352
- package/lib/risk-scoring.mjs +2 -345
- package/lib/scoring-evidence-quality.mjs +2 -107
- package/lib/semantic-version.mjs +2 -54
- package/lib/service-binding-dns.mjs +46 -2
- package/lib/smtp-transport-review.mjs +48 -19
- package/lib/sslbl-certificates.generated.mjs +142 -139
- package/lib/static-html-analysis.mjs +32 -4
- package/lib/structured-data-identity.mjs +1 -1
- package/lib/technology-evidence-role.mjs +1 -51
- package/lib/threat-intelligence-manifests.mjs +1 -1
- package/lib/threat-intelligence-runtime.mjs +1 -1
- package/lib/threat-intelligence-targets.mjs +1 -1
- package/lib/threat-intelligence-types.mjs +2 -75
- package/lib/tls-intelligence.mjs +30 -5
- package/lib/typosquat-generator.mjs +11 -2
- package/lib/website-enrichment.mjs +404 -0
- package/lib/whois-authority.mjs +43 -5
- package/lib/whois-chain.mjs +12 -3
- package/lib/whois-common-formats.mjs +3 -1
- package/lib/whois-contacts.mjs +13 -2
- package/lib/whois-normalization.mjs +3 -1
- package/lib/whois-parser.mjs +5 -3
- package/package.json +15 -14
- package/packages/analysis/analyst-taxonomy.mjs +40 -0
- package/packages/analysis/bounded-json.mjs +330 -0
- package/packages/analysis/candidate-provenance-bounds.mjs +4 -0
- package/packages/analysis/cli-argument-grammar.mjs +216 -0
- package/packages/analysis/ct-query.mjs +27 -0
- package/packages/analysis/ct-response-bounds.mjs +9 -0
- package/packages/analysis/external-intelligence-risk.mjs +124 -0
- package/packages/analysis/http-evidence-bounds.mjs +8 -0
- package/packages/analysis/lookup-network-evidence-bounds.mjs +10 -0
- package/packages/analysis/opportunity-scoring.mjs +107 -0
- package/packages/analysis/perceptual-hash-comparison.mjs +34 -0
- package/packages/analysis/portable-generator.mjs +29 -0
- package/packages/analysis/project-metadata.mjs +8 -0
- package/packages/analysis/registrable-domain.mjs +56 -0
- package/packages/analysis/risk-calibration-summary.mjs +352 -0
- package/packages/analysis/risk-scoring.mjs +348 -0
- package/packages/analysis/scoring-evidence-quality.mjs +107 -0
- package/packages/analysis/semantic-version.mjs +54 -0
- package/packages/analysis/threat-intelligence-types.mjs +75 -0
- package/packages/cases/case-containment-handoff.mjs +195 -0
- package/packages/cases/case-evidence-links.mjs +151 -0
- package/packages/cases/case-evidence-model.mjs +89 -12
- package/packages/cases/case-evidence-quality.mjs +5 -0
- package/packages/cases/case-export-input.mjs +7 -5
- package/packages/cases/case-incident-context.mjs +52 -0
- package/packages/cases/case-markdown.mjs +11 -0
- package/packages/cases/case-migration-model.mjs +40 -24
- package/packages/cases/case-object-coverage.mjs +33 -0
- package/packages/cases/case-packet-correction.mjs +106 -0
- package/packages/cases/case-recheck-model.mjs +124 -36
- package/packages/cases/case-record-contracts.mjs +1 -1
- package/packages/cases/case-record-core.mjs +1 -1
- package/packages/cases/case-record-operations.mjs +111 -118
- package/packages/cases/case-record-projection.mjs +23 -4
- package/packages/cases/case-record-version-input.mjs +41 -0
- package/packages/cases/case-report.mjs +93 -27
- package/packages/cases/case-requested-evidence.mjs +146 -0
- package/packages/cases/case-response-actions.mjs +159 -1
- package/packages/cases/case-response-model.mjs +16 -1
- package/packages/cases/case-response-object.mjs +119 -0
- package/packages/cases/case-response-outcomes.mjs +108 -20
- package/packages/cases/case-response-packet-render.mjs +35 -12
- package/packages/cases/case-response-packet.mjs +55 -13
- package/packages/cases/case-response-records.mjs +0 -1
- package/packages/cases/case-response-review-inputs.mjs +60 -8
- package/packages/cases/case-storage-model.mjs +1 -1
- package/packages/cases/case-workflow-metadata.mjs +217 -0
- package/packages/cases/case-workflow-migration.mjs +43 -0
- package/packages/cases/http-summary.mjs +6 -1
- package/packages/comparison/favicon-similarity.mjs +1 -1
- package/packages/comparison/page-similarity.mjs +1 -1
- package/packages/comparison/relationship-evidence.mjs +21 -9
- package/packages/comparison/relationship-provenance.mjs +7 -1
- package/packages/contracts/analyst-interchange.mjs +35 -15
- package/packages/contracts/candidate-watch-review.mjs +54 -0
- package/packages/contracts/case-portability.mjs +360 -49
- package/packages/contracts/cli-command-semantics.mjs +5 -0
- package/packages/contracts/cli-grammar.mjs +6 -0
- package/packages/contracts/cli-lookup-brief.mjs +2 -0
- package/packages/contracts/context-review.mjs +25 -0
- package/packages/contracts/document-intake.mjs +11 -0
- package/packages/contracts/domain-control-flight-recorder.mjs +30 -14
- package/packages/contracts/domain-control-manifest.mjs +1 -1
- package/packages/contracts/domain-control-monitor.mjs +13 -2
- package/packages/contracts/domain-control-review.mjs +36 -15
- package/packages/contracts/external-observation-interchange.mjs +96 -28
- package/packages/contracts/har-review.mjs +2 -0
- package/packages/contracts/identity-events.mjs +4 -0
- package/packages/contracts/investigation-run.mjs +2 -0
- package/packages/contracts/ip-address.mjs +10 -0
- package/packages/contracts/lookup-evidence.mjs +3 -2
- package/packages/contracts/mail-authentication.mjs +5 -0
- package/packages/contracts/message-intake.mjs +37 -0
- package/packages/contracts/offline-comparison.mjs +4 -1
- package/packages/contracts/passive-mail.mjs +10 -0
- package/packages/contracts/risk-calibration.mjs +44 -29
- package/packages/contracts/schema-lifecycle.mjs +3 -1
- package/packages/contracts/web-capture.mjs +2 -2
- package/packages/contracts/workspace-portability.mjs +144 -28
- package/packages/evidence/collection-quality.mjs +67 -0
- package/packages/evidence/credential-form-attribution.mjs +60 -0
- package/packages/evidence/dns-query-outcome.mjs +72 -0
- package/packages/evidence/email-recipient.mjs +18 -0
- package/packages/evidence/image-regions.mjs +15 -0
- package/packages/evidence/lookup-target.mjs +5 -1
- package/packages/evidence/observation.mjs +2 -0
- package/packages/evidence/png-pixels.mjs +117 -0
- package/packages/evidence/public-address-policy.mjs +83 -0
- package/packages/evidence/record-identity.mjs +60 -16
- package/packages/evidence/technology-evidence-role.mjs +51 -0
- package/packages/interchange/defensive-indicator-export.mjs +264 -0
- package/packages/interchange/external-findings-import.mjs +36 -29
- package/packages/interchange/json-output.mjs +14 -0
- package/packages/interchange/managed-indicator-export.mjs +36 -0
- package/packages/interchange/managed-indicator-set.mjs +223 -0
- package/packages/interchange/misp-indicator-export.mjs +93 -0
- package/packages/interchange/sharing-policy.mjs +56 -0
- package/packages/interchange/stix-indicator-export.mjs +129 -0
- package/packages/interchange/web-capture-import.mjs +22 -15
- package/packages/investigation/acquisition-decision-packet.mjs +79 -1
- package/packages/investigation/bulk-mail-exposure.mjs +7 -13
- package/packages/investigation/capture-coverage.mjs +57 -0
- package/packages/investigation/connector-provenance-review.mjs +100 -0
- package/packages/investigation/context-review.mjs +35 -0
- package/packages/investigation/document-intake.mjs +87 -0
- package/packages/investigation/docx-intake.mjs +133 -0
- package/packages/investigation/domain-history-review.mjs +132 -0
- package/packages/investigation/domain-transition-review.mjs +49 -0
- package/packages/investigation/evidence-coverage-ledger.mjs +9 -1
- package/packages/investigation/har-intake.mjs +68 -0
- package/packages/investigation/identity-event-intake.mjs +131 -0
- package/packages/investigation/identity-incident-review.mjs +39 -0
- package/packages/investigation/incident-sequence-review.mjs +58 -0
- package/packages/investigation/infrastructure-observation.mjs +234 -0
- package/packages/investigation/intake-context.mjs +284 -0
- package/packages/investigation/intake-indicators.mjs +116 -0
- package/packages/investigation/intake-phones.mjs +155 -0
- package/packages/investigation/intake-report.mjs +20 -0
- package/packages/investigation/investigation-manifest.mjs +35 -9
- package/packages/investigation/link-intake.mjs +209 -0
- package/packages/investigation/lookup-asset-graph.mjs +1 -1
- package/packages/investigation/mail-authentication-review.mjs +222 -0
- package/packages/investigation/mail-header-identity.mjs +209 -0
- package/packages/investigation/message-intake.mjs +235 -0
- package/packages/investigation/page-behaviour.mjs +113 -0
- package/packages/investigation/pdf-intake.mjs +155 -0
- package/packages/investigation/platform-continuity-review.mjs +60 -0
- package/packages/investigation/qr-intake.mjs +56 -0
- package/packages/investigation/requested-action-hints.mjs +11 -0
- package/packages/investigation/selected-input-review.mjs +17 -0
- package/packages/investigation/storefront-review.mjs +70 -0
- package/packages/monitoring/domain-feed.mjs +321 -0
- package/packages/workspace/brand-candidate-workflow.mjs +351 -0
- package/packages/workspace/brand-keyword-campaign.mjs +231 -0
- package/packages/workspace/brand-profile-model.mjs +48 -4
- package/packages/workspace/bulk-review-model.mjs +28 -26
- package/packages/workspace/bulk-session-model.mjs +27 -13
- package/packages/workspace/campaign-model.mjs +1 -1
- package/packages/workspace/candidate-watch-handoff.mjs +195 -0
- package/packages/workspace/detection-rule-model.mjs +11 -3
- package/packages/workspace/hostile-input.mjs +1 -1
- package/packages/workspace/investigation-guide.mjs +2 -2
- package/packages/workspace/investigation-template-model.mjs +26 -2
- package/packages/workspace/page-baseline.mjs +2 -2
- package/packages/workspace/relationship-observation-model.mjs +17 -13
- package/packages/workspace/shortlist-model.mjs +24 -7
- package/packages/workspace/watchlist-history.mjs +59 -16
- package/packages/workspace/watchlist-store.mjs +152 -11
- package/packages/workspace/website-snapshot-model.mjs +28 -3
- package/packages/workspace/workspace-archive-crypto.mjs +1 -1
- package/packages/workspace/workspace-archive.mjs +5 -4
- package/third-party-notices.txt +549 -16
- package/lib/hostname.mjs +0 -2
|
@@ -14,6 +14,7 @@ export const CAPABILITY_IDS = Object.freeze({
|
|
|
14
14
|
URLSCAN_SEARCH: 'urlscan_search',
|
|
15
15
|
URLHAUS_HOST: 'urlhaus_host',
|
|
16
16
|
THREATFOX_DOMAIN_IOC: 'threatfox_domain_ioc',
|
|
17
|
+
DOMAIN_FEED_SEARCH: 'domain_feed_search',
|
|
17
18
|
REGISTRAR_RDAP: 'registrar_rdap',
|
|
18
19
|
NETWORK_CONTEXT: 'network_context',
|
|
19
20
|
REVERSE_DNS: 'reverse_dns',
|
|
@@ -76,9 +77,11 @@ export const CLI_COMMAND_SEMANTICS = Object.freeze({
|
|
|
76
77
|
'page-compare': semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
77
78
|
'mail-review': semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
78
79
|
'mail-headers': semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
80
|
+
intake: semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
79
81
|
'review-evidence': semantic('investigate', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
80
82
|
brief: semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
81
83
|
case: semantic('respond', CAPABILITY_IDS.ANALYST_CASES),
|
|
84
|
+
'indicator-set': semantic('respond', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
82
85
|
'case-pack': semantic('respond', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
83
86
|
'domain-control': semantic('assure', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
84
87
|
'monitor-once': semantic('assure', CAPABILITY_IDS.LOOKUP),
|
|
@@ -86,6 +89,8 @@ export const CLI_COMMAND_SEMANTICS = Object.freeze({
|
|
|
86
89
|
'change-packet': semantic('respond', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
87
90
|
'sharing-review': semantic('respond', CAPABILITY_IDS.PORTABLE_EVIDENCE),
|
|
88
91
|
'workflow-plan': semantic('assure', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
92
|
+
'watchlist-review': semantic('assure', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
93
|
+
'domain-feed': semantic('investigate', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
89
94
|
'workflow-run': semantic('assure', CAPABILITY_IDS.WORKFLOW_EXECUTION),
|
|
90
95
|
diff: semantic('assure', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
91
96
|
reconcile: semantic('assure', CAPABILITY_IDS.OFFLINE_REVIEW),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { MAX_INVESTIGATION_MANIFEST_ARTIFACTS } from "./investigation-package-limits.mjs";
|
|
2
|
+
export const MAX_CLI_ARGUMENTS = MAX_INVESTIGATION_MANIFEST_ARTIFACTS + 32;
|
|
3
|
+
export const MAX_CLI_ARGUMENT_LENGTH = 1024;
|
|
4
|
+
export function hasUnsafeCliText(value) {
|
|
5
|
+
return /[\x00-\x1f\x7f-\x9f]|\p{Default_Ignorable_Code_Point}/u.test(value);
|
|
6
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Common presentation of bounded, analyst-selected contextual evidence. */
|
|
2
|
+
export const CONTEXT_REVIEW_SCHEMA = 'whoisleuth.context-review';
|
|
3
|
+
export const CONTEXT_REVIEW_VERSION = 1;
|
|
4
|
+
export const DOMAIN_HISTORY_INPUT_SCHEMA = 'whoisleuth.domain-history.input';
|
|
5
|
+
export const DOMAIN_HISTORY_INPUT_VERSION = 2;
|
|
6
|
+
export const DOMAIN_HISTORY_LEGACY_INPUT_VERSION = 1;
|
|
7
|
+
export const PLATFORM_CONTINUITY_INPUT_SCHEMA = 'whoisleuth.platform-continuity.input';
|
|
8
|
+
export const PLATFORM_CONTINUITY_INPUT_VERSION = 1;
|
|
9
|
+
export const STOREFRONT_INPUT_SCHEMA = 'whoisleuth.storefront-review.input';
|
|
10
|
+
export const STOREFRONT_INPUT_VERSION = 1;
|
|
11
|
+
export const CONNECTOR_INPUT_SCHEMA = 'whoisleuth.connector-review.input';
|
|
12
|
+
export const CONNECTOR_INPUT_VERSION = 1;
|
|
13
|
+
export const INCIDENT_SEQUENCE_INPUT_SCHEMA = 'whoisleuth.incident-sequence.input';
|
|
14
|
+
export const INCIDENT_SEQUENCE_INPUT_VERSION = 1;
|
|
15
|
+
export const CONTEXT_INPUT_CONTRACTS = [
|
|
16
|
+
{ schema: DOMAIN_HISTORY_INPUT_SCHEMA, version: DOMAIN_HISTORY_INPUT_VERSION },
|
|
17
|
+
{ schema: PLATFORM_CONTINUITY_INPUT_SCHEMA, version: PLATFORM_CONTINUITY_INPUT_VERSION },
|
|
18
|
+
{ schema: STOREFRONT_INPUT_SCHEMA, version: STOREFRONT_INPUT_VERSION },
|
|
19
|
+
{ schema: CONNECTOR_INPUT_SCHEMA, version: CONNECTOR_INPUT_VERSION },
|
|
20
|
+
{ schema: INCIDENT_SEQUENCE_INPUT_SCHEMA, version: INCIDENT_SEQUENCE_INPUT_VERSION },
|
|
21
|
+
];
|
|
22
|
+
export const CONTEXT_INPUT_SCHEMAS = CONTEXT_INPUT_CONTRACTS.map(input => input.schema);
|
|
23
|
+
export const MAX_CONTEXT_INPUT_BYTES = 16 * 1024 * 1024;
|
|
24
|
+
export const MAX_CONTEXT_RECORDS = 200;
|
|
25
|
+
export const CONTEXT_REVIEW_KINDS = ['domain_history', 'platform_continuity', 'storefront', 'connector', 'incident_sequence'];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Input admission, decoded XML, page work and pixels are independently bounded. */
|
|
2
|
+
export const MAX_DOCUMENT_PARTS = 512;
|
|
3
|
+
export const MAX_DOCUMENT_PAGES = 256;
|
|
4
|
+
export const MAX_DOCUMENT_DECODED_BYTES = 32 * 1024 * 1024;
|
|
5
|
+
export const MAX_DOCUMENT_TEXT_BYTES = 8 * 1024 * 1024;
|
|
6
|
+
export const MAX_DOCUMENT_XML_NODES = 200_000;
|
|
7
|
+
export const MAX_DOCUMENT_PAGE_OPERATIONS = 200_000;
|
|
8
|
+
export const MAX_DOCUMENT_XML_DEPTH = 64;
|
|
9
|
+
export const MAX_DOCUMENT_IMAGE_PIXELS = 16 * 1024 * 1024;
|
|
10
|
+
export const MAX_DOCUMENT_TOTAL_IMAGE_PIXELS = 64 * 1024 * 1024;
|
|
11
|
+
export const DOCUMENT_REVIEW_DEADLINE_MS = 60_000;
|
|
@@ -5,8 +5,8 @@ import { MAX_DOMAIN_CONTROL_MONITOR_CONCURRENCY, MAX_DOMAIN_CONTROL_MONITOR_DOMA
|
|
|
5
5
|
export const DOMAIN_CONTROL_FLIGHT_RECORDER_INPUT_SCHEMA = 'whoisleuth.domain-control-flight-recorder.input';
|
|
6
6
|
export const DOMAIN_CONTROL_FLIGHT_RECORDER_SCHEMA = 'whoisleuth.domain-control-flight-recorder';
|
|
7
7
|
export const PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION = 1;
|
|
8
|
-
export const DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION =
|
|
9
|
-
export const SUPPORTED_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSIONS = [PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION, DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION];
|
|
8
|
+
export const DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION = 3;
|
|
9
|
+
export const SUPPORTED_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSIONS = [PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION, 2, DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION];
|
|
10
10
|
export const MIN_FLIGHT_RECORDER_OBSERVATIONS = 1;
|
|
11
11
|
export const MAX_FLIGHT_RECORDER_OBSERVATIONS = 200;
|
|
12
12
|
export const MAX_FLIGHT_RECORDER_WINDOWS = 40;
|
|
@@ -95,11 +95,14 @@ export const PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_EVENT_KEYS = Object.freeze([
|
|
|
95
95
|
'approvedWindow',
|
|
96
96
|
'explanation',
|
|
97
97
|
]);
|
|
98
|
-
export const
|
|
99
|
-
export const
|
|
98
|
+
export const SOURCE_TIMED_FLIGHT_RECORDER_EVENT_KEYS = Object.freeze([...PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_EVENT_KEYS, 'capturedAt']);
|
|
99
|
+
export const DOMAIN_CONTROL_FLIGHT_RECORDER_EVENT_KEYS = Object.freeze([...SOURCE_TIMED_FLIGHT_RECORDER_EVENT_KEYS, 'collectionDepth', 'changeInterval']);
|
|
100
|
+
export const FLIGHT_RECORDER_CHANGE_INTERVAL_KEYS = Object.freeze(['after', 'by', 'incompleteObservations']);
|
|
101
|
+
export const HISTORICAL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS = Object.freeze([
|
|
100
102
|
'id',
|
|
101
103
|
'reason',
|
|
102
104
|
]);
|
|
105
|
+
export const DOMAIN_CONTROL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS = Object.freeze([...HISTORICAL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS, 'startsAt', 'endsAt']);
|
|
103
106
|
export const PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_SUMMARY_KEYS = Object.freeze([
|
|
104
107
|
'firstObservations',
|
|
105
108
|
'observedChanges',
|
|
@@ -115,10 +118,14 @@ export const PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_LIMITATIONS = Object.freeze([
|
|
|
115
118
|
'Approved windows label expected timing but do not delete evidence or establish that a change was authorised, successful, safe, or complete.',
|
|
116
119
|
'Observed changes can reflect publication lag or different collection conditions and require analyst review.',
|
|
117
120
|
]);
|
|
118
|
-
export const
|
|
121
|
+
export const SOURCE_TIMED_FLIGHT_RECORDER_LIMITATIONS = Object.freeze([
|
|
119
122
|
...PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_LIMITATIONS,
|
|
120
123
|
'Capture time and source observation time remain separate. Unknown, conflicting or non-increasing source times cannot establish an observed change.',
|
|
121
124
|
]);
|
|
125
|
+
export const DOMAIN_CONTROL_FLIGHT_RECORDER_LIMITATIONS = Object.freeze([
|
|
126
|
+
...SOURCE_TIMED_FLIGHT_RECORDER_LIMITATIONS,
|
|
127
|
+
'A change interval is bounded by comparable complete source observations, not an exact change time. Incomplete observations inside it remain explicit. An approved window must contain the whole interval.',
|
|
128
|
+
]);
|
|
122
129
|
export const DOMAIN_CONTROL_FLIGHT_RECORDER_INPUT_COMPATIBILITY = defineSchemaCompatibility({
|
|
123
130
|
id: 'cli.domain-control-flight-recorder-input',
|
|
124
131
|
kind: 'cli_document',
|
|
@@ -224,14 +231,22 @@ export const DOMAIN_CONTROL_FLIGHT_RECORDER_SCHEMA_LIFECYCLE = defineSchemaLifec
|
|
|
224
231
|
scope: 'repository',
|
|
225
232
|
},
|
|
226
233
|
].flatMap((fixture) => {
|
|
227
|
-
const version = DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION;
|
|
228
|
-
const id = fixture.id.replace(/v\d+$/u, `v${version}`);
|
|
229
|
-
const content = fixture.role === 'input'
|
|
230
|
-
? { bytes: 2108, sha256: '6998ea864355dd0802b3b6f2c4905f8c84136ad0d4ac9cad1a0fd63dca523b60' }
|
|
231
|
-
: { bytes: 4649, sha256: '8f3168d101291166f34cede351bc176a934e7997920cd8c22ec00d642ec000df' };
|
|
232
234
|
return [
|
|
233
235
|
{ ...fixture, role: fixture.role === 'input' ? 'input' : 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
234
|
-
|
|
236
|
+
...[2, DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION].map(version => {
|
|
237
|
+
const id = fixture.id.replace(/v\d+$/u, `v${version}`);
|
|
238
|
+
const content = version === 2
|
|
239
|
+
? fixture.role === 'input'
|
|
240
|
+
? { bytes: 2108, sha256: '6998ea864355dd0802b3b6f2c4905f8c84136ad0d4ac9cad1a0fd63dca523b60' }
|
|
241
|
+
: { bytes: 4649, sha256: '8f3168d101291166f34cede351bc176a934e7997920cd8c22ec00d642ec000df' }
|
|
242
|
+
: fixture.role === 'input'
|
|
243
|
+
? { bytes: 2108, sha256: '3d9b91dfd34754482047cde64d6343676ec4747267677fcbcc989a65fbd9a6c6' }
|
|
244
|
+
: { bytes: 5597, sha256: 'ab6a82cfecfb8238a72fbe2dcd4a68a1fd888990e5070eff9d98a337796624d6' };
|
|
245
|
+
return { ...fixture, ...content, id, path: `test/fixtures/${id}.json`, version,
|
|
246
|
+
role: fixture.role === 'input' ? 'input' : version === DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION ? 'current' : 'historical',
|
|
247
|
+
expectation: version === DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION ? fixture.expectation : 'accepted_exact',
|
|
248
|
+
expectedOutputFixtureId: version === DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION ? fixture.expectedOutputFixtureId?.replace(/v\d+$/u, `v${version}`) ?? null : null };
|
|
249
|
+
}),
|
|
235
250
|
];
|
|
236
251
|
}),
|
|
237
252
|
metadata: {
|
|
@@ -257,11 +272,12 @@ export const DOMAIN_CONTROL_FLIGHT_RECORDER_SCHEMA_LIFECYCLE = defineSchemaLifec
|
|
|
257
272
|
versions: [version],
|
|
258
273
|
objects: [
|
|
259
274
|
{ path: '$', requiredKeys: DOMAIN_CONTROL_FLIGHT_RECORDER_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
260
|
-
{ path: '$.events[]', requiredKeys: version ===
|
|
261
|
-
{ path: '$.events[].approvedWindow', requiredKeys: DOMAIN_CONTROL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
275
|
+
{ path: '$.events[]', requiredKeys: version === 1 ? PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_EVENT_KEYS : version === 2 ? SOURCE_TIMED_FLIGHT_RECORDER_EVENT_KEYS : DOMAIN_CONTROL_FLIGHT_RECORDER_EVENT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
276
|
+
{ path: '$.events[].approvedWindow', requiredKeys: version >= 3 ? DOMAIN_CONTROL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS : HISTORICAL_FLIGHT_RECORDER_APPROVED_WINDOW_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
277
|
+
...(version >= 3 ? [{ path: '$.events[].changeInterval', requiredKeys: FLIGHT_RECORDER_CHANGE_INTERVAL_KEYS, optionalKeys: [], unknownKeys: 'reject' }] : []),
|
|
262
278
|
{ path: '$.summary', requiredKeys: version === PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_VERSION ? PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_SUMMARY_KEYS : DOMAIN_CONTROL_FLIGHT_RECORDER_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
263
279
|
],
|
|
264
|
-
fixedArrays: [{ path: '$.limitations', values: version ===
|
|
280
|
+
fixedArrays: [{ path: '$.limitations', values: version === 1 ? PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_LIMITATIONS : version === 2 ? SOURCE_TIMED_FLIGHT_RECORDER_LIMITATIONS : DOMAIN_CONTROL_FLIGHT_RECORDER_LIMITATIONS }],
|
|
265
281
|
normalisation: 'preserve_document',
|
|
266
282
|
target: null,
|
|
267
283
|
},
|
|
@@ -410,7 +410,7 @@ export const DOMAIN_CONTROL_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamily({
|
|
|
410
410
|
bounds: [
|
|
411
411
|
{ id: 'exported-entries', path: '$.selectedDomains', phase: 'action', unit: 'entries', minimum: 1, maximum: MAX_DOMAIN_CONTROL_BROWSER_PROFILE_ENTRIES, handling: 'cap_operation' },
|
|
412
412
|
{ id: 'previewed-entries', path: '$.verifiedManifest.entries', phase: 'action', unit: 'entries', minimum: 1, maximum: MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES, handling: 'reject' },
|
|
413
|
-
{ id: 'applied-baselines', path: '$.choices', phase: 'action', unit: 'entries', minimum: 0, maximum: MAX_DOMAIN_CONTROL_BROWSER_PROFILE_ENTRIES, handling: '
|
|
413
|
+
{ id: 'applied-baselines', path: '$.choices', phase: 'action', unit: 'entries', minimum: 0, maximum: MAX_DOMAIN_CONTROL_BROWSER_PROFILE_ENTRIES, handling: 'reject' },
|
|
414
414
|
],
|
|
415
415
|
},
|
|
416
416
|
{
|
|
@@ -2,8 +2,13 @@ import { defineSchemaCompatibility } from "./schema-compatibility.mjs";
|
|
|
2
2
|
import { defineSchemaLifecycleFamily } from "./schema-lifecycle.mjs";
|
|
3
3
|
export const CLI_DOMAIN_CONTROL_MONITOR_SCHEMA = 'whoisleuth.cli.domain-control-monitor';
|
|
4
4
|
export const PUBLIC_CLI_DOMAIN_CONTROL_MONITOR_VERSION = 1;
|
|
5
|
-
export const CLI_DOMAIN_CONTROL_MONITOR_VERSION =
|
|
6
|
-
export const SUPPORTED_CLI_DOMAIN_CONTROL_MONITOR_VERSIONS = [PUBLIC_CLI_DOMAIN_CONTROL_MONITOR_VERSION, CLI_DOMAIN_CONTROL_MONITOR_VERSION];
|
|
5
|
+
export const CLI_DOMAIN_CONTROL_MONITOR_VERSION = 3;
|
|
6
|
+
export const SUPPORTED_CLI_DOMAIN_CONTROL_MONITOR_VERSIONS = [PUBLIC_CLI_DOMAIN_CONTROL_MONITOR_VERSION, 2, CLI_DOMAIN_CONTROL_MONITOR_VERSION];
|
|
7
|
+
export const DOMAIN_CONTROL_MONITOR_EMBEDDED_VERSIONS = Object.freeze({
|
|
8
|
+
1: Object.freeze({ review: 1, flightRecorder: 1 }),
|
|
9
|
+
2: Object.freeze({ review: 2, flightRecorder: 2 }),
|
|
10
|
+
3: Object.freeze({ review: 3, flightRecorder: 3 }),
|
|
11
|
+
});
|
|
7
12
|
export const MAX_DOMAIN_CONTROL_MONITOR_INPUT_BYTES = 16 * 1024 * 1024;
|
|
8
13
|
export const MAX_DOMAIN_CONTROL_MONITOR_JSON_DEPTH = 48;
|
|
9
14
|
export const MAX_DOMAIN_CONTROL_MONITOR_JSON_KEYS = 50_000;
|
|
@@ -100,6 +105,12 @@ export const DOMAIN_CONTROL_MONITOR_SCHEMA_LIFECYCLE = defineSchemaLifecycleFami
|
|
|
100
105
|
{
|
|
101
106
|
id: 'domain-control-monitor-v2', path: 'test/fixtures/domain-control-monitor-v2.json',
|
|
102
107
|
bytes: 18_023, sha256: 'f4017f3dc84b3adb6b6114ea49c37ff05939779daabbbb56c868010145cac55c',
|
|
108
|
+
contentDigestSha256: null, schema: CLI_DOMAIN_CONTROL_MONITOR_SCHEMA, version: 2,
|
|
109
|
+
role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null, scope: 'repository',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'domain-control-monitor-v3', path: 'test/fixtures/domain-control-monitor-v3.json',
|
|
113
|
+
bytes: 19_215, sha256: 'a7233a0b52b282e3ad8097b9bd71bf15125b743e60a421cfec765cb8b9456563',
|
|
103
114
|
contentDigestSha256: null, schema: CLI_DOMAIN_CONTROL_MONITOR_SCHEMA, version: CLI_DOMAIN_CONTROL_MONITOR_VERSION,
|
|
104
115
|
role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null, scope: 'repository',
|
|
105
116
|
},
|
|
@@ -10,10 +10,10 @@ export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA = 'whoisleuth.cli.domain-con
|
|
|
10
10
|
export const CLI_DOMAIN_CONTROL_REVIEW_SCHEMA = 'whoisleuth.cli.domain-control-review';
|
|
11
11
|
export const PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION = 1;
|
|
12
12
|
export const PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION = 1;
|
|
13
|
-
export const DOMAIN_CONTROL_REVIEW_VERSION =
|
|
14
|
-
export const CLI_DOMAIN_CONTROL_REVIEW_VERSION =
|
|
15
|
-
export const SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION, DOMAIN_CONTROL_REVIEW_VERSION];
|
|
16
|
-
export const SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION, CLI_DOMAIN_CONTROL_REVIEW_VERSION];
|
|
13
|
+
export const DOMAIN_CONTROL_REVIEW_VERSION = 3;
|
|
14
|
+
export const CLI_DOMAIN_CONTROL_REVIEW_VERSION = 3;
|
|
15
|
+
export const SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION, 2, DOMAIN_CONTROL_REVIEW_VERSION];
|
|
16
|
+
export const SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION, 2, CLI_DOMAIN_CONTROL_REVIEW_VERSION];
|
|
17
17
|
export const DOMAIN_CONTROL_REVIEW_OBSERVATION_FACTOR = 2;
|
|
18
18
|
export const MAX_DOMAIN_CONTROL_REVIEW_OBSERVATIONS = MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES
|
|
19
19
|
* DOMAIN_CONTROL_REVIEW_OBSERVATION_FACTOR;
|
|
@@ -87,7 +87,8 @@ export const PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([
|
|
|
87
87
|
'not_configured',
|
|
88
88
|
'due',
|
|
89
89
|
]);
|
|
90
|
-
export const
|
|
90
|
+
export const DOMAIN_CONTROL_REVIEW_V2_COUNT_KEYS = Object.freeze([...PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS, 'observed']);
|
|
91
|
+
export const DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([...DOMAIN_CONTROL_REVIEW_V2_COUNT_KEYS, 'not_due']);
|
|
91
92
|
export const DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS = Object.freeze([
|
|
92
93
|
'domain',
|
|
93
94
|
'state',
|
|
@@ -108,11 +109,21 @@ export const PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
|
|
|
108
109
|
'Only complete observations can produce drift. Partial, unavailable, unsupported, or missing evidence remains inconclusive.',
|
|
109
110
|
'A valid manifest digest or signature establishes file integrity, not the correctness of the desired state or supplied observations.',
|
|
110
111
|
]);
|
|
111
|
-
export const
|
|
112
|
+
export const DOMAIN_CONTROL_REVIEW_V2_LIMITATIONS = Object.freeze([
|
|
112
113
|
PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS[0],
|
|
113
114
|
'Only complete observations with valid source times within the current review-age window can establish alignment, drift or expected absence. Observation-only fields do not establish alignment.',
|
|
114
115
|
PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS[2],
|
|
115
116
|
]);
|
|
117
|
+
export const DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
|
|
118
|
+
...DOMAIN_CONTROL_REVIEW_V2_LIMITATIONS,
|
|
119
|
+
'Renewal dates are analyst-authored reminders, not observations of configuration.',
|
|
120
|
+
]);
|
|
121
|
+
export function domainControlReviewCountKeys(version) {
|
|
122
|
+
return version === 1 ? PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS : version === 2 ? DOMAIN_CONTROL_REVIEW_V2_COUNT_KEYS : DOMAIN_CONTROL_REVIEW_COUNT_KEYS;
|
|
123
|
+
}
|
|
124
|
+
export function domainControlReviewLimitations(version) {
|
|
125
|
+
return version === 1 ? PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS : version === 2 ? DOMAIN_CONTROL_REVIEW_V2_LIMITATIONS : DOMAIN_CONTROL_REVIEW_LIMITATIONS;
|
|
126
|
+
}
|
|
116
127
|
export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_KEYS = Object.freeze([
|
|
117
128
|
'schema',
|
|
118
129
|
'version',
|
|
@@ -233,11 +244,11 @@ const CORE_REVIEW_SHAPES = SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.flatMap((ver
|
|
|
233
244
|
objects: [
|
|
234
245
|
{ path: '$', requiredKeys: DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
235
246
|
{ path: '$.manifest', requiredKeys: DOMAIN_CONTROL_REVIEW_MANIFEST_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
236
|
-
{ path: '$.counts', requiredKeys: version
|
|
247
|
+
{ path: '$.counts', requiredKeys: domainControlReviewCountKeys(version), optionalKeys: [], unknownKeys: 'reject' },
|
|
237
248
|
{ path: '$.domains[]', requiredKeys: DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
238
249
|
{ path: '$.domains[].comparisons[]', requiredKeys: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS : DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, optionalKeys: [], unknownKeys: 'reject' },
|
|
239
250
|
],
|
|
240
|
-
fixedArrays: [{ path: '$.limitations', values: version
|
|
251
|
+
fixedArrays: [{ path: '$.limitations', values: domainControlReviewLimitations(version) }],
|
|
241
252
|
normalisation: 'preserve_document',
|
|
242
253
|
target: null,
|
|
243
254
|
},
|
|
@@ -253,6 +264,10 @@ function reviewFixtureShapeId(schema, version) {
|
|
|
253
264
|
return `domain-control-review.${cli ? 'cli-' : ''}${schema.endsWith('-input') ? 'input' : 'document'}.v${version}`;
|
|
254
265
|
}
|
|
255
266
|
const CURRENT_REVIEW_FIXTURE_CONTENT = {
|
|
267
|
+
"domain-control-review-input-v3": { "bytes": 1879, "sha256": "747cccb9a0610dd5b77ebd2a01f44dc7bd6a929b09b6e52037596427d0c2275b" },
|
|
268
|
+
"domain-control-review-v3": { "bytes": 4496, "sha256": "736926cf402ca868ddc832c229b88d3c91b44a4c73563c356633a69c1ec8d06c" },
|
|
269
|
+
"cli-domain-control-review-input-v3": { "bytes": 4123, "sha256": "0283efe6f78551a8aa5a9449a608fb4f3b46b39a9f11f6ffe93244979b16d30b" },
|
|
270
|
+
"cli-domain-control-review-v3": { "bytes": 9194, "sha256": "31c263f17cd663be74ab9801970a8800894da4023842137e41f602fde633452e" },
|
|
256
271
|
"domain-control-review-input-v2": {
|
|
257
272
|
"bytes": 1879,
|
|
258
273
|
"sha256": "ac3b5913a44c47bd179cd69e4a8bf4268f10e9f01dd7f59c7d722a8c0d241ad1"
|
|
@@ -408,13 +423,19 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
|
|
|
408
423
|
scope: 'repository',
|
|
409
424
|
},
|
|
410
425
|
].flatMap((fixture) => {
|
|
411
|
-
const
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
426
|
+
const currentVersion = fixture.schema.startsWith('whoisleuth.cli.') ? CLI_DOMAIN_CONTROL_REVIEW_VERSION : DOMAIN_CONTROL_REVIEW_VERSION;
|
|
427
|
+
const versions = fixture.schema.startsWith('whoisleuth.cli.') ? SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS : SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS;
|
|
428
|
+
return versions.map((version) => {
|
|
429
|
+
const id = fixture.id.replace(/v\d+$/u, `v${version}`);
|
|
430
|
+
const current = version === currentVersion;
|
|
431
|
+
return {
|
|
432
|
+
...fixture, ...(version === 1 ? {} : CURRENT_REVIEW_FIXTURE_CONTENT[id]), id,
|
|
433
|
+
path: `test/fixtures/${id}.json`, version, shapeId: reviewFixtureShapeId(fixture.schema, version),
|
|
434
|
+
role: fixture.role === 'input' ? 'input' : current ? 'current' : 'historical',
|
|
435
|
+
expectation: current ? fixture.expectation : fixture.schema === CLI_DOMAIN_CONTROL_REVIEW_SCHEMA ? 'historical_output_exact' : 'accepted_exact',
|
|
436
|
+
expectedOutputFixtureId: current ? fixture.expectedOutputFixtureId?.replace(/v\d+$/u, `v${version}`) ?? null : null,
|
|
437
|
+
};
|
|
438
|
+
});
|
|
418
439
|
}),
|
|
419
440
|
metadata: {
|
|
420
441
|
enforcement: 'declarative_only',
|
|
@@ -2,8 +2,8 @@ import { defineSchemaCompatibility } from "./schema-compatibility.mjs";
|
|
|
2
2
|
import { defineSchemaLifecycleFamily } from "./schema-lifecycle.mjs";
|
|
3
3
|
export const EXTERNAL_OBSERVATION_INTERCHANGE_CONTRACT_OWNER = 'packages/contracts/external-observation-interchange.mts';
|
|
4
4
|
export const EXTERNAL_FINDINGS_SCHEMA = 'whoisleuth.external-findings';
|
|
5
|
-
export const EXTERNAL_FINDINGS_VERSION =
|
|
6
|
-
export const SUPPORTED_EXTERNAL_FINDINGS_VERSIONS = Object.freeze([
|
|
5
|
+
export const EXTERNAL_FINDINGS_VERSION = 5;
|
|
6
|
+
export const SUPPORTED_EXTERNAL_FINDINGS_VERSIONS = Object.freeze([4, 5]);
|
|
7
7
|
export const MAX_EXTERNAL_FINDINGS_IMPORT_BYTES = 384 * 1024;
|
|
8
8
|
export const MAX_EXTERNAL_FINDINGS = 100;
|
|
9
9
|
export const MAX_EXTERNAL_FINDINGS_PER_DOMAIN = 20;
|
|
@@ -17,6 +17,19 @@ export const DNS_OBSERVATION_ROWS_SCHEMA = 'whoisleuth.dns-observation-rows';
|
|
|
17
17
|
export const CERTIFICATE_OBSERVATION_ROWS_SCHEMA = 'whoisleuth.certificate-observation-rows';
|
|
18
18
|
export const SUPPORTED_OBSERVATION_ROWS_VERSION = 1;
|
|
19
19
|
export const MAX_CONVERSION_INPUT_ROWS = MAX_EXTERNAL_FINDINGS * 4;
|
|
20
|
+
export const INFRASTRUCTURE_OBSERVATION_SCHEMA = 'whoisleuth.infrastructure-observation';
|
|
21
|
+
export const INFRASTRUCTURE_OBSERVATION_VERSION = 1;
|
|
22
|
+
export const MAX_INFRASTRUCTURE_OBSERVATION_BYTES = 128 * 1024;
|
|
23
|
+
export const MAX_INFRASTRUCTURE_HOSTS = 128;
|
|
24
|
+
export const MAX_INFRASTRUCTURE_DNS_ROWS = 512;
|
|
25
|
+
export const MAX_INFRASTRUCTURE_CERTIFICATES = 32;
|
|
26
|
+
export const MAX_INFRASTRUCTURE_ROLES = 128;
|
|
27
|
+
export const MAX_INFRASTRUCTURE_SOURCES = 16;
|
|
28
|
+
export const MAX_INFRASTRUCTURE_LIMITATIONS = 12;
|
|
29
|
+
export const INFRASTRUCTURE_DNS_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR'];
|
|
30
|
+
export const INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA = 'whoisleuth.infrastructure-comparison.input';
|
|
31
|
+
export const INFRASTRUCTURE_COMPARISON_INPUT_VERSION = 1;
|
|
32
|
+
export const MAX_INFRASTRUCTURE_COMPARISON_INPUT_BYTES = 2 * MAX_INFRASTRUCTURE_OBSERVATION_BYTES + 1_024;
|
|
20
33
|
export const EXTERNAL_OBSERVATION_INTERCHANGE_COMPATIBILITY_FACADES = Object.freeze([
|
|
21
34
|
['frontend/src/lib/analysis/external-findings-import.ts', 'packages/interchange/external-findings-import.mts'],
|
|
22
35
|
['frontend/src/lib/analysis/external-findings-converters.ts', 'packages/interchange/external-findings-converters.mts'],
|
|
@@ -24,9 +37,9 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_COMPATIBILITY_FACADES = Object.fre
|
|
|
24
37
|
export const EXTERNAL_FINDINGS_COMPATIBILITY = defineSchemaCompatibility({
|
|
25
38
|
id: 'export.external-findings', kind: 'export', schema: EXTERNAL_FINDINGS_SCHEMA,
|
|
26
39
|
currentVersion: EXTERNAL_FINDINGS_VERSION, supportedVersions: SUPPORTED_EXTERNAL_FINDINGS_VERSIONS,
|
|
27
|
-
acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: '
|
|
40
|
+
acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'none', writeSemantics: 'non_destructive_merge',
|
|
28
41
|
byteBudget: MAX_EXTERNAL_FINDINGS_IMPORT_BYTES, owner: EXTERNAL_OBSERVATION_INTERCHANGE_CONTRACT_OWNER,
|
|
29
|
-
note: 'Strict local findings import.
|
|
42
|
+
note: 'Strict local findings import. Historical version 4 is preserved exactly; version 5 adds an optional exact source-qualified infrastructure snapshot. No collection is initiated.',
|
|
30
43
|
});
|
|
31
44
|
export const EXTERNAL_FINDING_ROWS_COMPATIBILITY = defineSchemaCompatibility({
|
|
32
45
|
id: 'import.external-finding-rows', kind: 'export', schema: EXTERNAL_FINDING_ROWS_SCHEMA,
|
|
@@ -62,17 +75,26 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_COMPATIBILITY = Object.freeze([
|
|
|
62
75
|
DOMAIN_OBSERVATION_ROWS_COMPATIBILITY,
|
|
63
76
|
DNS_OBSERVATION_ROWS_COMPATIBILITY,
|
|
64
77
|
CERTIFICATE_OBSERVATION_ROWS_COMPATIBILITY,
|
|
78
|
+
defineSchemaCompatibility({ id: 'export.infrastructure-observation', kind: 'export', schema: INFRASTRUCTURE_OBSERVATION_SCHEMA, currentVersion: 1, supportedVersions: [1], acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'exact_current_only', writeSemantics: 'read_only', byteBudget: MAX_INFRASTRUCTURE_OBSERVATION_BYTES, owner: EXTERNAL_OBSERVATION_INTERCHANGE_CONTRACT_OWNER, note: 'Exact source-qualified selected infrastructure evidence retained through existing Case pins. Wildcards, DNS outcomes and independent provider roles remain distinct.' }),
|
|
79
|
+
defineSchemaCompatibility({ id: 'cli.infrastructure-comparison-input', kind: 'cli_document', schema: INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA, currentVersion: 1, supportedVersions: [1], acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'read_only', writeSemantics: 'read_only', byteBudget: MAX_INFRASTRUCTURE_COMPARISON_INPUT_BYTES, owner: EXTERNAL_OBSERVATION_INTERCHANGE_CONTRACT_OWNER, note: 'An explicit earlier/later snapshot pair reviewed offline without collection, persistence or current absence claims.' }),
|
|
65
80
|
]);
|
|
66
81
|
const EXTERNAL_INTERCHANGE_FIXTURES = Object.freeze([
|
|
67
|
-
{ id: 'external-findings-v4', path: 'test/fixtures/external-observation-interchange/external-findings-v4.json', bytes: 634, sha256: 'ceab916e1dcf99704c94e1b0cd82f5a061f138ae6a07ce8335273080c73b7624', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: '
|
|
68
|
-
{ id: 'external-finding-rows-v1', path: 'test/fixtures/external-observation-interchange/external-finding-rows-v1.json', bytes: 435, sha256: '09048325d801fdc837134580fd887cacde28744c9f87a43afc388c96117a4659', schema: EXTERNAL_FINDING_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'external-finding-rows-v1-output' },
|
|
69
|
-
{ id: 'external-finding-rows-v1-output', path: 'test/fixtures/external-observation-interchange/external-finding-rows-v1-output.json', bytes: 581, sha256: '7f84a9f6177d3245acd6fc21275276694fbe9e8cd94922b1e6997a73afa3149a', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: '
|
|
70
|
-
{ id: 'domain-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/domain-observation-rows-v1.json', bytes: 390, sha256: '2f95ab21e57e1a6aaab03cea75a4d58fd9e1234ba87f5268a899b23103359474', schema: DOMAIN_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'domain-observation-rows-v1-output' },
|
|
71
|
-
{ id: 'domain-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/domain-observation-rows-v1-output.json', bytes: 1_027, sha256: 'bba949308e9bb5b58bf5611d6dec23f074979522627631948cffc2f0056ac817', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: '
|
|
72
|
-
{ id: 'dns-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/dns-observation-rows-v1.json', bytes: 369, sha256: 'afb1808a8a81339a1801d337259c19c77ed957583b4ae06579b38ea6a8f68ed1', schema: DNS_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'dns-observation-rows-v1-output' },
|
|
73
|
-
{ id: 'dns-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/dns-observation-rows-v1-output.json', bytes: 988, sha256: '4c9a49b96181d2907eb95319d15975758823994fe029c051486f1cb6869221a0', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: '
|
|
74
|
-
{ id: 'certificate-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/certificate-observation-rows-v1.json', bytes: 515, sha256: '68363a5fe074b08a386dbc95a0993a2933ebcf05ba2f96148df632842d1c5869', schema: CERTIFICATE_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'certificate-observation-rows-v1-output' },
|
|
75
|
-
{ id: 'certificate-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/certificate-observation-rows-v1-output.json', bytes: 1_244, sha256: '6c484601b872f10bfdb7d9519d4b216f14ef277e7a429e4cc131154ad0e07652', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: '
|
|
82
|
+
{ id: 'external-findings-v4', path: 'test/fixtures/external-observation-interchange/external-findings-v4.json', bytes: 634, sha256: 'ceab916e1dcf99704c94e1b0cd82f5a061f138ae6a07ce8335273080c73b7624', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
83
|
+
{ id: 'external-finding-rows-v1', path: 'test/fixtures/external-observation-interchange/external-finding-rows-v1.json', bytes: 435, sha256: '09048325d801fdc837134580fd887cacde28744c9f87a43afc388c96117a4659', schema: EXTERNAL_FINDING_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'external-finding-rows-v1-output-v5' },
|
|
84
|
+
{ id: 'external-finding-rows-v1-output', path: 'test/fixtures/external-observation-interchange/external-finding-rows-v1-output.json', bytes: 581, sha256: '7f84a9f6177d3245acd6fc21275276694fbe9e8cd94922b1e6997a73afa3149a', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
85
|
+
{ id: 'domain-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/domain-observation-rows-v1.json', bytes: 390, sha256: '2f95ab21e57e1a6aaab03cea75a4d58fd9e1234ba87f5268a899b23103359474', schema: DOMAIN_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'domain-observation-rows-v1-output-v5' },
|
|
86
|
+
{ id: 'domain-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/domain-observation-rows-v1-output.json', bytes: 1_027, sha256: 'bba949308e9bb5b58bf5611d6dec23f074979522627631948cffc2f0056ac817', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
87
|
+
{ id: 'dns-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/dns-observation-rows-v1.json', bytes: 369, sha256: 'afb1808a8a81339a1801d337259c19c77ed957583b4ae06579b38ea6a8f68ed1', schema: DNS_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'dns-observation-rows-v1-output-v5' },
|
|
88
|
+
{ id: 'dns-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/dns-observation-rows-v1-output.json', bytes: 988, sha256: '4c9a49b96181d2907eb95319d15975758823994fe029c051486f1cb6869221a0', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
89
|
+
{ id: 'certificate-observation-rows-v1', path: 'test/fixtures/external-observation-interchange/certificate-observation-rows-v1.json', bytes: 515, sha256: '68363a5fe074b08a386dbc95a0993a2933ebcf05ba2f96148df632842d1c5869', schema: CERTIFICATE_OBSERVATION_ROWS_SCHEMA, version: 1, role: 'input', expectation: 'normalises_to_current_output', expectedOutputFixtureId: 'certificate-observation-rows-v1-output-v5' },
|
|
90
|
+
{ id: 'certificate-observation-rows-v1-output', path: 'test/fixtures/external-observation-interchange/certificate-observation-rows-v1-output.json', bytes: 1_244, sha256: '6c484601b872f10bfdb7d9519d4b216f14ef277e7a429e4cc131154ad0e07652', schema: EXTERNAL_FINDINGS_SCHEMA, version: 4, role: 'historical', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
91
|
+
{ id: 'external-finding-rows-v1-output-v5', path: 'test/fixtures/external-observation-interchange/external-finding-rows-v1-output-v5.json', bytes: 442, sha256: '9996be2b9d832fca9aa523a1a424148ef762483ab3923d35ca73e83cd16a8195', schema: EXTERNAL_FINDINGS_SCHEMA, version: 5, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
92
|
+
{ id: 'domain-observation-rows-v1-output-v5', path: 'test/fixtures/external-observation-interchange/domain-observation-rows-v1-output-v5.json', bytes: 771, sha256: 'd375353576b5990e835d53c14bf7fa5adb5205191d3969478a69ec68b5e1291b', schema: EXTERNAL_FINDINGS_SCHEMA, version: 5, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
93
|
+
{ id: 'dns-observation-rows-v1-output-v5', path: 'test/fixtures/external-observation-interchange/dns-observation-rows-v1-output-v5.json', bytes: 732, sha256: '532ff6ac9e9255f14105eb0a0286434fadb94f6d7397f0fb96007ebb6b7d1522', schema: EXTERNAL_FINDINGS_SCHEMA, version: 5, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
94
|
+
{ id: 'certificate-observation-rows-v1-output-v5', path: 'test/fixtures/external-observation-interchange/certificate-observation-rows-v1-output-v5.json', bytes: 988, sha256: '09904df103f83f64616556e653fa14c6f2f1dc392b1f75a85fd3099680840e37', schema: EXTERNAL_FINDINGS_SCHEMA, version: 5, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
95
|
+
{ id: 'external-findings-v5', path: 'test/fixtures/external-observation-interchange/external-findings-v5.json', bytes: 3871, sha256: 'debd062c2d951d22c06c29bb076529fa69a2769b8bae7269ce3884550fb55ba3', schema: EXTERNAL_FINDINGS_SCHEMA, version: 5, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
96
|
+
{ id: 'infrastructure-comparison-input-v1', path: 'test/fixtures/infrastructure-observations/infrastructure-comparison-input-v1.json', bytes: 6284, sha256: 'ef0022faf29586774bd1b2de1f95eb3839d382e424c7b3d446e4dc1058437104', schema: INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA, version: 1, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
97
|
+
{ id: 'infrastructure-observation-v1', path: 'test/fixtures/infrastructure-observations/infrastructure-observation-v1.json', bytes: 3430, sha256: '1b76e43e5d5c889654faf12114217994c5cbd3a378685e7f9b9d18ebdde801f7', schema: INFRASTRUCTURE_OBSERVATION_SCHEMA, version: 1, role: 'current', expectation: 'accepted_exact', expectedOutputFixtureId: null },
|
|
76
98
|
].map((fixture) => Object.freeze({
|
|
77
99
|
...fixture,
|
|
78
100
|
contentDigestSha256: null,
|
|
@@ -84,6 +106,7 @@ function externalFixtureIds(schema, version) {
|
|
|
84
106
|
.map((fixture) => fixture.id));
|
|
85
107
|
}
|
|
86
108
|
const EXTERNAL_INTERCHANGE_CONTRACTS = Object.freeze([
|
|
109
|
+
...[['export.infrastructure-observation', INFRASTRUCTURE_OBSERVATION_SCHEMA, true, MAX_INFRASTRUCTURE_OBSERVATION_BYTES], ['cli.infrastructure-comparison-input', INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA, false, MAX_INFRASTRUCTURE_COMPARISON_INPUT_BYTES]].map(([compatibilityId, schema, emitted, byteBudget]) => Object.freeze({ compatibilityId, schema, version: 1, role: 'document', lifecycle: 'current', readable: true, emitted, exactKeys: true, extensionPolicy: 'reject', futureVersionBehaviour: 'reject', migrationTarget: null, canonicalisation: null, byteBudget, fixtureIds: externalFixtureIds(schema, 1) })),
|
|
87
110
|
...SUPPORTED_EXTERNAL_FINDINGS_VERSIONS.map((version) => Object.freeze({
|
|
88
111
|
compatibilityId: EXTERNAL_FINDINGS_COMPATIBILITY.id,
|
|
89
112
|
schema: EXTERNAL_FINDINGS_SCHEMA,
|
|
@@ -95,7 +118,7 @@ const EXTERNAL_INTERCHANGE_CONTRACTS = Object.freeze([
|
|
|
95
118
|
exactKeys: true,
|
|
96
119
|
extensionPolicy: 'reject',
|
|
97
120
|
futureVersionBehaviour: 'reject',
|
|
98
|
-
migrationTarget:
|
|
121
|
+
migrationTarget: null,
|
|
99
122
|
canonicalisation: null,
|
|
100
123
|
byteBudget: MAX_EXTERNAL_FINDINGS_IMPORT_BYTES,
|
|
101
124
|
fixtureIds: externalFixtureIds(EXTERNAL_FINDINGS_SCHEMA, version),
|
|
@@ -151,18 +174,38 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_LIFECYCLE_FAMILY = defineSchemaLif
|
|
|
151
174
|
metadata: {
|
|
152
175
|
enforcement: 'declarative_only',
|
|
153
176
|
shapes: [
|
|
154
|
-
externalShape('external-interchange.findings.v4', EXTERNAL_FINDINGS_SCHEMA, [
|
|
177
|
+
externalShape('external-interchange.findings.v4', EXTERNAL_FINDINGS_SCHEMA, [4], ['schema', 'schemaVersion', 'source', 'findings'], 'preserve_document'),
|
|
178
|
+
externalShape('external-interchange.findings.v5', EXTERNAL_FINDINGS_SCHEMA, [5], ['schema', 'schemaVersion', 'source', 'findings'], 'preserve_document'),
|
|
179
|
+
externalShape('external-interchange.infrastructure.v1', INFRASTRUCTURE_OBSERVATION_SCHEMA, [1], ['schema', 'version', 'id', 'target', 'observedAt', 'mode', 'scope', 'coverage', 'sources', 'dns', 'certificates', 'roles', 'limitations'], 'preserve_document'),
|
|
180
|
+
externalShape('external-interchange.infrastructure-comparison.v1', INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA, [1], ['schema', 'version', 'earlier', 'later'], 'preserve_document'),
|
|
155
181
|
externalShape('external-interchange.finding-rows.v1', EXTERNAL_FINDING_ROWS_SCHEMA, [1], ['schema', 'schemaVersion', 'source', 'rows'], 'input_to_current'),
|
|
156
182
|
externalShape('external-interchange.domain-rows.v1', DOMAIN_OBSERVATION_ROWS_SCHEMA, [1], ['schema', 'schemaVersion', 'source', 'observations'], 'input_to_current'),
|
|
157
183
|
externalShape('external-interchange.dns-rows.v1', DNS_OBSERVATION_ROWS_SCHEMA, [1], ['schema', 'schemaVersion', 'source', 'observations'], 'input_to_current'),
|
|
158
184
|
externalShape('external-interchange.certificate-rows.v1', CERTIFICATE_OBSERVATION_ROWS_SCHEMA, [1], ['schema', 'schemaVersion', 'source', 'observations'], 'input_to_current'),
|
|
159
185
|
],
|
|
160
|
-
boundProfiles: [{ id: 'external-interchange.
|
|
186
|
+
boundProfiles: [{ id: 'external-interchange.infrastructure.bounds', bounds: [
|
|
187
|
+
{ id: 'raw-bytes', path: '$', phase: 'raw_intake', unit: 'bytes', minimum: 1, maximum: MAX_INFRASTRUCTURE_OBSERVATION_BYTES, handling: 'reject' },
|
|
188
|
+
{ id: 'serialised-bytes', path: '$', phase: 'serialised', unit: 'bytes', minimum: 1, maximum: MAX_INFRASTRUCTURE_OBSERVATION_BYTES, handling: 'reject' },
|
|
189
|
+
{ id: 'hostnames', path: 'scope.hostnames', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_INFRASTRUCTURE_HOSTS, handling: 'reject' },
|
|
190
|
+
{ id: 'dns-rows', path: 'dns', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_INFRASTRUCTURE_DNS_ROWS, handling: 'reject' },
|
|
191
|
+
{ id: 'certificate-rows', path: 'certificates', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_INFRASTRUCTURE_CERTIFICATES, handling: 'reject' },
|
|
192
|
+
{ id: 'role-rows', path: 'roles', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_INFRASTRUCTURE_ROLES, handling: 'reject' },
|
|
193
|
+
{ id: 'sources', path: 'sources', phase: 'pre_accumulation', unit: 'items', minimum: 1, maximum: MAX_INFRASTRUCTURE_SOURCES, handling: 'reject' },
|
|
194
|
+
{ id: 'dns-types', path: 'scope.dnsTypes', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: INFRASTRUCTURE_DNS_TYPES.length, handling: 'reject' },
|
|
195
|
+
{ id: 'limitations', path: 'limitations', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_INFRASTRUCTURE_LIMITATIONS, handling: 'reject' },
|
|
196
|
+
] }, { id: 'external-interchange.infrastructure-comparison.bounds', bounds: [
|
|
197
|
+
{ id: 'raw-bytes', path: '$', phase: 'raw_intake', unit: 'bytes', minimum: 1, maximum: MAX_INFRASTRUCTURE_COMPARISON_INPUT_BYTES, handling: 'reject' },
|
|
198
|
+
{ id: 'serialised-bytes', path: '$', phase: 'serialised', unit: 'bytes', minimum: 1, maximum: MAX_INFRASTRUCTURE_COMPARISON_INPUT_BYTES, handling: 'reject' },
|
|
199
|
+
] }, { id: 'external-interchange.document.bounds', bounds: [
|
|
161
200
|
{ id: 'raw-bytes', path: '$', phase: 'raw_intake', unit: 'bytes', minimum: 1, maximum: MAX_EXTERNAL_FINDINGS_IMPORT_BYTES, handling: 'reject' },
|
|
162
201
|
{ id: 'serialised-bytes', path: '$', phase: 'serialised', unit: 'bytes', minimum: 1, maximum: MAX_EXTERNAL_FINDINGS_IMPORT_BYTES, handling: 'reject' },
|
|
163
202
|
{ id: 'rows', path: '$', phase: 'pre_accumulation', unit: 'items', minimum: 1, maximum: MAX_CONVERSION_INPUT_ROWS, handling: 'reject' },
|
|
164
203
|
] }],
|
|
165
204
|
hooks: [
|
|
205
|
+
{ id: 'external-interchange.infrastructure.read', role: 'normaliser', runtime: 'shared', module: 'packages/investigation/infrastructure-observation.mts', exportName: 'readInfrastructureObservation' },
|
|
206
|
+
{ id: 'external-interchange.infrastructure.serialise', role: 'serialiser', runtime: 'shared', module: 'packages/investigation/infrastructure-observation.mts', exportName: 'serialiseInfrastructureObservation' },
|
|
207
|
+
{ id: 'external-interchange.infrastructure.convert', role: 'normaliser', runtime: 'shared', module: 'packages/interchange/external-findings-converters.mts', exportName: 'convertInfrastructureObservation' },
|
|
208
|
+
{ id: 'external-interchange.infrastructure.compare', role: 'normaliser', runtime: 'cli', module: 'cli/offline-evidence-review.mts', exportName: 'buildOfflineEvidenceReview' },
|
|
166
209
|
{ id: 'external-interchange.findings.normalise', role: 'normaliser', runtime: 'shared', module: 'packages/interchange/external-findings-import.mts', exportName: 'parseExternalFindingsDocument' },
|
|
167
210
|
{ id: 'external-interchange.findings.serialise', role: 'serialiser', runtime: 'shared', module: 'packages/interchange/external-findings-import.mts', exportName: 'serializeExternalFindingsDocument' },
|
|
168
211
|
{ id: 'external-interchange.finding-rows.convert', role: 'normaliser', runtime: 'shared', module: 'packages/interchange/external-findings-converters.mts', exportName: 'convertExternalFindingRows' },
|
|
@@ -170,10 +213,15 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_LIFECYCLE_FAMILY = defineSchemaLif
|
|
|
170
213
|
{ id: 'external-interchange.findings.merge', role: 'merger', runtime: 'shared', module: 'packages/interchange/external-findings-import.mts', exportName: 'mergeExternalFindingsIntoCases' },
|
|
171
214
|
],
|
|
172
215
|
serialisationProfiles: [{
|
|
173
|
-
id: 'external-interchange.findings.json.
|
|
174
|
-
versions: [
|
|
175
|
-
indentSpaces:
|
|
216
|
+
id: 'external-interchange.findings.json.v5', schema: EXTERNAL_FINDINGS_SCHEMA,
|
|
217
|
+
versions: [5], mediaType: 'application/json', encoding: 'utf-8', bom: false,
|
|
218
|
+
indentSpaces: 0, terminalLf: true, propertyOrder: 'normalised_fixed', canonicalisation: null, integrity: 'none',
|
|
176
219
|
serializerHookId: 'external-interchange.findings.serialise', verifierHookIds: [],
|
|
220
|
+
}, {
|
|
221
|
+
id: 'external-interchange.infrastructure.json.v1', schema: INFRASTRUCTURE_OBSERVATION_SCHEMA,
|
|
222
|
+
versions: [1], mediaType: 'application/json', encoding: 'utf-8', bom: false,
|
|
223
|
+
indentSpaces: 0, terminalLf: true, propertyOrder: 'normalised_fixed', canonicalisation: null, integrity: 'none',
|
|
224
|
+
serializerHookId: 'external-interchange.infrastructure.serialise', verifierHookIds: [],
|
|
177
225
|
}],
|
|
178
226
|
privacyProfiles: [
|
|
179
227
|
{ id: 'external-interchange.privacy.transient', classification: 'analyst_authored_sensitive', projection: 'browser_import', includedCategories: ['source-attribution', 'bounded-observations', 'completeness', 'limitations'], excludedCategories: ['raw-upstream-payloads', 'expanded-contacts', 'credentials', 'cookies', 'query-bearing-urls'], notePolicy: 'discarded', retention: 'transient_report', network: 'none', sharingReview: 'required' },
|
|
@@ -181,22 +229,42 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_LIFECYCLE_FAMILY = defineSchemaLif
|
|
|
181
229
|
],
|
|
182
230
|
expiryProfiles: [{ id: 'external-interchange.expiry.not-applicable', field: null, anchor: null, handling: 'not_applicable', phase: 'not_applicable', maximumLifetimeDays: null }],
|
|
183
231
|
consumerEdges: [
|
|
232
|
+
{
|
|
233
|
+
id: 'external-interchange.consumer.infrastructure-read', plane: 'shared', operation: 'read-and-export-exact-infrastructure-snapshot',
|
|
234
|
+
acceptedContracts: [{ schema: INFRASTRUCTURE_OBSERVATION_SCHEMA, versions: [1], mode: 'direct' }], emittedContract: { schema: INFRASTRUCTURE_OBSERVATION_SCHEMA, version: 1 },
|
|
235
|
+
shapeIds: ['external-interchange.infrastructure.v1'], boundProfileIds: ['external-interchange.infrastructure.bounds'], hookIds: ['external-interchange.infrastructure.read', 'external-interchange.infrastructure.serialise'], serialisationProfileId: 'external-interchange.infrastructure.json.v1', privacyProfileId: 'external-interchange.privacy.transient', retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: 'external-interchange.consumer.infrastructure-convert', plane: 'shared', operation: 'convert-exact-snapshot-to-one-finding',
|
|
239
|
+
acceptedContracts: [{ schema: INFRASTRUCTURE_OBSERVATION_SCHEMA, versions: [1], mode: 'direct' }], emittedContract: { schema: EXTERNAL_FINDINGS_SCHEMA, version: 5 },
|
|
240
|
+
shapeIds: ['external-interchange.infrastructure.v1', 'external-interchange.findings.v5'], boundProfileIds: ['external-interchange.infrastructure.bounds', 'external-interchange.document.bounds'], hookIds: ['external-interchange.infrastructure.convert', 'external-interchange.findings.serialise'], serialisationProfileId: 'external-interchange.findings.json.v5', privacyProfileId: 'external-interchange.privacy.transient', retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
id: 'external-interchange.consumer.infrastructure-compare', plane: 'cli', operation: 'offline-infrastructure-comparison',
|
|
244
|
+
acceptedContracts: [{ schema: INFRASTRUCTURE_COMPARISON_INPUT_SCHEMA, versions: [1], mode: 'direct' }], emittedContract: null,
|
|
245
|
+
shapeIds: ['external-interchange.infrastructure-comparison.v1'], boundProfileIds: ['external-interchange.infrastructure-comparison.bounds'], hookIds: ['external-interchange.infrastructure.compare'], serialisationProfileId: null, privacyProfileId: 'external-interchange.privacy.transient', retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 'external-interchange.consumer.findings-v4-read', plane: 'shared', operation: 'preserve-historical-findings',
|
|
249
|
+
acceptedContracts: [{ schema: EXTERNAL_FINDINGS_SCHEMA, versions: [4], mode: 'direct' }], emittedContract: null,
|
|
250
|
+
shapeIds: ['external-interchange.findings.v4'], boundProfileIds: ['external-interchange.document.bounds'], hookIds: ['external-interchange.findings.normalise'], serialisationProfileId: null, privacyProfileId: 'external-interchange.privacy.transient', retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
251
|
+
},
|
|
184
252
|
{
|
|
185
253
|
id: 'external-interchange.consumer.findings-normalise', plane: 'shared', operation: 'normalise-strict-findings',
|
|
186
|
-
acceptedContracts: [{ schema: EXTERNAL_FINDINGS_SCHEMA, versions: [
|
|
254
|
+
acceptedContracts: [{ schema: EXTERNAL_FINDINGS_SCHEMA, versions: [5], mode: 'direct' }],
|
|
187
255
|
emittedContract: { schema: EXTERNAL_FINDINGS_SCHEMA, version: EXTERNAL_FINDINGS_VERSION },
|
|
188
|
-
shapeIds: ['external-interchange.findings.
|
|
256
|
+
shapeIds: ['external-interchange.findings.v5'], boundProfileIds: ['external-interchange.document.bounds'],
|
|
189
257
|
hookIds: ['external-interchange.findings.normalise', 'external-interchange.findings.serialise'],
|
|
190
|
-
serialisationProfileId: 'external-interchange.findings.json.
|
|
258
|
+
serialisationProfileId: 'external-interchange.findings.json.v5', privacyProfileId: 'external-interchange.privacy.transient',
|
|
191
259
|
retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
192
260
|
},
|
|
193
261
|
{
|
|
194
262
|
id: 'external-interchange.consumer.finding-rows', plane: 'shared', operation: 'convert-finding-rows',
|
|
195
263
|
acceptedContracts: [{ schema: EXTERNAL_FINDING_ROWS_SCHEMA, versions: [1], mode: 'direct' }],
|
|
196
264
|
emittedContract: { schema: EXTERNAL_FINDINGS_SCHEMA, version: EXTERNAL_FINDINGS_VERSION },
|
|
197
|
-
shapeIds: ['external-interchange.finding-rows.v1', 'external-interchange.findings.
|
|
265
|
+
shapeIds: ['external-interchange.finding-rows.v1', 'external-interchange.findings.v5'], boundProfileIds: ['external-interchange.document.bounds'],
|
|
198
266
|
hookIds: ['external-interchange.finding-rows.convert', 'external-interchange.findings.serialise'],
|
|
199
|
-
serialisationProfileId: 'external-interchange.findings.json.
|
|
267
|
+
serialisationProfileId: 'external-interchange.findings.json.v5', privacyProfileId: 'external-interchange.privacy.transient',
|
|
200
268
|
retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
201
269
|
},
|
|
202
270
|
{
|
|
@@ -207,15 +275,15 @@ export const EXTERNAL_OBSERVATION_INTERCHANGE_LIFECYCLE_FAMILY = defineSchemaLif
|
|
|
207
275
|
{ schema: CERTIFICATE_OBSERVATION_ROWS_SCHEMA, versions: [1], mode: 'direct' },
|
|
208
276
|
],
|
|
209
277
|
emittedContract: { schema: EXTERNAL_FINDINGS_SCHEMA, version: EXTERNAL_FINDINGS_VERSION },
|
|
210
|
-
shapeIds: ['external-interchange.domain-rows.v1', 'external-interchange.dns-rows.v1', 'external-interchange.certificate-rows.v1', 'external-interchange.findings.
|
|
278
|
+
shapeIds: ['external-interchange.domain-rows.v1', 'external-interchange.dns-rows.v1', 'external-interchange.certificate-rows.v1', 'external-interchange.findings.v5'],
|
|
211
279
|
boundProfileIds: ['external-interchange.document.bounds'], hookIds: ['external-interchange.observation-rows.convert', 'external-interchange.findings.serialise'],
|
|
212
|
-
serialisationProfileId: 'external-interchange.findings.json.
|
|
280
|
+
serialisationProfileId: 'external-interchange.findings.json.v5', privacyProfileId: 'external-interchange.privacy.transient',
|
|
213
281
|
retentionEffect: 'transient_report', ...externalConsumerCommon,
|
|
214
282
|
},
|
|
215
283
|
{
|
|
216
284
|
id: 'external-interchange.consumer.case-merge', plane: 'shared', operation: 'non-destructive-case-merge',
|
|
217
|
-
acceptedContracts: [{ schema: EXTERNAL_FINDINGS_SCHEMA, versions: [
|
|
218
|
-
shapeIds: ['external-interchange.findings.v4'], boundProfileIds: ['external-interchange.document.bounds'],
|
|
285
|
+
acceptedContracts: [{ schema: EXTERNAL_FINDINGS_SCHEMA, versions: [...SUPPORTED_EXTERNAL_FINDINGS_VERSIONS], mode: 'direct' }], emittedContract: null,
|
|
286
|
+
shapeIds: ['external-interchange.findings.v4', 'external-interchange.findings.v5'], boundProfileIds: ['external-interchange.document.bounds'],
|
|
219
287
|
hookIds: ['external-interchange.findings.merge'], serialisationProfileId: null,
|
|
220
288
|
privacyProfileId: 'external-interchange.privacy.case-merge', retentionEffect: 'browser_indexeddb', ...externalConsumerCommon,
|
|
221
289
|
},
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const CLI_INVESTIGATION_RUN_SCHEMA = 'whoisleuth.cli.investigation-run';
|
|
2
2
|
export const CLI_INVESTIGATION_RUN_VERSION = 3;
|
|
3
|
+
export const CLI_INVESTIGATION_PREVIEW_SCHEMA = 'whoisleuth.cli.investigation-preview';
|
|
4
|
+
export const CLI_INVESTIGATION_PREVIEW_VERSION = 1;
|
|
3
5
|
export const SUPPORTED_CLI_INVESTIGATION_RUN_VERSIONS = Object.freeze([1, 2, 3]);
|
|
4
6
|
export const MAX_INVESTIGATION_RUN_BYTES = 24 * 1024 * 1024;
|
|
5
7
|
export const MAX_INVESTIGATION_RUN_SELECTIONS = 16;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/** Syntactic identity only: private and reserved addresses remain valid evidence. */
|
|
2
|
+
export function canonicalIpAddress(value) {
|
|
3
|
+
const candidate = typeof value === 'string' ? value.trim() : value;
|
|
4
|
+
const parsed = addressValue(candidate);
|
|
5
|
+
if (!parsed)
|
|
6
|
+
return null;
|
|
7
|
+
if (parsed.family === 4)
|
|
8
|
+
return [24, 16, 8, 0].map(shift => (parsed.value >>> shift) & 255).join('.');
|
|
9
|
+
return new URL(`https://[${candidate}]/`).hostname.slice(1, -1);
|
|
10
|
+
}
|
|
1
11
|
export function ipv6Groups(value) {
|
|
2
12
|
const address = addressValue(value);
|
|
3
13
|
if (address?.family !== 6)
|