@vizejs/marquette 0.299.1
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 +129 -0
- package/dist/index.d.mts +52 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +33 -0
- package/dist/index.mjs.map +1 -0
- package/dist/model-DWcxWbC1.d.mts +197 -0
- package/dist/model-DWcxWbC1.d.mts.map +1 -0
- package/dist/test-run-admission.d.mts +48 -0
- package/dist/test-run-admission.d.mts.map +1 -0
- package/dist/test-run-admission.mjs +72 -0
- package/dist/test-run-admission.mjs.map +1 -0
- package/dist/test-run-canonical.d.mts +35 -0
- package/dist/test-run-canonical.d.mts.map +1 -0
- package/dist/test-run-canonical.mjs +124 -0
- package/dist/test-run-canonical.mjs.map +1 -0
- package/dist/test-run-model-B2INFVlw.mjs +9 -0
- package/dist/test-run-model-B2INFVlw.mjs.map +1 -0
- package/dist/test-run-model-DkllmEsY.d.mts +181 -0
- package/dist/test-run-model-DkllmEsY.d.mts.map +1 -0
- package/dist/test-run-validate-XF0vyoWI.mjs +229 -0
- package/dist/test-run-validate-XF0vyoWI.mjs.map +1 -0
- package/dist/test-run-validate.d.mts +24 -0
- package/dist/test-run-validate.d.mts.map +1 -0
- package/dist/test-run-validate.mjs +2 -0
- package/dist/test-run.d.mts +40 -0
- package/dist/test-run.d.mts.map +1 -0
- package/dist/test-run.mjs +27 -0
- package/dist/test-run.mjs.map +1 -0
- package/dist/validate.d.mts +29 -0
- package/dist/validate.d.mts.map +1 -0
- package/dist/validate.mjs +146 -0
- package/dist/validate.mjs.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//#region src/test-run-canonical.ts
|
|
2
|
+
/** Prefix of every test-run deployment admission id. */
|
|
3
|
+
const TEST_RUN_ADMISSION_PREFIX = "test-run:";
|
|
4
|
+
const ADMISSION_FINGERPRINT = /^[a-f0-9]{64}$/;
|
|
5
|
+
function retained(evidence) {
|
|
6
|
+
return {
|
|
7
|
+
reference: evidence.reference,
|
|
8
|
+
fingerprint: evidence.fingerprint
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function target(execution) {
|
|
12
|
+
return {
|
|
13
|
+
id: execution.id,
|
|
14
|
+
kind: execution.kind,
|
|
15
|
+
environment: execution.environment
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function suite(execution) {
|
|
19
|
+
return {
|
|
20
|
+
id: execution.id,
|
|
21
|
+
targetId: execution.targetId,
|
|
22
|
+
kind: execution.kind,
|
|
23
|
+
shardIndex: execution.shardIndex,
|
|
24
|
+
shardCount: execution.shardCount,
|
|
25
|
+
outcome: execution.outcome,
|
|
26
|
+
passed: execution.passed,
|
|
27
|
+
failed: execution.failed,
|
|
28
|
+
skipped: execution.skipped,
|
|
29
|
+
retries: execution.retries,
|
|
30
|
+
durationMs: execution.durationMs,
|
|
31
|
+
invocationFingerprint: execution.invocationFingerprint,
|
|
32
|
+
report: retained(execution.report),
|
|
33
|
+
log: retained(execution.log)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Serializes a test-run evidence record canonically.
|
|
38
|
+
*
|
|
39
|
+
* Property order matches the record schema, targets sort by id, suites sort
|
|
40
|
+
* by id then shard index, and selection identifiers sort lexicographically,
|
|
41
|
+
* so equivalent records produce byte-identical JSON in every language. Call
|
|
42
|
+
* validation before trusting the record; canonicalization does not make an
|
|
43
|
+
* invalid record valid.
|
|
44
|
+
*/
|
|
45
|
+
function canonicalTestRunJson(evidence) {
|
|
46
|
+
const canonical = {
|
|
47
|
+
format: evidence.format,
|
|
48
|
+
formatVersion: evidence.formatVersion ?? 1,
|
|
49
|
+
id: evidence.id,
|
|
50
|
+
application: evidence.application,
|
|
51
|
+
environment: evidence.environment,
|
|
52
|
+
contractFingerprint: evidence.contractFingerprint,
|
|
53
|
+
sourceRevision: evidence.sourceRevision,
|
|
54
|
+
release: evidence.release,
|
|
55
|
+
artifact: {
|
|
56
|
+
id: evidence.artifact.id,
|
|
57
|
+
fingerprint: evidence.artifact.fingerprint,
|
|
58
|
+
sizeBytes: evidence.artifact.sizeBytes
|
|
59
|
+
},
|
|
60
|
+
startedAt: evidence.startedAt,
|
|
61
|
+
completedAt: evidence.completedAt,
|
|
62
|
+
validUntil: evidence.validUntil,
|
|
63
|
+
runner: {
|
|
64
|
+
identity: evidence.runner.identity,
|
|
65
|
+
authenticationEvidence: retained(evidence.runner.authenticationEvidence),
|
|
66
|
+
isolation: evidence.runner.isolation,
|
|
67
|
+
invocationFingerprint: evidence.runner.invocationFingerprint,
|
|
68
|
+
environmentEvidence: retained(evidence.runner.environmentEvidence),
|
|
69
|
+
environmentFingerprint: evidence.runner.environmentFingerprint
|
|
70
|
+
},
|
|
71
|
+
selection: {
|
|
72
|
+
targetIds: [...evidence.selection.targetIds].sort(),
|
|
73
|
+
suiteIds: [...evidence.selection.suiteIds].sort()
|
|
74
|
+
},
|
|
75
|
+
targets: evidence.targets.map(target).sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0),
|
|
76
|
+
suites: evidence.suites.map(suite).sort((left, right) => left.id !== right.id ? left.id < right.id ? -1 : 1 : left.shardIndex - right.shardIndex),
|
|
77
|
+
verification: {
|
|
78
|
+
verifier: evidence.verification.verifier,
|
|
79
|
+
completedAt: evidence.verification.completedAt,
|
|
80
|
+
outcome: evidence.verification.outcome,
|
|
81
|
+
targetCount: evidence.verification.targetCount,
|
|
82
|
+
suiteCount: evidence.verification.suiteCount,
|
|
83
|
+
passed: evidence.verification.passed,
|
|
84
|
+
failed: evidence.verification.failed,
|
|
85
|
+
skipped: evidence.verification.skipped,
|
|
86
|
+
retries: evidence.verification.retries,
|
|
87
|
+
evidence: retained(evidence.verification.evidence)
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return JSON.stringify(canonical);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Returns the lowercase SHA-256 fingerprint of the canonical record.
|
|
94
|
+
*
|
|
95
|
+
* The fingerprint is the exact value admitted as `test-run:<sha256>` by
|
|
96
|
+
* deployment gates. Uses the Web Crypto API available in every supported
|
|
97
|
+
* runtime.
|
|
98
|
+
*/
|
|
99
|
+
async function testRunFingerprint(evidence) {
|
|
100
|
+
const bytes = new TextEncoder().encode(canonicalTestRunJson(evidence));
|
|
101
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
102
|
+
let fingerprint = "";
|
|
103
|
+
for (const byte of new Uint8Array(digest)) fingerprint += byte.toString(16).padStart(2, "0");
|
|
104
|
+
return fingerprint;
|
|
105
|
+
}
|
|
106
|
+
/** Returns the `test-run:<sha256>` admission id for one record. */
|
|
107
|
+
async function testRunAdmissionId(evidence) {
|
|
108
|
+
return `${TEST_RUN_ADMISSION_PREFIX}${await testRunFingerprint(evidence)}`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns the fingerprint named by a `test-run:<sha256>` admission id.
|
|
112
|
+
*
|
|
113
|
+
* Returns `undefined` unless the prefix, length, and lowercase hexadecimal
|
|
114
|
+
* grammar are all exact.
|
|
115
|
+
*/
|
|
116
|
+
function parseTestRunAdmissionId(id) {
|
|
117
|
+
if (!id.startsWith("test-run:")) return;
|
|
118
|
+
const fingerprint = id.slice(9);
|
|
119
|
+
return ADMISSION_FINGERPRINT.test(fingerprint) ? fingerprint : void 0;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { TEST_RUN_ADMISSION_PREFIX, canonicalTestRunJson, parseTestRunAdmissionId, testRunAdmissionId, testRunFingerprint };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=test-run-canonical.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run-canonical.mjs","names":[],"sources":["../src/test-run-canonical.ts"],"sourcesContent":["import type {\n TestRunEvidence,\n TestRunRetainedEvidence,\n TestRunSuiteExecution,\n TestRunTargetExecution,\n} from \"./test-run-model.js\";\n\n/** Prefix of every test-run deployment admission id. */\nexport const TEST_RUN_ADMISSION_PREFIX = \"test-run:\";\n\nconst ADMISSION_FINGERPRINT = /^[a-f0-9]{64}$/;\n\nfunction retained(evidence: TestRunRetainedEvidence): TestRunRetainedEvidence {\n return { reference: evidence.reference, fingerprint: evidence.fingerprint };\n}\n\nfunction target(execution: TestRunTargetExecution): TestRunTargetExecution {\n return { id: execution.id, kind: execution.kind, environment: execution.environment };\n}\n\nfunction suite(execution: TestRunSuiteExecution): TestRunSuiteExecution {\n return {\n id: execution.id,\n targetId: execution.targetId,\n kind: execution.kind,\n shardIndex: execution.shardIndex,\n shardCount: execution.shardCount,\n outcome: execution.outcome,\n passed: execution.passed,\n failed: execution.failed,\n skipped: execution.skipped,\n retries: execution.retries,\n durationMs: execution.durationMs,\n invocationFingerprint: execution.invocationFingerprint,\n report: retained(execution.report),\n log: retained(execution.log),\n };\n}\n\n/**\n * Serializes a test-run evidence record canonically.\n *\n * Property order matches the record schema, targets sort by id, suites sort\n * by id then shard index, and selection identifiers sort lexicographically,\n * so equivalent records produce byte-identical JSON in every language. Call\n * validation before trusting the record; canonicalization does not make an\n * invalid record valid.\n */\nexport function canonicalTestRunJson(evidence: TestRunEvidence): string {\n const canonical = {\n format: evidence.format,\n formatVersion: evidence.formatVersion ?? 1,\n id: evidence.id,\n application: evidence.application,\n environment: evidence.environment,\n contractFingerprint: evidence.contractFingerprint,\n sourceRevision: evidence.sourceRevision,\n release: evidence.release,\n artifact: {\n id: evidence.artifact.id,\n fingerprint: evidence.artifact.fingerprint,\n sizeBytes: evidence.artifact.sizeBytes,\n },\n startedAt: evidence.startedAt,\n completedAt: evidence.completedAt,\n validUntil: evidence.validUntil,\n runner: {\n identity: evidence.runner.identity,\n authenticationEvidence: retained(evidence.runner.authenticationEvidence),\n isolation: evidence.runner.isolation,\n invocationFingerprint: evidence.runner.invocationFingerprint,\n environmentEvidence: retained(evidence.runner.environmentEvidence),\n environmentFingerprint: evidence.runner.environmentFingerprint,\n },\n selection: {\n targetIds: [...evidence.selection.targetIds].sort(),\n suiteIds: [...evidence.selection.suiteIds].sort(),\n },\n targets: evidence.targets\n .map(target)\n .sort((left, right) => (left.id < right.id ? -1 : left.id > right.id ? 1 : 0)),\n suites: evidence.suites\n .map(suite)\n .sort((left, right) =>\n left.id !== right.id ? (left.id < right.id ? -1 : 1) : left.shardIndex - right.shardIndex,\n ),\n verification: {\n verifier: evidence.verification.verifier,\n completedAt: evidence.verification.completedAt,\n outcome: evidence.verification.outcome,\n targetCount: evidence.verification.targetCount,\n suiteCount: evidence.verification.suiteCount,\n passed: evidence.verification.passed,\n failed: evidence.verification.failed,\n skipped: evidence.verification.skipped,\n retries: evidence.verification.retries,\n evidence: retained(evidence.verification.evidence),\n },\n };\n return JSON.stringify(canonical);\n}\n\n/**\n * Returns the lowercase SHA-256 fingerprint of the canonical record.\n *\n * The fingerprint is the exact value admitted as `test-run:<sha256>` by\n * deployment gates. Uses the Web Crypto API available in every supported\n * runtime.\n */\nexport async function testRunFingerprint(evidence: TestRunEvidence): Promise<string> {\n const bytes = new TextEncoder().encode(canonicalTestRunJson(evidence));\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n let fingerprint = \"\";\n for (const byte of new Uint8Array(digest)) {\n fingerprint += byte.toString(16).padStart(2, \"0\");\n }\n return fingerprint;\n}\n\n/** Returns the `test-run:<sha256>` admission id for one record. */\nexport async function testRunAdmissionId(evidence: TestRunEvidence): Promise<string> {\n return `${TEST_RUN_ADMISSION_PREFIX}${await testRunFingerprint(evidence)}`;\n}\n\n/**\n * Returns the fingerprint named by a `test-run:<sha256>` admission id.\n *\n * Returns `undefined` unless the prefix, length, and lowercase hexadecimal\n * grammar are all exact.\n */\nexport function parseTestRunAdmissionId(id: string): string | undefined {\n if (!id.startsWith(TEST_RUN_ADMISSION_PREFIX)) {\n return undefined;\n }\n const fingerprint = id.slice(TEST_RUN_ADMISSION_PREFIX.length);\n return ADMISSION_FINGERPRINT.test(fingerprint) ? fingerprint : undefined;\n}\n"],"mappings":";;AAQA,MAAa,4BAA4B;AAEzC,MAAM,wBAAwB;AAE9B,SAAS,SAAS,UAA4D;CAC5E,OAAO;EAAE,WAAW,SAAS;EAAW,aAAa,SAAS;EAAa;;AAG7E,SAAS,OAAO,WAA2D;CACzE,OAAO;EAAE,IAAI,UAAU;EAAI,MAAM,UAAU;EAAM,aAAa,UAAU;EAAa;;AAGvF,SAAS,MAAM,WAAyD;CACtE,OAAO;EACL,IAAI,UAAU;EACd,UAAU,UAAU;EACpB,MAAM,UAAU;EAChB,YAAY,UAAU;EACtB,YAAY,UAAU;EACtB,SAAS,UAAU;EACnB,QAAQ,UAAU;EAClB,QAAQ,UAAU;EAClB,SAAS,UAAU;EACnB,SAAS,UAAU;EACnB,YAAY,UAAU;EACtB,uBAAuB,UAAU;EACjC,QAAQ,SAAS,UAAU,OAAO;EAClC,KAAK,SAAS,UAAU,IAAI;EAC7B;;;;;;;;;;;AAYH,SAAgB,qBAAqB,UAAmC;CACtE,MAAM,YAAY;EAChB,QAAQ,SAAS;EACjB,eAAe,SAAS,iBAAiB;EACzC,IAAI,SAAS;EACb,aAAa,SAAS;EACtB,aAAa,SAAS;EACtB,qBAAqB,SAAS;EAC9B,gBAAgB,SAAS;EACzB,SAAS,SAAS;EAClB,UAAU;GACR,IAAI,SAAS,SAAS;GACtB,aAAa,SAAS,SAAS;GAC/B,WAAW,SAAS,SAAS;GAC9B;EACD,WAAW,SAAS;EACpB,aAAa,SAAS;EACtB,YAAY,SAAS;EACrB,QAAQ;GACN,UAAU,SAAS,OAAO;GAC1B,wBAAwB,SAAS,SAAS,OAAO,uBAAuB;GACxE,WAAW,SAAS,OAAO;GAC3B,uBAAuB,SAAS,OAAO;GACvC,qBAAqB,SAAS,SAAS,OAAO,oBAAoB;GAClE,wBAAwB,SAAS,OAAO;GACzC;EACD,WAAW;GACT,WAAW,CAAC,GAAG,SAAS,UAAU,UAAU,CAAC,MAAM;GACnD,UAAU,CAAC,GAAG,SAAS,UAAU,SAAS,CAAC,MAAM;GAClD;EACD,SAAS,SAAS,QACf,IAAI,OAAO,CACX,MAAM,MAAM,UAAW,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,EAAG;EAChF,QAAQ,SAAS,OACd,IAAI,MAAM,CACV,MAAM,MAAM,UACX,KAAK,OAAO,MAAM,KAAM,KAAK,KAAK,MAAM,KAAK,KAAK,IAAK,KAAK,aAAa,MAAM,WAChF;EACH,cAAc;GACZ,UAAU,SAAS,aAAa;GAChC,aAAa,SAAS,aAAa;GACnC,SAAS,SAAS,aAAa;GAC/B,aAAa,SAAS,aAAa;GACnC,YAAY,SAAS,aAAa;GAClC,QAAQ,SAAS,aAAa;GAC9B,QAAQ,SAAS,aAAa;GAC9B,SAAS,SAAS,aAAa;GAC/B,SAAS,SAAS,aAAa;GAC/B,UAAU,SAAS,SAAS,aAAa,SAAS;GACnD;EACF;CACD,OAAO,KAAK,UAAU,UAAU;;;;;;;;;AAUlC,eAAsB,mBAAmB,UAA4C;CACnF,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,qBAAqB,SAAS,CAAC;CACtE,MAAM,SAAS,MAAM,WAAW,OAAO,OAAO,OAAO,WAAW,MAAM;CACtE,IAAI,cAAc;CAClB,KAAK,MAAM,QAAQ,IAAI,WAAW,OAAO,EACvC,eAAe,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;CAEnD,OAAO;;;AAIT,eAAsB,mBAAmB,UAA4C;CACnF,OAAO,GAAG,4BAA4B,MAAM,mBAAmB,SAAS;;;;;;;;AAS1E,SAAgB,wBAAwB,IAAgC;CACtE,IAAI,CAAC,GAAG,WAAA,YAAqC,EAC3C;CAEF,MAAM,cAAc,GAAG,MAAM,EAAiC;CAC9D,OAAO,sBAAsB,KAAK,YAAY,GAAG,cAAc,KAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/test-run-model.ts
|
|
2
|
+
/** Serialized `format` marker for test-run evidence records. */
|
|
3
|
+
const TEST_RUN_EVIDENCE_FORMAT = "vize.test-run.evidence";
|
|
4
|
+
/** Current serialized test-run evidence format version. */
|
|
5
|
+
const TEST_RUN_EVIDENCE_FORMAT_VERSION = 1;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { TEST_RUN_EVIDENCE_FORMAT_VERSION as n, TEST_RUN_EVIDENCE_FORMAT as t };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=test-run-model-B2INFVlw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run-model-B2INFVlw.mjs","names":[],"sources":["../src/test-run-model.ts"],"sourcesContent":["/** Serialized `format` marker for test-run evidence records. */\nexport const TEST_RUN_EVIDENCE_FORMAT = \"vize.test-run.evidence\" as const;\n\n/** Current serialized test-run evidence format version. */\nexport const TEST_RUN_EVIDENCE_FORMAT_VERSION = 1 as const;\n\n/** Isolation level of the runner that executed the tests. */\nexport type TestRunIsolation = \"dedicated\" | \"ephemeral\";\n\n/** Kind of user-visible target a test execution ran against. */\nexport type TestRunTargetKind = \"web\" | \"native\" | \"desktop\" | \"terminal\" | \"server\";\n\n/** Semantic kind of one executed suite. */\nexport type TestRunSuiteKind =\n | \"unit\"\n | \"integration\"\n | \"contract\"\n | \"end-to-end\"\n | \"accessibility\"\n | \"visual\"\n | \"performance\"\n | \"resilience\"\n | \"installation\"\n | \"upgrade\"\n | \"migration\";\n\n/** Final result of one executed suite shard. */\nexport type TestRunSuiteOutcome = \"passed\" | \"failed\" | \"cancelled\";\n\n/** Final result of the independent verification pass. */\nexport type TestRunVerificationOutcome = \"accepted\" | \"rejected\";\n\n/**\n * Immutable, content-addressed reference to retained evidence.\n *\n * The reference names the retained content by SHA-256 so a green label can\n * never drift away from the bytes that were verified.\n */\nexport interface TestRunRetainedEvidence {\n /** Content-addressed retrieval reference in `sha256:<64 hex>` form. */\n readonly reference: string;\n /** Lowercase SHA-256 fingerprint of the retained content. */\n readonly fingerprint: string;\n}\n\n/** Exact release artifact that the recorded test executions exercised. */\nexport interface TestRunArtifact {\n /** Stable artifact identifier. */\n readonly id: string;\n /** Lowercase SHA-256 fingerprint of the artifact bytes. */\n readonly fingerprint: string;\n /** Exact artifact size in bytes; must be at least one byte. */\n readonly sizeBytes: number;\n}\n\n/** Authenticated runner that executed the recorded test run. */\nexport interface TestRunRunner {\n /** Stable runner identity. */\n readonly identity: string;\n /** Retained evidence for the runner's authentication. */\n readonly authenticationEvidence: TestRunRetainedEvidence;\n /** Isolation level the runner guaranteed for this invocation. */\n readonly isolation: TestRunIsolation;\n /** Lowercase SHA-256 fingerprint of the exact invocation. */\n readonly invocationFingerprint: string;\n /** Retained evidence describing the execution environment. */\n readonly environmentEvidence: TestRunRetainedEvidence;\n /** Lowercase SHA-256 fingerprint of the execution environment. */\n readonly environmentFingerprint: string;\n}\n\n/**\n * Complete candidate-selected target and suite coverage for the run.\n *\n * Recorded executions must cover exactly these identifiers; anything less is\n * an undeclared omission and anything more is an undeclared execution.\n */\nexport interface TestRunSelection<\n TargetId extends string = string,\n SuiteId extends string = string,\n> {\n /** Selected target identifiers, unique within the selection. */\n readonly targetIds: readonly TargetId[];\n /** Selected suite identifiers, unique within the selection. */\n readonly suiteIds: readonly SuiteId[];\n}\n\n/** One executed target of the release candidate. */\nexport interface TestRunTargetExecution<Id extends string = string> {\n /** Stable target identifier from the candidate selection. */\n readonly id: Id;\n /** Kind of target that was exercised. */\n readonly kind: TestRunTargetKind;\n /** Environment identifier the target executed in. */\n readonly environment: string;\n}\n\n/** One executed suite shard with its exact recorded results. */\nexport interface TestRunSuiteExecution<\n Id extends string = string,\n TargetId extends string = string,\n> {\n /** Stable suite identifier from the candidate selection. */\n readonly id: Id;\n /** Target this shard executed against. */\n readonly targetId: TargetId;\n /** Semantic suite kind. */\n readonly kind: TestRunSuiteKind;\n /** One-based shard index within `shardCount`. */\n readonly shardIndex: number;\n /** Total number of shards the suite was split into. */\n readonly shardCount: number;\n /** Final shard outcome. */\n readonly outcome: TestRunSuiteOutcome;\n /** Number of passed tests. */\n readonly passed: number;\n /** Number of failed tests. */\n readonly failed: number;\n /** Number of skipped tests. */\n readonly skipped: number;\n /** Number of retried tests; retries must always be declared. */\n readonly retries: number;\n /** Wall-clock shard duration in milliseconds. */\n readonly durationMs: number;\n /** Lowercase SHA-256 fingerprint of the exact shard invocation. */\n readonly invocationFingerprint: string;\n /** Retained machine-readable report evidence. */\n readonly report: TestRunRetainedEvidence;\n /** Retained execution log evidence. */\n readonly log: TestRunRetainedEvidence;\n}\n\n/** Independent verification summary over every recorded execution. */\nexport interface TestRunVerification {\n /** Stable identity of the independent verifier. */\n readonly verifier: string;\n /** Millisecond-precision UTC time the verification completed. */\n readonly completedAt: string;\n /** Final verification outcome. */\n readonly outcome: TestRunVerificationOutcome;\n /** Exact number of recorded target executions. */\n readonly targetCount: number;\n /** Exact number of recorded suite executions. */\n readonly suiteCount: number;\n /** Total passed tests across every recorded suite execution. */\n readonly passed: number;\n /** Total failed tests across every recorded suite execution. */\n readonly failed: number;\n /** Total skipped tests across every recorded suite execution. */\n readonly skipped: number;\n /** Total retried tests across every recorded suite execution. */\n readonly retries: number;\n /** Retained evidence produced by the verification pass. */\n readonly evidence: TestRunRetainedEvidence;\n}\n\n/**\n * Complete, versioned test-run evidence for one release candidate.\n *\n * The record binds application, environment, application contract, source\n * revision, release, and exact artifact fingerprint to bounded target and\n * suite executions, so a `tests` deployment check can only be satisfied by\n * retained, immutable facts instead of a mutable label or path.\n */\nexport interface TestRunEvidence {\n /** Serialized format marker; always {@link TEST_RUN_EVIDENCE_FORMAT}. */\n readonly format: typeof TEST_RUN_EVIDENCE_FORMAT;\n /**\n * Serialized format version.\n *\n * @default 1\n */\n readonly formatVersion?: typeof TEST_RUN_EVIDENCE_FORMAT_VERSION;\n /** Stable record identifier. */\n readonly id: string;\n /** Application the run verified. */\n readonly application: string;\n /** Deployment environment the run verified the candidate for. */\n readonly environment: string;\n /** Lowercase SHA-256 fingerprint of the application contract. */\n readonly contractFingerprint: string;\n /** Exact source revision the candidate was built from. */\n readonly sourceRevision: string;\n /** Release the candidate belongs to. */\n readonly release: string;\n /** Exact artifact the recorded executions exercised. */\n readonly artifact: TestRunArtifact;\n /** Millisecond-precision UTC time the run started. */\n readonly startedAt: string;\n /** Millisecond-precision UTC time the run completed. */\n readonly completedAt: string;\n /** Millisecond-precision UTC time the record expires. */\n readonly validUntil: string;\n /** Authenticated runner that executed the run. */\n readonly runner: TestRunRunner;\n /** Complete candidate-selected target and suite coverage. */\n readonly selection: TestRunSelection;\n /** Recorded target executions. */\n readonly targets: readonly TestRunTargetExecution[];\n /** Recorded suite executions. */\n readonly suites: readonly TestRunSuiteExecution[];\n /** Independent verification summary. */\n readonly verification: TestRunVerification;\n}\n\n/** Target identifiers recorded by one test-run evidence record. */\nexport type TestRunTargetId<Evidence extends TestRunEvidence> = Evidence[\"targets\"][number][\"id\"];\n\n/** Suite identifiers recorded by one test-run evidence record. */\nexport type TestRunSuiteId<Evidence extends TestRunEvidence> = Evidence[\"suites\"][number][\"id\"];\n"],"mappings":";;AACA,MAAa,2BAA2B;;AAGxC,MAAa,mCAAmC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
//#region src/test-run-model.d.ts
|
|
2
|
+
/** Serialized `format` marker for test-run evidence records. */
|
|
3
|
+
declare const TEST_RUN_EVIDENCE_FORMAT: "vize.test-run.evidence";
|
|
4
|
+
/** Current serialized test-run evidence format version. */
|
|
5
|
+
declare const TEST_RUN_EVIDENCE_FORMAT_VERSION: 1;
|
|
6
|
+
/** Isolation level of the runner that executed the tests. */
|
|
7
|
+
type TestRunIsolation = "dedicated" | "ephemeral";
|
|
8
|
+
/** Kind of user-visible target a test execution ran against. */
|
|
9
|
+
type TestRunTargetKind = "web" | "native" | "desktop" | "terminal" | "server";
|
|
10
|
+
/** Semantic kind of one executed suite. */
|
|
11
|
+
type TestRunSuiteKind = "unit" | "integration" | "contract" | "end-to-end" | "accessibility" | "visual" | "performance" | "resilience" | "installation" | "upgrade" | "migration";
|
|
12
|
+
/** Final result of one executed suite shard. */
|
|
13
|
+
type TestRunSuiteOutcome = "passed" | "failed" | "cancelled";
|
|
14
|
+
/** Final result of the independent verification pass. */
|
|
15
|
+
type TestRunVerificationOutcome = "accepted" | "rejected";
|
|
16
|
+
/**
|
|
17
|
+
* Immutable, content-addressed reference to retained evidence.
|
|
18
|
+
*
|
|
19
|
+
* The reference names the retained content by SHA-256 so a green label can
|
|
20
|
+
* never drift away from the bytes that were verified.
|
|
21
|
+
*/
|
|
22
|
+
interface TestRunRetainedEvidence {
|
|
23
|
+
/** Content-addressed retrieval reference in `sha256:<64 hex>` form. */
|
|
24
|
+
readonly reference: string;
|
|
25
|
+
/** Lowercase SHA-256 fingerprint of the retained content. */
|
|
26
|
+
readonly fingerprint: string;
|
|
27
|
+
}
|
|
28
|
+
/** Exact release artifact that the recorded test executions exercised. */
|
|
29
|
+
interface TestRunArtifact {
|
|
30
|
+
/** Stable artifact identifier. */
|
|
31
|
+
readonly id: string;
|
|
32
|
+
/** Lowercase SHA-256 fingerprint of the artifact bytes. */
|
|
33
|
+
readonly fingerprint: string;
|
|
34
|
+
/** Exact artifact size in bytes; must be at least one byte. */
|
|
35
|
+
readonly sizeBytes: number;
|
|
36
|
+
}
|
|
37
|
+
/** Authenticated runner that executed the recorded test run. */
|
|
38
|
+
interface TestRunRunner {
|
|
39
|
+
/** Stable runner identity. */
|
|
40
|
+
readonly identity: string;
|
|
41
|
+
/** Retained evidence for the runner's authentication. */
|
|
42
|
+
readonly authenticationEvidence: TestRunRetainedEvidence;
|
|
43
|
+
/** Isolation level the runner guaranteed for this invocation. */
|
|
44
|
+
readonly isolation: TestRunIsolation;
|
|
45
|
+
/** Lowercase SHA-256 fingerprint of the exact invocation. */
|
|
46
|
+
readonly invocationFingerprint: string;
|
|
47
|
+
/** Retained evidence describing the execution environment. */
|
|
48
|
+
readonly environmentEvidence: TestRunRetainedEvidence;
|
|
49
|
+
/** Lowercase SHA-256 fingerprint of the execution environment. */
|
|
50
|
+
readonly environmentFingerprint: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Complete candidate-selected target and suite coverage for the run.
|
|
54
|
+
*
|
|
55
|
+
* Recorded executions must cover exactly these identifiers; anything less is
|
|
56
|
+
* an undeclared omission and anything more is an undeclared execution.
|
|
57
|
+
*/
|
|
58
|
+
interface TestRunSelection<TargetId extends string = string, SuiteId extends string = string> {
|
|
59
|
+
/** Selected target identifiers, unique within the selection. */
|
|
60
|
+
readonly targetIds: readonly TargetId[];
|
|
61
|
+
/** Selected suite identifiers, unique within the selection. */
|
|
62
|
+
readonly suiteIds: readonly SuiteId[];
|
|
63
|
+
}
|
|
64
|
+
/** One executed target of the release candidate. */
|
|
65
|
+
interface TestRunTargetExecution<Id extends string = string> {
|
|
66
|
+
/** Stable target identifier from the candidate selection. */
|
|
67
|
+
readonly id: Id;
|
|
68
|
+
/** Kind of target that was exercised. */
|
|
69
|
+
readonly kind: TestRunTargetKind;
|
|
70
|
+
/** Environment identifier the target executed in. */
|
|
71
|
+
readonly environment: string;
|
|
72
|
+
}
|
|
73
|
+
/** One executed suite shard with its exact recorded results. */
|
|
74
|
+
interface TestRunSuiteExecution<Id extends string = string, TargetId extends string = string> {
|
|
75
|
+
/** Stable suite identifier from the candidate selection. */
|
|
76
|
+
readonly id: Id;
|
|
77
|
+
/** Target this shard executed against. */
|
|
78
|
+
readonly targetId: TargetId;
|
|
79
|
+
/** Semantic suite kind. */
|
|
80
|
+
readonly kind: TestRunSuiteKind;
|
|
81
|
+
/** One-based shard index within `shardCount`. */
|
|
82
|
+
readonly shardIndex: number;
|
|
83
|
+
/** Total number of shards the suite was split into. */
|
|
84
|
+
readonly shardCount: number;
|
|
85
|
+
/** Final shard outcome. */
|
|
86
|
+
readonly outcome: TestRunSuiteOutcome;
|
|
87
|
+
/** Number of passed tests. */
|
|
88
|
+
readonly passed: number;
|
|
89
|
+
/** Number of failed tests. */
|
|
90
|
+
readonly failed: number;
|
|
91
|
+
/** Number of skipped tests. */
|
|
92
|
+
readonly skipped: number;
|
|
93
|
+
/** Number of retried tests; retries must always be declared. */
|
|
94
|
+
readonly retries: number;
|
|
95
|
+
/** Wall-clock shard duration in milliseconds. */
|
|
96
|
+
readonly durationMs: number;
|
|
97
|
+
/** Lowercase SHA-256 fingerprint of the exact shard invocation. */
|
|
98
|
+
readonly invocationFingerprint: string;
|
|
99
|
+
/** Retained machine-readable report evidence. */
|
|
100
|
+
readonly report: TestRunRetainedEvidence;
|
|
101
|
+
/** Retained execution log evidence. */
|
|
102
|
+
readonly log: TestRunRetainedEvidence;
|
|
103
|
+
}
|
|
104
|
+
/** Independent verification summary over every recorded execution. */
|
|
105
|
+
interface TestRunVerification {
|
|
106
|
+
/** Stable identity of the independent verifier. */
|
|
107
|
+
readonly verifier: string;
|
|
108
|
+
/** Millisecond-precision UTC time the verification completed. */
|
|
109
|
+
readonly completedAt: string;
|
|
110
|
+
/** Final verification outcome. */
|
|
111
|
+
readonly outcome: TestRunVerificationOutcome;
|
|
112
|
+
/** Exact number of recorded target executions. */
|
|
113
|
+
readonly targetCount: number;
|
|
114
|
+
/** Exact number of recorded suite executions. */
|
|
115
|
+
readonly suiteCount: number;
|
|
116
|
+
/** Total passed tests across every recorded suite execution. */
|
|
117
|
+
readonly passed: number;
|
|
118
|
+
/** Total failed tests across every recorded suite execution. */
|
|
119
|
+
readonly failed: number;
|
|
120
|
+
/** Total skipped tests across every recorded suite execution. */
|
|
121
|
+
readonly skipped: number;
|
|
122
|
+
/** Total retried tests across every recorded suite execution. */
|
|
123
|
+
readonly retries: number;
|
|
124
|
+
/** Retained evidence produced by the verification pass. */
|
|
125
|
+
readonly evidence: TestRunRetainedEvidence;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Complete, versioned test-run evidence for one release candidate.
|
|
129
|
+
*
|
|
130
|
+
* The record binds application, environment, application contract, source
|
|
131
|
+
* revision, release, and exact artifact fingerprint to bounded target and
|
|
132
|
+
* suite executions, so a `tests` deployment check can only be satisfied by
|
|
133
|
+
* retained, immutable facts instead of a mutable label or path.
|
|
134
|
+
*/
|
|
135
|
+
interface TestRunEvidence {
|
|
136
|
+
/** Serialized format marker; always {@link TEST_RUN_EVIDENCE_FORMAT}. */
|
|
137
|
+
readonly format: typeof TEST_RUN_EVIDENCE_FORMAT;
|
|
138
|
+
/**
|
|
139
|
+
* Serialized format version.
|
|
140
|
+
*
|
|
141
|
+
* @default 1
|
|
142
|
+
*/
|
|
143
|
+
readonly formatVersion?: typeof TEST_RUN_EVIDENCE_FORMAT_VERSION;
|
|
144
|
+
/** Stable record identifier. */
|
|
145
|
+
readonly id: string;
|
|
146
|
+
/** Application the run verified. */
|
|
147
|
+
readonly application: string;
|
|
148
|
+
/** Deployment environment the run verified the candidate for. */
|
|
149
|
+
readonly environment: string;
|
|
150
|
+
/** Lowercase SHA-256 fingerprint of the application contract. */
|
|
151
|
+
readonly contractFingerprint: string;
|
|
152
|
+
/** Exact source revision the candidate was built from. */
|
|
153
|
+
readonly sourceRevision: string;
|
|
154
|
+
/** Release the candidate belongs to. */
|
|
155
|
+
readonly release: string;
|
|
156
|
+
/** Exact artifact the recorded executions exercised. */
|
|
157
|
+
readonly artifact: TestRunArtifact;
|
|
158
|
+
/** Millisecond-precision UTC time the run started. */
|
|
159
|
+
readonly startedAt: string;
|
|
160
|
+
/** Millisecond-precision UTC time the run completed. */
|
|
161
|
+
readonly completedAt: string;
|
|
162
|
+
/** Millisecond-precision UTC time the record expires. */
|
|
163
|
+
readonly validUntil: string;
|
|
164
|
+
/** Authenticated runner that executed the run. */
|
|
165
|
+
readonly runner: TestRunRunner;
|
|
166
|
+
/** Complete candidate-selected target and suite coverage. */
|
|
167
|
+
readonly selection: TestRunSelection;
|
|
168
|
+
/** Recorded target executions. */
|
|
169
|
+
readonly targets: readonly TestRunTargetExecution[];
|
|
170
|
+
/** Recorded suite executions. */
|
|
171
|
+
readonly suites: readonly TestRunSuiteExecution[];
|
|
172
|
+
/** Independent verification summary. */
|
|
173
|
+
readonly verification: TestRunVerification;
|
|
174
|
+
}
|
|
175
|
+
/** Target identifiers recorded by one test-run evidence record. */
|
|
176
|
+
type TestRunTargetId<Evidence extends TestRunEvidence> = Evidence["targets"][number]["id"];
|
|
177
|
+
/** Suite identifiers recorded by one test-run evidence record. */
|
|
178
|
+
type TestRunSuiteId<Evidence extends TestRunEvidence> = Evidence["suites"][number]["id"];
|
|
179
|
+
//#endregion
|
|
180
|
+
export { TestRunVerificationOutcome as _, TestRunIsolation as a, TestRunSelection as c, TestRunSuiteKind as d, TestRunSuiteOutcome as f, TestRunVerification as g, TestRunTargetKind as h, TestRunEvidence as i, TestRunSuiteExecution as l, TestRunTargetId as m, TEST_RUN_EVIDENCE_FORMAT_VERSION as n, TestRunRetainedEvidence as o, TestRunTargetExecution as p, TestRunArtifact as r, TestRunRunner as s, TEST_RUN_EVIDENCE_FORMAT as t, TestRunSuiteId as u };
|
|
181
|
+
//# sourceMappingURL=test-run-model-DkllmEsY.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run-model-DkllmEsY.d.mts","names":[],"sources":["../src/test-run-model.ts"],"mappings":";;cACa,wBAAA;;cAGA,gCAAA;;KAGD,gBAAA;AAHZ;AAAA,KAMY,iBAAA;;KAGA,gBAAA;;KAcA,mBAAA;;KAGA,0BAAA;;;AApBZ;;;;UA4BiB,uBAAA;EAzBL;EAAA,SA2BD,SAAA;;WAEA,WAAA;AAAA;AAfX;AAAA,UAmBiB,eAAA;;WAEN,EAAA;EArBoB;EAAA,SAuBpB,WAAA;EApB2B;EAAA,SAsB3B,SAAA;AAAA;;UAIM,aAAA;EAlBuB;EAAA,SAoB7B,QAAA;EAlBA;EAAA,SAoBA,sBAAA,EAAwB,uBAAA;EAdlB;EAAA,SAgBN,SAAA,EAAW,gBAAA;;WAEX,qBAAA;EAhBA;EAAA,SAkBA,mBAAA,EAAqB,uBAAA;EAdrB;EAAA,SAgBA,sBAAA;AAAA;AAZX;;;;;;AAAA,UAqBiB,gBAAA;EAXsC;EAAA,SAgB5C,SAAA,WAAoB,QAAA;EAtBpB;EAAA,SAwBA,QAAA,WAAmB,OAAA;AAAA;;UAIb,sBAAA;EAtBN;EAAA,SAwBA,EAAA,EAAI,EAAA;EAtBJ;EAAA,SAwBA,IAAA,EAAM,iBAAA;EAxBgB;EAAA,SA0BtB,WAAA;AAAA;;UAIM,qBAAA;EApBf;EAAA,SAyBS,EAAA,EAAI,EAAA;EArBJ;EAAA,SAuBA,QAAA,EAAU,QAAA;EArBV;EAAA,SAuBA,IAAA,EAAM,gBAAA;EAvBoB;EAAA,SAyB1B,UAAA;EArBM;EAAA,SAuBN,UAAA;EAvB4B;EAAA,SAyB5B,OAAA,EAAS,mBAAA;EAzBoB;EAAA,SA2B7B,MAAA;EAzBI;EAAA,SA2BJ,MAAA;EAzBM;EAAA,SA2BN,OAAA;EAzBW;EAAA,SA2BX,OAAA;EAvBM;EAAA,SAyBN,UAAA;EAzB2B;EAAA,SA2B3B,qBAAA;EApBU;EAAA,SAsBV,MAAA,EAAQ,uBAAA;EAdC;EAAA,SAgBT,GAAA,EAAK,uBAAA;AAAA;;UAIC,mBAAA;EAlCf;EAAA,SAoCS,QAAA;EAhCA;EAAA,SAkCA,WAAA;EAhCA;EAAA,SAkCA,OAAA,EAAS,0BAAA;EAhCT;EAAA,SAkCA,WAAA;EAhCA;EAAA,SAkCA,UAAA;EA9BA;EAAA,SAgCA,MAAA;EA9BA;EAAA,SAgCA,MAAA;EA5BA;EAAA,SA8BA,OAAA;EA1BA;EAAA,SA4BA,OAAA;EAxBA;EAAA,SA0BA,QAAA,EAAU,uBAAA;AAAA;;;;AApBrB;;;;;UA+BiB,eAAA;EAzBN;EAAA,SA2BA,MAAA,SAAe,wBAAA;EAzBf;;;;;EAAA,SA+BA,aAAA,UAAuB,gCAAA;EAnBvB;EAAA,SAqBA,EAAA;EArBiC;EAAA,SAuBjC,WAAA;EAZM;EAAA,SAcN,WAAA;;WAEA,mBAAA;EARuB;EAAA,SAUvB,cAAA;EAYQ;EAAA,SAVR,OAAA;EAckB;EAAA,SAZlB,QAAA,EAAU,eAAA;EAgBI;EAAA,SAdd,SAAA;EAciC;EAAA,SAZjC,WAAA;EAxBe;EAAA,SA0Bf,UAAA;EApBuB;EAAA,SAsBvB,MAAA,EAAQ,aAAA;EAlBR;EAAA,SAoBA,SAAA,EAAW,gBAAA;EAhBX;EAAA,SAkBA,OAAA,WAAkB,sBAAA;EAdlB;EAAA,SAgBA,MAAA,WAAiB,qBAAA;EAdP;EAAA,SAgBV,YAAA,EAAc,mBAAA;AAAA;;KAIb,eAAA,kBAAiC,eAAA,IAAmB,QAAA;;KAGpD,cAAA,kBAAgC,eAAA,IAAmB,QAAA"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import "./test-run-model-B2INFVlw.mjs";
|
|
2
|
+
const IDENTIFIER = /^[a-z0-9][a-z0-9._-]*$/;
|
|
3
|
+
const DIGEST = /^[a-f0-9]{64}$/;
|
|
4
|
+
const SOURCE_REVISION = /^[a-f0-9]{40,128}$/;
|
|
5
|
+
const TIMESTAMP = /^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z$/;
|
|
6
|
+
/** Builds the stable diagnostic path for a named collection member. */
|
|
7
|
+
function evidencePath(collection, id) {
|
|
8
|
+
return `${collection}.${id}`;
|
|
9
|
+
}
|
|
10
|
+
/** Creates one error diagnostic. */
|
|
11
|
+
function error(code, path, message) {
|
|
12
|
+
return {
|
|
13
|
+
code,
|
|
14
|
+
severity: "error",
|
|
15
|
+
path,
|
|
16
|
+
message
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Validates the shared identifier grammar and the schema length bound. */
|
|
20
|
+
function checkIdentifier(id, path, diagnostics) {
|
|
21
|
+
if (!IDENTIFIER.test(id)) diagnostics.push(error("VIZE_MARQUETTE_103", path, "identifier must use lowercase ASCII letters, digits, dash, underscore, or dot"));
|
|
22
|
+
if (id.length === 0 || id.length > 128) diagnostics.push(error("VIZE_MARQUETTE_103", path, "identifier must be between 1 and 128 characters"));
|
|
23
|
+
}
|
|
24
|
+
/** Validates a lowercase 64-character SHA-256 fingerprint. */
|
|
25
|
+
function checkDigest(value, path, diagnostics) {
|
|
26
|
+
if (!DIGEST.test(value)) diagnostics.push(error("VIZE_MARQUETTE_104", path, "fingerprint must be 64 lowercase hexadecimal characters"));
|
|
27
|
+
}
|
|
28
|
+
/** Validates an exact source revision digest. */
|
|
29
|
+
function checkSourceRevision(value, diagnostics) {
|
|
30
|
+
if (!SOURCE_REVISION.test(value)) diagnostics.push(error("VIZE_MARQUETTE_105", "sourceRevision", "source revision must be 40 to 128 lowercase hexadecimal characters"));
|
|
31
|
+
}
|
|
32
|
+
/** Returns whether `value` is a millisecond-precision UTC calendar instant. */
|
|
33
|
+
function isStrictTimestamp(value) {
|
|
34
|
+
const match = TIMESTAMP.exec(value);
|
|
35
|
+
if (match === null) return false;
|
|
36
|
+
const year = Number(match[1]);
|
|
37
|
+
const month = Number(match[2]);
|
|
38
|
+
return Number(match[3]) <= (month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31);
|
|
39
|
+
}
|
|
40
|
+
/** Validates a millisecond-precision UTC timestamp. */
|
|
41
|
+
function checkTimestamp(value, path, diagnostics) {
|
|
42
|
+
if (!isStrictTimestamp(value)) diagnostics.push(error("VIZE_MARQUETTE_107", path, "timestamp must be a millisecond-precision UTC instant like 2026-01-01T00:00:00.000Z"));
|
|
43
|
+
}
|
|
44
|
+
/** Rejects integers that lose precision in a consuming language. */
|
|
45
|
+
function checkSafeInteger(value, path, diagnostics) {
|
|
46
|
+
if (value > 9007199254740991) diagnostics.push(error("VIZE_MARQUETTE_111", path, "value must not exceed the largest exactly-representable integer"));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates an immutable retained-evidence binding.
|
|
50
|
+
*
|
|
51
|
+
* The retrieval reference must be content-addressed and name exactly the
|
|
52
|
+
* fingerprinted bytes; anything else would let retained evidence mutate
|
|
53
|
+
* behind a stable-looking record.
|
|
54
|
+
*/
|
|
55
|
+
function checkRetainedEvidence(retained, path, diagnostics) {
|
|
56
|
+
checkDigest(retained.fingerprint, evidencePath(path, "fingerprint"), diagnostics);
|
|
57
|
+
const suffix = retained.reference.startsWith("sha256:") ? retained.reference.slice(7) : void 0;
|
|
58
|
+
if (suffix === void 0 || !DIGEST.test(suffix)) diagnostics.push(error("VIZE_MARQUETTE_108", evidencePath(path, "reference"), "evidence reference must be sha256: followed by 64 lowercase hexadecimal characters"));
|
|
59
|
+
else if (suffix !== retained.fingerprint) diagnostics.push(error("VIZE_MARQUETTE_109", evidencePath(path, "reference"), "content-addressed reference must name the fingerprinted content"));
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/test-run-validate-executions.ts
|
|
63
|
+
/** Maximum recorded target executions and selected target identifiers. */
|
|
64
|
+
const TEST_RUN_MAX_TARGETS = 32;
|
|
65
|
+
/** Maximum recorded suite executions and selected suite identifiers. */
|
|
66
|
+
const TEST_RUN_MAX_SUITES = 512;
|
|
67
|
+
/** Maximum shard index and shard count for one suite execution. */
|
|
68
|
+
const TEST_RUN_MAX_SHARDS = 1024;
|
|
69
|
+
/** Validates recorded target executions against the candidate selection. */
|
|
70
|
+
function validateTargets(evidence, diagnostics) {
|
|
71
|
+
if (evidence.targets.length === 0 || evidence.targets.length > 32) diagnostics.push(error("VIZE_MARQUETTE_131", "targets", "record must include between 1 and 32 target executions"));
|
|
72
|
+
const seen = /* @__PURE__ */ new Set();
|
|
73
|
+
const selected = new Set(evidence.selection.targetIds);
|
|
74
|
+
for (const target of evidence.targets) {
|
|
75
|
+
const path = evidencePath("targets", target.id);
|
|
76
|
+
checkIdentifier(target.id, path, diagnostics);
|
|
77
|
+
checkIdentifier(target.environment, evidencePath(path, "environment"), diagnostics);
|
|
78
|
+
if (seen.has(target.id)) diagnostics.push(error("VIZE_MARQUETTE_117", path, "target execution is recorded more than once"));
|
|
79
|
+
seen.add(target.id);
|
|
80
|
+
if (!selected.has(target.id)) diagnostics.push(error("VIZE_MARQUETTE_118", path, "target execution was not selected for this candidate"));
|
|
81
|
+
}
|
|
82
|
+
for (const id of evidence.selection.targetIds) if (!seen.has(id)) diagnostics.push(error("VIZE_MARQUETTE_119", evidencePath("selection.targetIds", id), "selected target has no recorded execution"));
|
|
83
|
+
}
|
|
84
|
+
/** Validates recorded suite executions, shards, and their consistency. */
|
|
85
|
+
function validateSuites(evidence, diagnostics) {
|
|
86
|
+
if (evidence.suites.length === 0 || evidence.suites.length > 512) diagnostics.push(error("VIZE_MARQUETTE_131", "suites", "record must include between 1 and 512 suite executions"));
|
|
87
|
+
const shards = /* @__PURE__ */ new Map();
|
|
88
|
+
const selected = new Set(evidence.selection.suiteIds);
|
|
89
|
+
const recordedTargets = new Set(evidence.targets.map((target) => target.id));
|
|
90
|
+
for (const suite of evidence.suites) {
|
|
91
|
+
const path = evidencePath("suites", suite.id);
|
|
92
|
+
let group = shards.get(suite.id);
|
|
93
|
+
if (group === void 0) {
|
|
94
|
+
group = {
|
|
95
|
+
shardCount: suite.shardCount,
|
|
96
|
+
kind: suite.kind,
|
|
97
|
+
targetId: suite.targetId,
|
|
98
|
+
indexes: /* @__PURE__ */ new Set(),
|
|
99
|
+
kindsDisagree: false,
|
|
100
|
+
targetsDisagree: false,
|
|
101
|
+
countsDisagree: false
|
|
102
|
+
};
|
|
103
|
+
shards.set(suite.id, group);
|
|
104
|
+
checkIdentifier(suite.id, path, diagnostics);
|
|
105
|
+
if (!selected.has(suite.id)) diagnostics.push(error("VIZE_MARQUETTE_121", path, "suite execution was not selected for this candidate"));
|
|
106
|
+
if (!recordedTargets.has(suite.targetId)) diagnostics.push(error("VIZE_MARQUETTE_123", evidencePath(path, "targetId"), "suite target has no recorded target execution"));
|
|
107
|
+
}
|
|
108
|
+
group.kindsDisagree ||= group.kind !== suite.kind;
|
|
109
|
+
group.targetsDisagree ||= group.targetId !== suite.targetId;
|
|
110
|
+
group.countsDisagree ||= group.shardCount !== suite.shardCount;
|
|
111
|
+
if (group.indexes.has(suite.shardIndex)) diagnostics.push(error("VIZE_MARQUETTE_120", path, "suite shard is recorded more than once"));
|
|
112
|
+
group.indexes.add(suite.shardIndex);
|
|
113
|
+
if (suite.shardCount === 0 || suite.shardCount > 1024 || suite.shardIndex === 0 || suite.shardIndex > suite.shardCount) diagnostics.push(error("VIZE_MARQUETTE_124", evidencePath(path, "shardIndex"), "shard index must fall within a shard count between 1 and 1024"));
|
|
114
|
+
checkSafeInteger(suite.durationMs, evidencePath(path, "durationMs"), diagnostics);
|
|
115
|
+
checkDigest(suite.invocationFingerprint, evidencePath(path, "invocationFingerprint"), diagnostics);
|
|
116
|
+
checkRetainedEvidence(suite.report, evidencePath(path, "report"), diagnostics);
|
|
117
|
+
checkRetainedEvidence(suite.log, evidencePath(path, "log"), diagnostics);
|
|
118
|
+
const executed = suite.passed + suite.failed + suite.skipped;
|
|
119
|
+
if (!(suite.outcome === "passed" ? suite.failed === 0 && executed > 0 : suite.outcome === "failed" ? suite.failed > 0 : true)) diagnostics.push(error("VIZE_MARQUETTE_130", evidencePath(path, "outcome"), "suite outcome does not match its recorded counts"));
|
|
120
|
+
}
|
|
121
|
+
for (const id of evidence.selection.suiteIds) if (!shards.has(id)) diagnostics.push(error("VIZE_MARQUETTE_122", evidencePath("selection.suiteIds", id), "selected suite has no recorded execution"));
|
|
122
|
+
for (const [id, group] of shards) {
|
|
123
|
+
const path = evidencePath("suites", id);
|
|
124
|
+
if (group.kindsDisagree || group.targetsDisagree || group.countsDisagree) diagnostics.push(error("VIZE_MARQUETTE_126", path, "every shard of one suite must share its kind, target, and shard count"));
|
|
125
|
+
else if (group.shardCount !== 0 && group.shardCount <= 1024 && group.indexes.size !== group.shardCount) diagnostics.push(error("VIZE_MARQUETTE_125", path, `suite must record every shard from 1 to ${group.shardCount}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Validates the independent verification summary. */
|
|
129
|
+
function validateVerification(evidence, diagnostics) {
|
|
130
|
+
const verification = evidence.verification;
|
|
131
|
+
checkIdentifier(verification.verifier, "verification.verifier", diagnostics);
|
|
132
|
+
checkTimestamp(verification.completedAt, "verification.completedAt", diagnostics);
|
|
133
|
+
checkRetainedEvidence(verification.evidence, "verification.evidence", diagnostics);
|
|
134
|
+
if (verification.completedAt < evidence.completedAt) diagnostics.push(error("VIZE_MARQUETTE_114", "verification.completedAt", "verification must complete after the run completes"));
|
|
135
|
+
if (verification.targetCount !== evidence.targets.length) diagnostics.push(error("VIZE_MARQUETTE_127", "verification.targetCount", "verified target count must equal the recorded target executions"));
|
|
136
|
+
if (verification.suiteCount !== evidence.suites.length) diagnostics.push(error("VIZE_MARQUETTE_127", "verification.suiteCount", "verified suite count must equal the recorded suite executions"));
|
|
137
|
+
const totals = {
|
|
138
|
+
passed: 0,
|
|
139
|
+
failed: 0,
|
|
140
|
+
skipped: 0,
|
|
141
|
+
retries: 0
|
|
142
|
+
};
|
|
143
|
+
for (const suite of evidence.suites) {
|
|
144
|
+
totals.passed += suite.passed;
|
|
145
|
+
totals.failed += suite.failed;
|
|
146
|
+
totals.skipped += suite.skipped;
|
|
147
|
+
totals.retries += suite.retries;
|
|
148
|
+
}
|
|
149
|
+
const recorded = [
|
|
150
|
+
[
|
|
151
|
+
totals.passed,
|
|
152
|
+
verification.passed,
|
|
153
|
+
"verification.passed",
|
|
154
|
+
"passed"
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
totals.failed,
|
|
158
|
+
verification.failed,
|
|
159
|
+
"verification.failed",
|
|
160
|
+
"failed"
|
|
161
|
+
],
|
|
162
|
+
[
|
|
163
|
+
totals.skipped,
|
|
164
|
+
verification.skipped,
|
|
165
|
+
"verification.skipped",
|
|
166
|
+
"skipped"
|
|
167
|
+
],
|
|
168
|
+
[
|
|
169
|
+
totals.retries,
|
|
170
|
+
verification.retries,
|
|
171
|
+
"verification.retries",
|
|
172
|
+
"retried"
|
|
173
|
+
]
|
|
174
|
+
];
|
|
175
|
+
for (const [total, value, path, name] of recorded) if (total !== value) diagnostics.push(error("VIZE_MARQUETTE_128", path, `verified ${name} total must equal the sum over suite executions`));
|
|
176
|
+
if (verification.outcome === "accepted") {
|
|
177
|
+
if (!evidence.suites.every((suite) => suite.outcome === "passed" && suite.failed === 0) || verification.failed > 0) diagnostics.push(error("VIZE_MARQUETTE_129", "verification.outcome", "verification cannot accept a run with failed or cancelled executions"));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/test-run-validate.ts
|
|
182
|
+
/**
|
|
183
|
+
* Validates a complete test-run evidence record.
|
|
184
|
+
*
|
|
185
|
+
* Diagnostics are deterministic and sorted by path, code, and message so the
|
|
186
|
+
* same record produces identical CLI, promotion, test, and CI output in
|
|
187
|
+
* every consuming language. A record with any error diagnostic must never
|
|
188
|
+
* satisfy a deployment check.
|
|
189
|
+
*/
|
|
190
|
+
function validateTestRunEvidence(evidence) {
|
|
191
|
+
const diagnostics = [];
|
|
192
|
+
if (evidence.format !== "vize.test-run.evidence") diagnostics.push(error("VIZE_MARQUETTE_101", "format", "unsupported test-run evidence format marker"));
|
|
193
|
+
if ((evidence.formatVersion ?? 1) !== 1) diagnostics.push(error("VIZE_MARQUETTE_102", "formatVersion", "unsupported test-run evidence format version"));
|
|
194
|
+
checkIdentifier(evidence.id, "id", diagnostics);
|
|
195
|
+
checkIdentifier(evidence.application, "application", diagnostics);
|
|
196
|
+
checkIdentifier(evidence.environment, "environment", diagnostics);
|
|
197
|
+
checkDigest(evidence.contractFingerprint, "contractFingerprint", diagnostics);
|
|
198
|
+
checkSourceRevision(evidence.sourceRevision, diagnostics);
|
|
199
|
+
if (evidence.release.length === 0 || evidence.release.length > 256) diagnostics.push(error("VIZE_MARQUETTE_106", "release", "release must be between 1 and 256 characters"));
|
|
200
|
+
checkIdentifier(evidence.artifact.id, "artifact.id", diagnostics);
|
|
201
|
+
checkDigest(evidence.artifact.fingerprint, "artifact.fingerprint", diagnostics);
|
|
202
|
+
if (evidence.artifact.sizeBytes === 0) diagnostics.push(error("VIZE_MARQUETTE_110", "artifact.sizeBytes", "artifact size must be at least one byte"));
|
|
203
|
+
checkSafeInteger(evidence.artifact.sizeBytes, "artifact.sizeBytes", diagnostics);
|
|
204
|
+
checkTimestamp(evidence.startedAt, "startedAt", diagnostics);
|
|
205
|
+
checkTimestamp(evidence.completedAt, "completedAt", diagnostics);
|
|
206
|
+
checkTimestamp(evidence.validUntil, "validUntil", diagnostics);
|
|
207
|
+
if (evidence.completedAt < evidence.startedAt) diagnostics.push(error("VIZE_MARQUETTE_112", "completedAt", "run completion must not precede its start"));
|
|
208
|
+
if (evidence.validUntil <= evidence.completedAt) diagnostics.push(error("VIZE_MARQUETTE_113", "validUntil", "record expiry must come after run completion"));
|
|
209
|
+
const runner = evidence.runner;
|
|
210
|
+
checkIdentifier(runner.identity, "runner.identity", diagnostics);
|
|
211
|
+
checkRetainedEvidence(runner.authenticationEvidence, "runner.authenticationEvidence", diagnostics);
|
|
212
|
+
checkDigest(runner.invocationFingerprint, "runner.invocationFingerprint", diagnostics);
|
|
213
|
+
checkRetainedEvidence(runner.environmentEvidence, "runner.environmentEvidence", diagnostics);
|
|
214
|
+
checkDigest(runner.environmentFingerprint, "runner.environmentFingerprint", diagnostics);
|
|
215
|
+
const selection = evidence.selection;
|
|
216
|
+
if (selection.targetIds.length === 0 || selection.targetIds.length > 32) diagnostics.push(error("VIZE_MARQUETTE_115", "selection.targetIds", "selection must include between 1 and 32 targets"));
|
|
217
|
+
if (selection.suiteIds.length === 0 || selection.suiteIds.length > 512) diagnostics.push(error("VIZE_MARQUETTE_115", "selection.suiteIds", "selection must include between 1 and 512 suites"));
|
|
218
|
+
for (const id of selection.targetIds) checkIdentifier(id, evidencePath("selection.targetIds", id), diagnostics);
|
|
219
|
+
for (const id of selection.suiteIds) checkIdentifier(id, evidencePath("selection.suiteIds", id), diagnostics);
|
|
220
|
+
validateTargets(evidence, diagnostics);
|
|
221
|
+
validateSuites(evidence, diagnostics);
|
|
222
|
+
validateVerification(evidence, diagnostics);
|
|
223
|
+
diagnostics.sort((left, right) => left.path !== right.path ? left.path < right.path ? -1 : 1 : left.code !== right.code ? left.code < right.code ? -1 : 1 : left.message < right.message ? -1 : left.message > right.message ? 1 : 0);
|
|
224
|
+
return diagnostics;
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
export { error as a, TEST_RUN_MAX_TARGETS as i, TEST_RUN_MAX_SHARDS as n, isStrictTimestamp as o, TEST_RUN_MAX_SUITES as r, validateTestRunEvidence as t };
|
|
228
|
+
|
|
229
|
+
//# sourceMappingURL=test-run-validate-XF0vyoWI.mjs.map
|