From 81b446d1c20c3ec87586c123264adf7e81a4cea7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:16:59 -0700 Subject: [PATCH 1/6] test(acquisition): reject future deployment evidence timestamps --- ...oyment-evidence-temporal-integrity.test.ts | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 test/acquisition-deployment-evidence-temporal-integrity.test.ts diff --git a/test/acquisition-deployment-evidence-temporal-integrity.test.ts b/test/acquisition-deployment-evidence-temporal-integrity.test.ts new file mode 100644 index 000000000..ddba7a7dd --- /dev/null +++ b/test/acquisition-deployment-evidence-temporal-integrity.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it } from "vitest"; +import { evaluateAcquisitionDeploymentEvidence } from "../scripts/lib/acquisition-deployment-evidence.mjs"; + +const repository = "ContextualWisdomLab/noema"; +const releaseTag = "v0.1.0"; +const commitSha = "a".repeat(40); +const deploymentEvidenceSha256 = "b".repeat(64); + +function fixture() { + return { + expectedTag: releaseTag, + deploymentEvidence: { + schemaVersion: 1, + generatedAt: "2026-08-04T00:00:00.000Z", + source: { + repository, + releaseTag, + releaseRef: `refs/tags/${releaseTag}`, + commitSha, + }, + deployment: { + environment: "production", + workerName: "noema", + trafficPercentage: 100, + workflowRunUrl: `https://github.com/${repository}/actions/runs/123`, + deployedAt: "2026-08-04T00:00:01.000Z", + deploymentCreatedAt: "2026-08-04T00:00:02.000Z", + }, + validation: { + immutableRelease: true, + strictKpi: true, + smokePassed: true, + kpiExecutedAt: "2026-08-03T23:59:50.000Z", + smokeTimestamp: "2026-08-04T00:00:04.000Z", + }, + }, + deploymentEvidenceSha256, + governanceEvidence: { + schema_version: 1, + repository, + environment: "production", + status: "PASS", + reviewer_count: 1, + reviewers: [{ type: "Team", id: 42, identifier: "production-approvers" }], + checks: [{ name: "reviewed", pass: true, detail: "reviewed" }], + failures: [], + }, + attestationBundle: { + mediaType: "application/vnd.dev.sigstore.bundle.v0.3+json", + verificationMaterial: { tlogEntries: [{}] }, + dsseEnvelope: { payload: "ZXZpZGVuY2U=", signatures: [{ sig: "c2ln" }] }, + }, + verificationReceipt: { + schemaVersion: 1, + verified: true, + repository, + releaseTag, + commitSha, + deploymentEvidenceSha256, + signerWorkflow: `${repository}/.github/workflows/cd.yml`, + predicateType: "https://contextualwisdomlab.org/attestations/noema-deployment/v1", + oidcIssuer: "https://token.actions.githubusercontent.com", + denySelfHostedRunners: true, + workflowRunUrl: `https://github.com/${repository}/actions/runs/123`, + }, + }; +} + +function codes(input: ReturnType) { + return evaluateAcquisitionDeploymentEvidence(input).failures.map((entry) => entry.code); +} + +describe("acquisition deployment temporal evidence integrity", () => { + it.each([ + ["generatedAt", (input: ReturnType) => { + input.deploymentEvidence.generatedAt = "2999-01-01T00:00:00.000Z"; + }, "deployment_generated_at_invalid"], + ["deployedAt", (input: ReturnType) => { + input.deploymentEvidence.deployment.deployedAt = "2999-01-01T00:00:00.000Z"; + }, "deployment_deployed_at_invalid"], + ["deploymentCreatedAt", (input: ReturnType) => { + input.deploymentEvidence.deployment.deploymentCreatedAt = "2999-01-01T00:00:00.000Z"; + }, "deployment_created_at_invalid"], + ["kpiExecutedAt", (input: ReturnType) => { + input.deploymentEvidence.validation.kpiExecutedAt = "2999-01-01T00:00:00.000Z"; + }, "deployment_kpi_timestamp_invalid"], + ["smokeTimestamp", (input: ReturnType) => { + input.deploymentEvidence.validation.smokeTimestamp = "2999-01-01T00:00:00.000Z"; + }, "deployment_smoke_timestamp_invalid"], + ])("rejects future-dated %s retained acquisition evidence", (_label, mutate, expectedCode) => { + const input = fixture(); + mutate(input); + + const result = evaluateAcquisitionDeploymentEvidence(input); + + expect(result.pass).toBe(false); + expect(codes(input)).toContain(expectedCode); + }); +}); From 66504297429e15fcea89d29b89574bd329c55b94 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:19:17 -0700 Subject: [PATCH 2/6] test(acquisition): reject coerced deployment authority --- ...oyment-evidence-temporal-integrity.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/acquisition-deployment-evidence-temporal-integrity.test.ts b/test/acquisition-deployment-evidence-temporal-integrity.test.ts index ddba7a7dd..c462bba22 100644 --- a/test/acquisition-deployment-evidence-temporal-integrity.test.ts +++ b/test/acquisition-deployment-evidence-temporal-integrity.test.ts @@ -96,4 +96,24 @@ describe("acquisition deployment temporal evidence integrity", () => { expect(result.pass).toBe(false); expect(codes(input)).toContain(expectedCode); }); + + it("does not coerce string traffic percentage into deployment authority", () => { + const input = fixture(); + (input.deploymentEvidence.deployment as { trafficPercentage: number | string }).trafficPercentage = "100"; + + const result = evaluateAcquisitionDeploymentEvidence(input); + + expect(result.pass).toBe(false); + expect(codes(input)).toContain("deployment_traffic_not_full"); + }); + + it("does not coerce string reviewer counts into governance authority", () => { + const input = fixture(); + (input.governanceEvidence as { reviewer_count: number | string }).reviewer_count = "1"; + + const result = evaluateAcquisitionDeploymentEvidence(input); + + expect(result.pass).toBe(false); + expect(codes(input)).toContain("governance_reviewer_missing"); + }); }); From c9c974e3272f92c7d94a538a1c5b1b07bf77703a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:31:47 -0700 Subject: [PATCH 3/6] fix(acquisition): validate deployment authority timestamps --- .../lib/acquisition-deployment-evidence.mjs | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/scripts/lib/acquisition-deployment-evidence.mjs b/scripts/lib/acquisition-deployment-evidence.mjs index beb304385..9e2e8bb98 100644 --- a/scripts/lib/acquisition-deployment-evidence.mjs +++ b/scripts/lib/acquisition-deployment-evidence.mjs @@ -8,6 +8,7 @@ const EXPECTED_OIDC_ISSUER = "https://token.actions.githubusercontent.com"; const shaPattern = /^[0-9a-f]{40}$/; const digestPattern = /^[0-9a-f]{64}$/; const tagPattern = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; +const isoCalendarPrefixPattern = /^(\d{4})-(\d{2})-(\d{2})T/; function isObject(value) { return Boolean(value) && typeof value === "object" && !Array.isArray(value); @@ -21,6 +22,26 @@ function canonicalIdentity(value, pattern) { return typeof value === "string" && value === value.trim() && pattern.test(value); } +function isValidNonFutureTimestamp(value, nowMilliseconds) { + if (typeof value !== "string" || value !== value.trim()) { + return false; + } + const calendar = value.match(isoCalendarPrefixPattern); + const timestampMilliseconds = Date.parse(value); + if (!calendar || !Number.isFinite(timestampMilliseconds) || timestampMilliseconds > nowMilliseconds) { + return false; + } + const year = Number(calendar[1]); + const month = Number(calendar[2]); + const day = Number(calendar[3]); + const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + const daysPerMonth = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + return month >= 1 + && month <= 12 + && day >= 1 + && day <= daysPerMonth[month - 1]; +} + function failure(code, detail) { return { code, detail }; } @@ -65,6 +86,7 @@ function validBundle(value) { export function evaluateAcquisitionDeploymentEvidence(input = {}) { const failures = []; + const nowMilliseconds = Date.now(); const expectedTag = text(input.expectedTag); const deployment = input.deploymentEvidence; const governance = input.governanceEvidence; @@ -111,6 +133,12 @@ export function evaluateAcquisitionDeploymentEvidence(input = {}) { "deployment_schema_invalid", "Deployment evidence schemaVersion must be 1.", ); + add( + failures, + isValidNonFutureTimestamp(deployment.generatedAt, nowMilliseconds), + "deployment_generated_at_invalid", + "Deployment evidence generatedAt must be a valid non-future timestamp.", + ); add( failures, deployment.source?.repository === EXPECTED_REPOSITORY, @@ -149,7 +177,7 @@ export function evaluateAcquisitionDeploymentEvidence(input = {}) { ); add( failures, - Number(deployment.deployment?.trafficPercentage) === 100, + deployment.deployment?.trafficPercentage === 100, "deployment_traffic_not_full", "Deployment evidence must prove exactly 100% active traffic.", ); @@ -162,6 +190,18 @@ export function evaluateAcquisitionDeploymentEvidence(input = {}) { "deployment_workflow_url_invalid", "Deployment evidence must contain the trusted repository workflow-run URL.", ); + add( + failures, + isValidNonFutureTimestamp(deployment.deployment?.deployedAt, nowMilliseconds), + "deployment_deployed_at_invalid", + "Deployment deployedAt must be a valid non-future timestamp.", + ); + add( + failures, + isValidNonFutureTimestamp(deployment.deployment?.deploymentCreatedAt, nowMilliseconds), + "deployment_created_at_invalid", + "Deployment deploymentCreatedAt must be a valid non-future timestamp.", + ); add( failures, deployment.validation?.immutableRelease === true, @@ -180,6 +220,18 @@ export function evaluateAcquisitionDeploymentEvidence(input = {}) { "deployment_smoke_failed", "Deployment validation must prove successful post-deployment smoke checks.", ); + add( + failures, + isValidNonFutureTimestamp(deployment.validation?.kpiExecutedAt, nowMilliseconds), + "deployment_kpi_timestamp_invalid", + "Deployment KPI execution time must be a valid non-future timestamp.", + ); + add( + failures, + isValidNonFutureTimestamp(deployment.validation?.smokeTimestamp, nowMilliseconds), + "deployment_smoke_timestamp_invalid", + "Deployment smoke time must be a valid non-future timestamp.", + ); } if (isObject(governance)) { @@ -209,8 +261,8 @@ export function evaluateAcquisitionDeploymentEvidence(input = {}) { ); add( failures, - Number.isSafeInteger(Number(governance.reviewer_count)) - && Number(governance.reviewer_count) > 0 + Number.isSafeInteger(governance.reviewer_count) + && governance.reviewer_count > 0 && Array.isArray(governance.reviewers) && governance.reviewers.length > 0, "governance_reviewer_missing", From c893c57b766cbc6be091cc0ff0b4e0d689ed8edb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:34:04 -0700 Subject: [PATCH 4/6] test(deployment): reject coerced traffic authority --- ...loyment-evidence-traffic-authority.test.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 test/deployment-evidence-traffic-authority.test.ts diff --git a/test/deployment-evidence-traffic-authority.test.ts b/test/deployment-evidence-traffic-authority.test.ts new file mode 100644 index 000000000..96c431e42 --- /dev/null +++ b/test/deployment-evidence-traffic-authority.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it } from "vitest"; +import { buildDeploymentEvidence } from "../scripts/deployment-evidence.mjs"; + +const repository = "ContextualWisdomLab/noema"; +const commitSha = "a".repeat(40); +const workerVersionId = "v1-abc123"; + +function validInput() { + return { + identity: { + repository, + releaseTag: "v0.1.0", + commitSha, + environment: "production", + workflowRunUrl: `${repository}/actions/runs/123`, + generatedAt: "2026-08-04T00:00:00.000Z", + }, + releaseView: { + isImmutable: true, + tagName: "v0.1.0", + url: `https://github.com/${repository}/releases/tag/v0.1.0`, + }, + releaseEvidence: { + schemaVersion: 1, + source: { + repository, + commitSha, + ref: "refs/tags/v0.1.0", + version: "0.1.0", + }, + }, + wranglerOutput: [{ + type: "deploy", + worker_name: "noema", + version_id: workerVersionId, + targets: ["https://noema.example.workers.dev"], + timestamp: "2026-08-04T00:00:01.000Z", + }], + beforeDeployments: [], + afterDeployments: [{ + id: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb", + created_on: "2026-08-04T00:00:02.000Z", + versions: [{ version_id: workerVersionId, percentage: 100 }], + }], + smokeEvidence: { + passed: true, + timestamp: "2026-08-04T00:00:04Z", + noema_exchange_url: "https://noema.example.workers.dev/exchange", + }, + kpiEvidence: { + status: "PASS", + strict: true, + requireWindowDays: 30, + executedAt: "2026-08-03T23:59:50.000Z", + }, + digests: { + releaseEvidenceSha256: "1".repeat(64), + smokeEvidenceSha256: "2".repeat(64), + kpiEvidenceSha256: "3".repeat(64), + }, + }; +} + +describe("deployment traffic authority", () => { + it("rejects string-coerced 100 percent deployment status", () => { + const input = validInput(); + (input.afterDeployments[0].versions[0] as { percentage: number | string }).percentage = "100"; + + expect(() => buildDeploymentEvidence(input)).toThrow("100%"); + }); +}); From b9ad49085c1a950aab5cdaf6ff076e606d5b3cf1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:36:43 -0700 Subject: [PATCH 5/6] test(deployment): reject coerced KPI authority --- test/deployment-evidence-traffic-authority.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/deployment-evidence-traffic-authority.test.ts b/test/deployment-evidence-traffic-authority.test.ts index 96c431e42..7deb35d63 100644 --- a/test/deployment-evidence-traffic-authority.test.ts +++ b/test/deployment-evidence-traffic-authority.test.ts @@ -61,11 +61,18 @@ function validInput() { }; } -describe("deployment traffic authority", () => { +describe("deployment authority types", () => { it("rejects string-coerced 100 percent deployment status", () => { const input = validInput(); (input.afterDeployments[0].versions[0] as { percentage: number | string }).percentage = "100"; expect(() => buildDeploymentEvidence(input)).toThrow("100%"); }); + + it("rejects a string-coerced KPI window", () => { + const input = validInput(); + (input.kpiEvidence as { requireWindowDays: number | string }).requireWindowDays = "30"; + + expect(() => buildDeploymentEvidence(input)).toThrow("KPI evidence"); + }); }); From e29a503595d9487643500ff4ab7b9460046cbb88 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 18:38:24 -0700 Subject: [PATCH 6/6] fix(deployment): preserve typed authority evidence --- scripts/deployment-evidence.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/deployment-evidence.mjs b/scripts/deployment-evidence.mjs index e357119f2..92e453e4d 100644 --- a/scripts/deployment-evidence.mjs +++ b/scripts/deployment-evidence.mjs @@ -153,7 +153,7 @@ function deploymentVersion(deployment, expectedVersionId, label) { if (!match) { fail(`${label} does not identify the active deployment for Worker version ${expectedVersionId}`); } - if (Number(match.percentage) !== 100 || versions.length !== 1) { + if (match.percentage !== 100 || versions.length !== 1) { fail(`${label} must route exactly 100% of traffic to Worker version ${expectedVersionId}`); } return match; @@ -273,7 +273,12 @@ export function buildDeploymentEvidence(input) { } const kpiEvidence = requireObject(root.kpiEvidence, "KPI evidence"); - if (kpiEvidence.status !== "PASS" || kpiEvidence.strict !== true || Number(kpiEvidence.requireWindowDays) < 30) { + if ( + kpiEvidence.status !== "PASS" + || kpiEvidence.strict !== true + || !Number.isSafeInteger(kpiEvidence.requireWindowDays) + || kpiEvidence.requireWindowDays < 30 + ) { fail("KPI evidence must be strict PASS with a required window of at least 30 days"); } const kpiExecutedAt = requireTimestamp(kpiEvidence.executedAt, "KPI evidence executedAt");