From 75c4b4417c07572733f4c5581def4c28319ebdcc Mon Sep 17 00:00:00 2001 From: Andrei Hasna Date: Sun, 9 Aug 2026 20:26:20 +0300 Subject: [PATCH 1/2] feat: add deployment control-plane contracts Agent: codewith-iapp-news --- CHANGELOG.md | 17 + bun.lock | 3 + generated/deployment/v1/checksums.json | 22 + generated/deployment/v1/fixture-bundle.json | 1365 ++++ .../fixtures/artifact-attestation.valid.json | 51 + .../v1/fixtures/build-artifact.valid.json | 103 + .../deployment-approval-decision.valid.json | 88 + .../v1/fixtures/deployment-attempt.valid.json | 104 + .../v1/fixtures/deployment-plan.valid.json | 131 + .../v1/fixtures/deployment-receipt.valid.json | 148 + .../v1/fixtures/deployment-request.valid.json | 71 + .../fixtures/environment-binding.valid.json | 134 + .../v1/fixtures/intent-snapshot.valid.json | 126 + .../v1/fixtures/launch-evidence.valid.json | 109 + .../v1/fixtures/product-projection.valid.json | 57 + .../v1/fixtures/provider-receipt.valid.json | 66 + .../verified-source-candidate.valid.json | 144 + generated/deployment/v1/schema-bundle.json | 6600 +++++++++++++++++ hasna.contract.json | 2 +- package.json | 19 +- scripts/generate-deployment-contract.ts | 86 + scripts/smoke-todos-pack.ts | 43 +- src/deployment-artifacts.ts | 137 + src/deployment-fixtures.ts | 817 ++ src/deployment.ts | 1401 ++++ src/deployment/index.ts | 75 + src/hasna.contract.schema.json | 2 +- src/index.ts | 2 + src/no-cloud.ts | 19 +- src/schemas.ts | 132 +- src/service-contract.ts | 2 +- tests/deployment-artifacts.test.ts | 92 + tests/deployment.test.ts | 221 + tests/no-cloud-edge.test.ts | 16 + tests/published-package-security.test.ts | 2 +- tests/service-contract.test.ts | 33 + 36 files changed, 12425 insertions(+), 15 deletions(-) create mode 100644 generated/deployment/v1/checksums.json create mode 100644 generated/deployment/v1/fixture-bundle.json create mode 100644 generated/deployment/v1/fixtures/artifact-attestation.valid.json create mode 100644 generated/deployment/v1/fixtures/build-artifact.valid.json create mode 100644 generated/deployment/v1/fixtures/deployment-approval-decision.valid.json create mode 100644 generated/deployment/v1/fixtures/deployment-attempt.valid.json create mode 100644 generated/deployment/v1/fixtures/deployment-plan.valid.json create mode 100644 generated/deployment/v1/fixtures/deployment-receipt.valid.json create mode 100644 generated/deployment/v1/fixtures/deployment-request.valid.json create mode 100644 generated/deployment/v1/fixtures/environment-binding.valid.json create mode 100644 generated/deployment/v1/fixtures/intent-snapshot.valid.json create mode 100644 generated/deployment/v1/fixtures/launch-evidence.valid.json create mode 100644 generated/deployment/v1/fixtures/product-projection.valid.json create mode 100644 generated/deployment/v1/fixtures/provider-receipt.valid.json create mode 100644 generated/deployment/v1/fixtures/verified-source-candidate.valid.json create mode 100644 generated/deployment/v1/schema-bundle.json create mode 100644 scripts/generate-deployment-contract.ts create mode 100644 src/deployment-artifacts.ts create mode 100644 src/deployment-fixtures.ts create mode 100644 src/deployment.ts create mode 100644 src/deployment/index.ts create mode 100644 tests/deployment-artifacts.test.ts create mode 100644 tests/deployment.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab926f..1dd9daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to `@hasna/contracts` are documented here. +## [0.10.3] - 2026-08-09 + +- Adds thirteen strict, versioned deployment control-plane contracts covering + product projection through launch evidence, with canonical digest helpers, + linked-record validation, generated JSON Schemas, deterministic fixtures, + checksum manifests, public package exports, and packed-consumer coverage. +- Registers `hasna-deploy` as the deployment app's canonical operator binary + without widening the service-contract allowlist to arbitrary `hasna-*` + names. +- Aligns packed no-cloud scans with the existing 5 MiB source-member policy so + oversized built members are skipped instead of crashing the release gate; + bounded members remain scanned and covered by a two-sided regression. + +PATCH, not minor. The deployment contracts and exports are additive, the +binary alias is a narrow compatibility addition, and the scanner change makes +packed behavior match its documented source-tree behavior. + ## [0.10.2] - 2026-08-08 Ships the two commits that merged to `main` after 0.10.1: diff --git a/bun.lock b/bun.lock index 8227431..43c802b 100644 --- a/bun.lock +++ b/bun.lock @@ -7,6 +7,7 @@ "dependencies": { "commander": "^13.1.0", "zod": "^3.25.76", + "zod-to-json-schema": "^3.24.6", }, "devDependencies": { "@types/bun": "^1.2.4", @@ -60,5 +61,7 @@ "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], } } diff --git a/generated/deployment/v1/checksums.json b/generated/deployment/v1/checksums.json new file mode 100644 index 0000000..8e1e6fd --- /dev/null +++ b/generated/deployment/v1/checksums.json @@ -0,0 +1,22 @@ +{ + "contractVersion": "1.0.0", + "files": { + "fixture-bundle.json": "e6f5a998404bbdb12d31c890164961c0840de48beb921761b6489a15424412d0", + "fixtures/artifact-attestation.valid.json": "09439b2757a883b94be4d09e0ea9d58c9073616c4cf5ac8ab3f2a0aec4f64eec", + "fixtures/build-artifact.valid.json": "5a635e158079ba7fd12bf927ca807e7f7bd8af89f15206dd6c97db0d1c3141d4", + "fixtures/deployment-approval-decision.valid.json": "226e9c744243f24abe67214f3ffe0984796974306534a9636a75e183925216af", + "fixtures/deployment-attempt.valid.json": "25c2d098c70a2741d534ad3e9f9aa7e2a70cd9a1a466e36bfd3f5fb3471ce4cb", + "fixtures/deployment-plan.valid.json": "f827c78f219508c09f43686b9c619958b600739ef45a0275d5e9fde3a8880bd1", + "fixtures/deployment-receipt.valid.json": "4ef301e3485c8dc22bead5c385cd9f539d2f4845011c0b560a08ae91bb37c598", + "fixtures/deployment-request.valid.json": "47701f55f2bd4c234a5582c72e9a27b7e4e3ff56525b5f7e45ca455c2cf8dbe1", + "fixtures/environment-binding.valid.json": "7607d0000fff1b68de7e0e251c3d32ca472f22ca68cfab3297f6907594bb89a1", + "fixtures/intent-snapshot.valid.json": "f98c6e7bbbd4f25b4a1a8004cfe786b81a5d8dd42320b78ebfde727a7fb7e1b2", + "fixtures/launch-evidence.valid.json": "44445c3675fda69c10ac267124b6076dba2ae8b5528a2f2e386af84a6667975e", + "fixtures/product-projection.valid.json": "830dd826540ee9b13a00d2add27cb0b76bc339434b9136ecc3af8185c2166e73", + "fixtures/provider-receipt.valid.json": "69e4788c8a0f3464b7398401ae17af674ba36668f25d9802f6555cd6368abdc8", + "fixtures/verified-source-candidate.valid.json": "2bbe702f74c0caf3ee22399b7a1e734b39f5d122e9ea9ad791ad822eb5ba8f46", + "schema-bundle.json": "52a5593cbf77a9c4209de10425f56bcde01530ee57891c619ff8ef48ecc6dade" + }, + "manifestDigest": "7bffe387d2ccaace03c1077f875387f0b895390f79b662cee223104b677f898d", + "schema": "hasna.deployment.artifact_checksums.v1" +} diff --git a/generated/deployment/v1/fixture-bundle.json b/generated/deployment/v1/fixture-bundle.json new file mode 100644 index 0000000..175ac3a --- /dev/null +++ b/generated/deployment/v1/fixture-bundle.json @@ -0,0 +1,1365 @@ +{ + "contractVersion": "1.0.0", + "fixtureDigest": "51c1a8d58f9fc725bdd51a3ff757415efb5a61bb8da13fb14d34d06927d7479c", + "fixtures": { + "artifactAttestations": [ + { + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "artifactDigest": "9f57aeb5d9ea4e151380cfb3889d40b5cdac9747dd85c89921237df22f7aa29b", + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "evidenceRefs": [ + { + "id": "attestation-policy-result", + "kind": "test_result", + "sha256": "3a1bef67d71fd247cb5deca3e72af7972c2079b44262110743d92bd04b2700dd", + "summary": "Bounded evidence for attestation-policy-result", + "uri": "artifact://deployment-fixture/attestation-policy-result" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "attestation-example-app", + "issuer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "keyRef": { + "id": "signing-key-reference", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/signing-key-reference" + }, + "policyResult": "passed", + "policyRevision": 3, + "predicateKind": "slsa-provenance", + "predicateSchemaVersion": "v1.0", + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "schema": "hasna.artifact_attestation.v1", + "signatureRef": { + "id": "attestation-signature", + "kind": "artifact", + "sha256": "588d4b8435249c69b44b89619956817e6928293a1d75d0db7408c8476805712f", + "summary": "Bounded evidence for attestation-signature", + "uri": "artifact://deployment-fixture/attestation-signature" + } + } + ], + "buildArtifacts": [ + { + "artifactDigest": "9f57aeb5d9ea4e151380cfb3889d40b5cdac9747dd85c89921237df22f7aa29b", + "buildRun": { + "actor": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "constraints": [ + "credential-zero execution" + ], + "costEstimates": [], + "createdAt": "2026-08-09T09:00:00.000Z", + "decisions": [], + "evidenceRefs": [ + { + "id": "build-run-evidence", + "kind": "test_result", + "sha256": "cee6797059a4b2d4bdd5a78ec5ea58ac3760f50b720efdabfe95f3ff7b60b8e5", + "summary": "Bounded evidence for build-run-evidence", + "uri": "artifact://deployment-fixture/build-run-evidence" + } + ], + "finishedAt": "2026-08-09T09:05:00.000Z", + "id": "build-run", + "objective": "Produce verified deployment evidence", + "proofBundleRefs": [], + "resourceRefs": [], + "schema": "hasna.work_run.v1", + "startedAt": "2026-08-09T09:00:00.000Z", + "status": "succeeded", + "validationPlanRefs": [] + }, + "buildWorkflowRef": { + "id": "build-workflow", + "kind": "workflow", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/build-workflow" + }, + "builder": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "kind": "oci_image", + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "provenanceRefs": [ + { + "id": "artifact-provenance", + "kind": "artifact", + "sha256": "03b81cbf545913af8d9f70c9a3643ec3ae0338d0c02854e73a6f16014d4532ec", + "summary": "Bounded evidence for artifact-provenance", + "uri": "artifact://deployment-fixture/artifact-provenance" + } + ], + "repositoryCommitSha": "0123456789abcdef0123456789abcdef01234567", + "repositoryTreeSha": "89abcdef0123456789abcdef0123456789abcdef", + "sbomRefs": [ + { + "id": "artifact-sbom", + "kind": "artifact", + "sha256": "b4f783391e4b7ab46fdb49d5808cd389e1340173eab6afb1a80528664f778ae4", + "summary": "Bounded evidence for artifact-sbom", + "uri": "artifact://deployment-fixture/artifact-sbom" + } + ], + "scanRefs": [ + { + "id": "artifact-scan", + "kind": "test_result", + "sha256": "b5932ac32cf213f10bbaea588f83e9e3dfb0978adce936d8a347f806d6429b73", + "summary": "Bounded evidence for artifact-scan", + "uri": "artifact://deployment-fixture/artifact-scan" + } + ], + "schema": "hasna.build_artifact.v1", + "signatureRefs": [ + { + "id": "artifact-signature", + "kind": "artifact", + "sha256": "75ecda7b490798542b3f6dbd5de7addd705bdefeacb678981545b6a8a916d759", + "summary": "Bounded evidence for artifact-signature", + "uri": "artifact://deployment-fixture/artifact-signature" + } + ], + "sourceCandidate": { + "digest": "ae0668664ad166aec5e57a7990ce41b611cfa74f478a7e56a95a1a93f4bd70f0", + "id": "source-candidate-example-app", + "schema": "hasna.verified_source_candidate.v1" + }, + "status": "active", + "uri": "artifact://deployment-fixture/example-app-image" + } + ], + "deploymentApprovalDecisions": [ + { + "actionId": null, + "actorRole": "approver", + "attemptScope": { + "maximum": 2, + "minimum": 1 + }, + "authorizationPolicyRevision": 4, + "boundInputDigests": [ + { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "kind": "request" + }, + { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "kind": "plan" + }, + { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "kind": "intent" + } + ], + "createdAt": "2026-08-09T09:10:00.000Z", + "decision": { + "actor": { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "decisionType": "approval", + "evidenceRefs": [ + { + "id": "approval-envelope-evidence", + "kind": "report", + "sha256": "69f3bf4095c3714596d75471fd55a0660b985bbe757d9f8ad682c0db5c89b1d3", + "summary": "Bounded evidence for approval-envelope-evidence", + "uri": "artifact://deployment-fixture/approval-envelope-evidence" + } + ], + "id": "approval-envelope-example-app", + "obligations": [ + "retain immutable receipts", + "verify live outcome" + ], + "reason": "Approved after policy and evidence review", + "redactions": [], + "schema": "hasna.decision_envelope.v1", + "selected": [], + "skipped": [], + "status": "allowed" + }, + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-approval-evidence", + "kind": "report", + "sha256": "e3548ec1c75b17714a582350203a9dc66142ef9433bcfe69f256b0ef23d75e0d", + "summary": "Bounded evidence for deployment-approval-evidence", + "uri": "artifact://deployment-fixture/deployment-approval-evidence" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-approval-example-app", + "issuedAt": "2026-08-09T09:10:00.000Z", + "phaseId": null, + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + }, + "runtimeMaterial": null, + "schema": "hasna.deployment_approval_decision.v1", + "scope": "plan", + "separationOfDutiesPassed": true, + "unchangedRetryPolicy": "allowed" + } + ], + "deploymentAttempts": [ + { + "actionSteps": [ + { + "actionId": "apply-workload", + "evidenceRefs": [ + { + "id": "attempt-action-evidence", + "kind": "test_result", + "sha256": "4af04476abe762b8d7a3c55cbb03107ecd1ee3311716216c2731b728ec938eba", + "summary": "Bounded evidence for attempt-action-evidence", + "uri": "artifact://deployment-fixture/attempt-action-evidence" + } + ], + "finishedAt": "2026-08-09T09:18:00.000Z", + "providerCorrelationId": "provider-operation-example-app", + "sequence": 1, + "startedAt": "2026-08-09T09:11:00.000Z", + "state": "succeeded" + } + ], + "approvals": [ + { + "actionId": null, + "decision": { + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "id": "deployment-approval-example-app", + "schema": "hasna.deployment_approval_decision.v1" + }, + "phaseId": null, + "runtimeMaterialDigest": null, + "scope": "plan" + } + ], + "attemptNumber": 1, + "createdAt": "2026-08-09T09:10:00.000Z", + "decisionActors": [ + { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + } + ], + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "environmentLock": { + "fencingToken": 19, + "id": "environment-production-lock" + }, + "evidenceRefs": [ + { + "id": "attempt-evidence", + "kind": "report", + "sha256": "1bf89d5d5cfa2f47a382b6e1b2baf416291269eb2c8612692014b10db274c7d1", + "summary": "Bounded evidence for attempt-evidence", + "uri": "artifact://deployment-fixture/attempt-evidence" + } + ], + "executorActors": [ + { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + } + ], + "failureReason": null, + "finalReceipt": null, + "id": "deployment-attempt-example-app", + "inboxCorrelationRef": { + "id": "inbox-correlation", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/inbox-correlation" + }, + "outboxCorrelationRef": { + "id": "outbox-correlation", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/outbox-correlation" + }, + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + }, + "providerReceipts": [], + "requester": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "retryOf": null, + "revision": 1, + "schema": "hasna.deployment_attempt.v1", + "state": "succeeded", + "updatedAt": "2026-08-09T09:20:00.000Z" + } + ], + "deploymentPlans": [ + { + "actions": [ + { + "approvalScope": "plan", + "compensationOperationId": "provider.rollback", + "dependsOn": [], + "evidenceRequirements": [ + "provider-receipt", + "health-check" + ], + "fencingRequired": true, + "id": "apply-workload", + "idempotencyRequired": true, + "inputs": [ + { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + } + ], + "lockClass": "environment-exclusive", + "maxAttempts": 2, + "operationId": "provider.deploy", + "operationVersion": 1, + "outputSchema": "hasna.provider_receipt.v1", + "postconditions": [ + "provider-observed", + "health-verified" + ], + "preconditions": [ + "immutable-inputs", + "approval-valid" + ], + "providerCapabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "providerOperation": "provider.deploy", + "reconciliationRequired": true, + "retryClass": "reconcile_first", + "riskClass": "high", + "runtimeMaterialKind": null, + "sideEffectClass": "compute_or_infra_mutation", + "timeoutClass": "deployment-standard" + } + ], + "authorizationRequirements": [ + "production-deployer" + ], + "compiler": { + "actor": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "contractKitVersion": "1.0.0", + "version": "1.0.0" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "estimatedCost": { + "amountMicros": 125000, + "basis": "estimated", + "createdAt": "2026-08-09T09:00:00.000Z", + "currency": "USD", + "id": "cost-deployment-fixture", + "provider": "fixture-provider", + "resourceRefs": [], + "schema": "hasna.cost_estimate.v1" + }, + "evidenceRequirements": [ + "provider-receipt", + "live-verification" + ], + "expectedStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-plan-example-app", + "inputs": [ + { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + } + ], + "issuedAt": "2026-08-09T09:10:00.000Z", + "kind": "deployment", + "policyRequirements": [ + "production-policy" + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "providerCapabilityDigests": [ + "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283" + ], + "request": { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "id": "deployment-request-example-app", + "schema": "hasna.deployment_request.v1" + }, + "riskClass": "high", + "rollbackInputs": [], + "schema": "hasna.deployment_plan.v1", + "verificationCriteria": [ + "health", + "readiness", + "version" + ] + } + ], + "deploymentReceipts": [ + { + "approvals": [ + { + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "id": "deployment-approval-example-app", + "schema": "hasna.deployment_approval_decision.v1" + } + ], + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "attempt": { + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "id": "deployment-attempt-example-app", + "revision": 1, + "schema": "hasna.deployment_attempt.v1" + }, + "attestations": [ + { + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "id": "attestation-example-app", + "schema": "hasna.artifact_attestation.v1" + } + ], + "createdAt": "2026-08-09T09:20:00.000Z", + "desiredStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "digest": "5ac775c2791b494ee5f9753c9433a962747d122b255e3e70c6f90bb3657e51ec", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-receipt-evidence", + "kind": "report", + "sha256": "43000f198554ad25fae77c3183d3d94c05337ce86583c49496a2c9908753d191", + "summary": "Bounded evidence for deployment-receipt-evidence", + "uri": "artifact://deployment-fixture/deployment-receipt-evidence" + } + ], + "id": "deployment-receipt-example-app", + "infrastructurePlanRef": { + "id": "infrastructure-plan", + "kind": "artifact", + "sha256": "69729e2f9a9f80c6628533f90f5a7d2a2b74e4c679d5f951993d7e43779a4687", + "summary": "Bounded evidence for infrastructure-plan", + "uri": "artifact://deployment-fixture/infrastructure-plan" + }, + "infrastructureStateLineageRef": { + "id": "infrastructure-state-lineage", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/infrastructure-state-lineage" + }, + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "observedStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "outcome": "succeeded", + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "providerReceipts": [ + { + "digest": "d1bac8566b71d857174f3d12fd955618b60d8e41583a19779e6f769df5e27f2f", + "id": "provider-receipt-example-app", + "schema": "hasna.provider_receipt.v1" + } + ], + "request": { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "id": "deployment-request-example-app", + "schema": "hasna.deployment_request.v1" + }, + "schema": "hasna.deployment_receipt.v1", + "verification": [ + { + "evidenceRefs": [ + { + "id": "health-evidence", + "kind": "test_result", + "sha256": "2c71b1cac3f7d547901e9770c7d83e53fd42c3a1d19aca13a5a6803c99b538c9", + "summary": "Bounded evidence for health-evidence", + "uri": "artifact://deployment-fixture/health-evidence" + } + ], + "id": "health", + "kind": "health", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "readiness-evidence", + "kind": "test_result", + "sha256": "72dcfffdba62e929fbbf8694685a95b63a13fd80fb8e0c76cbad3c99520212b1", + "summary": "Bounded evidence for readiness-evidence", + "uri": "artifact://deployment-fixture/readiness-evidence" + } + ], + "id": "readiness", + "kind": "readiness", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "version-evidence", + "kind": "test_result", + "sha256": "b167aee71fede4fff20a9877818c55560eea193018efbd52fd309e04acc70142", + "summary": "Bounded evidence for version-evidence", + "uri": "artifact://deployment-fixture/version-evidence" + } + ], + "id": "version", + "kind": "version", + "status": "passed" + } + ], + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] + } + ], + "deploymentRequests": [ + { + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "attestations": [ + { + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "id": "attestation-example-app", + "schema": "hasna.artifact_attestation.v1" + } + ], + "auditCorrelationId": "audit-correlation-example-app", + "costEstimate": { + "amountMicros": 125000, + "basis": "estimated", + "createdAt": "2026-08-09T09:00:00.000Z", + "currency": "USD", + "id": "cost-deployment-fixture", + "provider": "fixture-provider", + "resourceRefs": [], + "schema": "hasna.cost_estimate.v1" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-request-evidence", + "kind": "report", + "sha256": "c49d9e0621a055a25676566c00cfcb0c62fa95ffb7d76dde3e3fde8ac38158ab", + "summary": "Bounded evidence for deployment-request-evidence", + "uri": "artifact://deployment-fixture/deployment-request-evidence" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-request-example-app", + "idempotencyKeyFingerprint": "e479de86d15e079ff8c219763d1e022f828eaa2444e68dbd7d9e4286acabed37", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "kind": "deployment", + "policyProfile": "production-policy", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "requestAt": "2026-08-09T09:10:00.000Z", + "requester": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "schema": "hasna.deployment_request.v1", + "sourceRequestId": "source-request-example-app" + } + ], + "environmentBindings": [ + { + "authorizationProfile": "production-authorization", + "backupProfile": "daily-snapshot", + "changeEvidenceRefs": [ + { + "id": "environment-change-evidence", + "kind": "report", + "sha256": "b8b88001421f6a0d07ad16ca06326ee476bf409e362b67a17c2bcbb60809d38b", + "summary": "Bounded evidence for environment-change-evidence", + "uri": "artifact://deployment-fixture/environment-change-evidence" + } + ], + "commercialBindingRef": { + "id": "commercial-binding", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/commercial-binding" + }, + "createdAt": "2026-08-09T09:00:00.000Z", + "dataBackend": "postgresql", + "dataClassification": "private", + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "environment": { + "classification": "production", + "id": "production" + }, + "etag": "65b1cd6489c7c3ec86bee822ab666f6cb33efceaac938a75b53f94f21ef65909", + "id": "environment-production", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "policyProfile": "production-policy", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "providerCapabilityCard": { + "adapterId": "fixture-adapter", + "appId": "example-app", + "auditEvents": [ + "deployment.requested", + "deployment.observed" + ], + "costPosture": "pre-authorized estimate required", + "credentialRequirements": [ + { + "allowedSecretInputs": [ + "credential_ref" + ], + "failClosedDiagnostic": "Provider credential reference is unavailable", + "refName": "deployment-credential-reference", + "requiredForModes": [ + "live_mutating" + ], + "revocationCheck": true + } + ], + "defaultMode": "sandbox", + "evidenceRefs": [ + { + "id": "provider-capability-evidence", + "kind": "report", + "sha256": "0ab44bc669befdb8ef57aacad9443cef9fffb1f0aa8bf0cf7006c682fad4f7f0", + "summary": "Bounded evidence for provider-capability-evidence", + "uri": "artifact://deployment-fixture/provider-capability-evidence" + } + ], + "modes": [ + "sandbox", + "live_mutating" + ], + "operations": [ + { + "noSideEffectSmoke": "provider.observe", + "operation": "provider.deploy", + "reconciliation": "provider.reconcile", + "requiresApproval": true, + "requiresIdempotencyKey": true, + "requiresRollbackOrRevocation": true, + "requiresSandboxEvidence": true, + "rollbackOrRevocation": "provider.rollback", + "sideEffectClass": "compute_or_infra_mutation", + "supportedModes": [ + "sandbox", + "live_mutating" + ] + } + ], + "ownerPackage": "@hasna/contracts", + "providerId": "fixture-provider", + "rateLimitPosture": "bounded", + "redactionRules": [ + "opaque references only" + ] + }, + "providerCapabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "providerConnectionRef": { + "id": "provider-connection", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/provider-connection" + }, + "providerIdentity": { + "accountId": "account-production", + "clusterId": "provider-cluster-production", + "networkId": "provider-network-production", + "projectId": "provider-project-example-app", + "region": "eu-central-1", + "routingId": "provider-routing-production", + "storageId": "provider-storage-production" + }, + "revision": 2, + "rollbackProfile": "prior-artifact", + "schema": "hasna.environment_binding.v1", + "updatedAt": "2026-08-09T09:05:00.000Z", + "writer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + } + } + ], + "intentSnapshots": [ + { + "accessClass": "private-service", + "alarmClass": "service-slo", + "backupClass": "daily-snapshot", + "commitSha": "0123456789abcdef0123456789abcdef01234567", + "configurationRequirements": [ + { + "kind": "secret_reference", + "name": "APP_DATABASE_REF", + "referenceClass": "vault-reference", + "required": true + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "evidenceRefs": [ + { + "id": "intent-evidence", + "kind": "report", + "sha256": "f00eae14e40e96fd35f4747f41aa0bb36862620cd3426e8f76663a4e540a75cf", + "summary": "Bounded evidence for intent-evidence", + "uri": "artifact://deployment-fixture/intent-evidence" + } + ], + "id": "intent-example-app", + "intentDocument": { + "digest": "509bffa5170ea51bba03de7bc52e83c69563d4fd92e933037f8ac68089706a5c", + "path": "deploy/intent.json" + }, + "migration": { + "compatibility": "backward_compatible", + "order": "before_workload", + "rollbackClass": "restore-snapshot" + }, + "networkClass": "private-egress-fenced", + "processes": [ + { + "id": "web", + "liveness": { + "expectedStatuses": [ + 200 + ], + "path": "/health", + "protocol": "https" + }, + "ports": [ + 8080 + ], + "readiness": { + "expectedStatuses": [ + 200 + ], + "path": "/ready", + "protocol": "https" + }, + "resources": { + "cpuMillicores": 250, + "maxReplicas": 3, + "memoryMiB": 512, + "minReplicas": 1 + }, + "role": "web", + "version": { + "expectedStatuses": [ + 200 + ], + "path": "/version", + "protocol": "https" + } + } + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "restoreClass": "point-in-time", + "rollbackClass": "prior-artifact", + "schema": "hasna.intent_snapshot.v1", + "serviceRequirements": [ + { + "class": "postgresql", + "id": "primary-database", + "kind": "database", + "required": true + } + ], + "treeSha": "89abcdef0123456789abcdef0123456789abcdef", + "validationPlan": { + "checks": [ + { + "expected": "Immutable evidence reviewed", + "id": "evidence-review", + "kind": "manual", + "required": true, + "resourceRefs": [] + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "id": "validation-intent", + "objective": "Verify immutable deployment inputs and observable outcomes", + "requiredEvidenceKinds": [ + "test_result" + ], + "schema": "hasna.validation_plan.v1", + "verifier": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + } + } + ], + "launchEvidence": [ + { + "compiledAt": "2026-08-09T09:25:00.000Z", + "createdAt": "2026-08-09T09:25:00.000Z", + "deploymentReceipt": { + "digest": "5ac775c2791b494ee5f9753c9433a962747d122b255e3e70c6f90bb3657e51ec", + "id": "deployment-receipt-example-app", + "schema": "hasna.deployment_receipt.v1" + }, + "digest": "0a5f3b4b9ff46b9f01996845c0164f94099e6a2203c8800567927190254cfd98", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "expiresAt": "2026-08-10T09:00:00.000Z", + "findings": [ + { + "evidenceRefs": [ + { + "id": "launch-follow-up-evidence", + "kind": "report", + "sha256": "b0423bd973dc39dad4635fd501014890d054d806e490821ceb1147222d9827bd", + "summary": "Bounded evidence for launch-follow-up-evidence", + "uri": "artifact://deployment-fixture/launch-follow-up-evidence" + } + ], + "id": "documentation-follow-up", + "severity": "p3", + "status": "accepted" + } + ], + "id": "launch-evidence-example-app", + "independentReview": true, + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "proofBundleRefs": [ + { + "id": "launch-proof-bundle", + "kind": "proof_bundle", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/launch-proof-bundle" + } + ], + "requiredChecks": [ + { + "evidenceRefs": [ + { + "id": "health-evidence", + "kind": "test_result", + "sha256": "2c71b1cac3f7d547901e9770c7d83e53fd42c3a1d19aca13a5a6803c99b538c9", + "summary": "Bounded evidence for health-evidence", + "uri": "artifact://deployment-fixture/health-evidence" + } + ], + "id": "health", + "kind": "health", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "readiness-evidence", + "kind": "test_result", + "sha256": "72dcfffdba62e929fbbf8694685a95b63a13fd80fb8e0c76cbad3c99520212b1", + "summary": "Bounded evidence for readiness-evidence", + "uri": "artifact://deployment-fixture/readiness-evidence" + } + ], + "id": "readiness", + "kind": "readiness", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "version-evidence", + "kind": "test_result", + "sha256": "b167aee71fede4fff20a9877818c55560eea193018efbd52fd309e04acc70142", + "summary": "Bounded evidence for version-evidence", + "uri": "artifact://deployment-fixture/version-evidence" + } + ], + "id": "version", + "kind": "version", + "status": "passed" + } + ], + "schema": "hasna.launch_evidence.v1", + "status": "launched", + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] + } + ], + "productProjections": [ + { + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "displayName": "Example App", + "id": "product-example-app", + "lifecycle": "active", + "ownerRefs": [ + { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + } + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "projectedAt": "2026-08-09T09:00:00.000Z", + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "revision": 1, + "schema": "hasna.product_projection.v1", + "slug": "example-app", + "sourceEvidenceRefs": [ + { + "id": "product-projection-source", + "kind": "report", + "sha256": "ff6415fb8dc367fce3945c107dc3322c63adaa35265dea3b4fc8e3d4e323f772", + "summary": "Bounded evidence for product-projection-source", + "uri": "artifact://deployment-fixture/product-projection-source" + } + ], + "sourceProjectRef": { + "id": "project-contract-fixture", + "kind": "project", + "tags": [ + "deployment-fixture" + ], + "uri": "project://example-app" + }, + "sourceRevision": 7, + "workspaceRef": { + "id": "project-contract-fixture", + "kind": "project", + "tags": [ + "deployment-fixture" + ], + "uri": "project://example-app" + } + } + ], + "providerReceipts": [ + { + "adapter": "fixture-adapter", + "attempt": { + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "id": "deployment-attempt-example-app", + "revision": 1, + "schema": "hasna.deployment_attempt.v1" + }, + "capabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "connectionRef": { + "id": "provider-connection", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/provider-connection" + }, + "createdAt": "2026-08-09T09:18:00.000Z", + "digest": "d1bac8566b71d857174f3d12fd955618b60d8e41583a19779e6f769df5e27f2f", + "id": "provider-receipt-example-app", + "normalizedResult": "succeeded", + "observationEvidenceRefs": [ + { + "id": "provider-observation-evidence", + "kind": "test_result", + "sha256": "415be35f669a860a71be2e6c80d391eaf62fe048c2bc51b04cd9827c4b11815d", + "summary": "Bounded evidence for provider-observation-evidence", + "uri": "artifact://deployment-fixture/provider-observation-evidence" + } + ], + "observedAt": "2026-08-09T09:19:00.000Z", + "observedProviderRevision": "provider-revision-19", + "operationId": "provider.deploy", + "operationVersion": 1, + "producer": { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + }, + "provider": "fixture-provider", + "providerIdentity": { + "deploymentId": "provider-deployment-example-app", + "eventId": "provider-event-example-app", + "operationId": "provider-operation-example-app", + "projectId": "provider-project-example-app", + "resourceIds": [ + "provider-service-example-app" + ] + }, + "providerStatus": "ready", + "reconciliationState": "confirmed", + "redaction": "full", + "requestFingerprint": "e479de86d15e079ff8c219763d1e022f828eaa2444e68dbd7d9e4286acabed37", + "responseEvidenceRefs": [ + { + "id": "provider-response-evidence", + "kind": "report", + "sha256": "9114b94c75d69425bc62fe93e08fdf2d7ca4cc5b4b911f11833214a256daafae", + "summary": "Bounded evidence for provider-response-evidence", + "uri": "artifact://deployment-fixture/provider-response-evidence" + } + ], + "retryClass": "reconcile_first", + "schema": "hasna.provider_receipt.v1", + "unknownOutcome": false + } + ], + "verifiedSourceCandidates": [ + { + "branchRef": { + "id": "branch-release", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/branch-release" + }, + "commitSha": "0123456789abcdef0123456789abcdef01234567", + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "ae0668664ad166aec5e57a7990ce41b611cfa74f478a7e56a95a1a93f4bd70f0", + "evidenceRefs": [ + { + "id": "verified-source-evidence", + "kind": "test_result", + "sha256": "6a23b335f15d09227dd883fe55efdea5febf6fb1ad360ab9d0af5e5a209ea3ec", + "summary": "Bounded evidence for verified-source-evidence", + "uri": "artifact://deployment-fixture/verified-source-evidence" + } + ], + "id": "source-candidate-example-app", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "pullRequestRef": { + "id": "pull-request-42", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/pull-request-42" + }, + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "results": [ + { + "evidenceRefs": [ + { + "id": "source-integrity-result", + "kind": "test_result", + "sha256": "2d547e433715c3c6462aad9ea126032b600a244626cd38a8f2f65f829fd5e069", + "summary": "Bounded evidence for source-integrity-result", + "uri": "artifact://deployment-fixture/source-integrity-result" + } + ], + "id": "source-integrity", + "kind": "source_integrity", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "source-review-result", + "kind": "test_result", + "sha256": "5858811c63f859f6062e26d72d4969afa6a24e1278e8247d832186a1bd6e9263", + "summary": "Bounded evidence for source-review-result", + "uri": "artifact://deployment-fixture/source-review-result" + } + ], + "id": "independent-review", + "kind": "review", + "status": "passed" + } + ], + "schema": "hasna.verified_source_candidate.v1", + "status": "verified", + "treeSha": "89abcdef0123456789abcdef0123456789abcdef", + "validationPlan": { + "checks": [ + { + "expected": "Immutable evidence reviewed", + "id": "evidence-review", + "kind": "manual", + "required": true, + "resourceRefs": [] + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "id": "validation-source", + "objective": "Verify immutable deployment inputs and observable outcomes", + "requiredEvidenceKinds": [ + "test_result" + ], + "schema": "hasna.validation_plan.v1", + "verifier": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + }, + "verificationRun": { + "actor": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "constraints": [ + "credential-zero execution" + ], + "costEstimates": [], + "createdAt": "2026-08-09T09:00:00.000Z", + "decisions": [], + "evidenceRefs": [ + { + "id": "verification-run-evidence", + "kind": "test_result", + "sha256": "8f1d2268bd8998f5c15af7b1de37de301238114e3f69d85de0f7f712ddcdeb25", + "summary": "Bounded evidence for verification-run-evidence", + "uri": "artifact://deployment-fixture/verification-run-evidence" + } + ], + "finishedAt": "2026-08-09T09:05:00.000Z", + "id": "verification-run", + "objective": "Produce verified deployment evidence", + "proofBundleRefs": [], + "resourceRefs": [], + "schema": "hasna.work_run.v1", + "startedAt": "2026-08-09T09:00:00.000Z", + "status": "succeeded", + "validationPlanRefs": [] + }, + "verifiedAt": "2026-08-09T09:10:00.000Z", + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] + } + ] + }, + "schema": "hasna.deployment.fixture_bundle.v1" +} diff --git a/generated/deployment/v1/fixtures/artifact-attestation.valid.json b/generated/deployment/v1/fixtures/artifact-attestation.valid.json new file mode 100644 index 0000000..ec6e474 --- /dev/null +++ b/generated/deployment/v1/fixtures/artifact-attestation.valid.json @@ -0,0 +1,51 @@ +{ + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "artifactDigest": "9f57aeb5d9ea4e151380cfb3889d40b5cdac9747dd85c89921237df22f7aa29b", + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "evidenceRefs": [ + { + "id": "attestation-policy-result", + "kind": "test_result", + "sha256": "3a1bef67d71fd247cb5deca3e72af7972c2079b44262110743d92bd04b2700dd", + "summary": "Bounded evidence for attestation-policy-result", + "uri": "artifact://deployment-fixture/attestation-policy-result" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "attestation-example-app", + "issuer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "keyRef": { + "id": "signing-key-reference", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/signing-key-reference" + }, + "policyResult": "passed", + "policyRevision": 3, + "predicateKind": "slsa-provenance", + "predicateSchemaVersion": "v1.0", + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "schema": "hasna.artifact_attestation.v1", + "signatureRef": { + "id": "attestation-signature", + "kind": "artifact", + "sha256": "588d4b8435249c69b44b89619956817e6928293a1d75d0db7408c8476805712f", + "summary": "Bounded evidence for attestation-signature", + "uri": "artifact://deployment-fixture/attestation-signature" + } +} diff --git a/generated/deployment/v1/fixtures/build-artifact.valid.json b/generated/deployment/v1/fixtures/build-artifact.valid.json new file mode 100644 index 0000000..916490b --- /dev/null +++ b/generated/deployment/v1/fixtures/build-artifact.valid.json @@ -0,0 +1,103 @@ +{ + "artifactDigest": "9f57aeb5d9ea4e151380cfb3889d40b5cdac9747dd85c89921237df22f7aa29b", + "buildRun": { + "actor": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "constraints": [ + "credential-zero execution" + ], + "costEstimates": [], + "createdAt": "2026-08-09T09:00:00.000Z", + "decisions": [], + "evidenceRefs": [ + { + "id": "build-run-evidence", + "kind": "test_result", + "sha256": "cee6797059a4b2d4bdd5a78ec5ea58ac3760f50b720efdabfe95f3ff7b60b8e5", + "summary": "Bounded evidence for build-run-evidence", + "uri": "artifact://deployment-fixture/build-run-evidence" + } + ], + "finishedAt": "2026-08-09T09:05:00.000Z", + "id": "build-run", + "objective": "Produce verified deployment evidence", + "proofBundleRefs": [], + "resourceRefs": [], + "schema": "hasna.work_run.v1", + "startedAt": "2026-08-09T09:00:00.000Z", + "status": "succeeded", + "validationPlanRefs": [] + }, + "buildWorkflowRef": { + "id": "build-workflow", + "kind": "workflow", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/build-workflow" + }, + "builder": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "kind": "oci_image", + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "provenanceRefs": [ + { + "id": "artifact-provenance", + "kind": "artifact", + "sha256": "03b81cbf545913af8d9f70c9a3643ec3ae0338d0c02854e73a6f16014d4532ec", + "summary": "Bounded evidence for artifact-provenance", + "uri": "artifact://deployment-fixture/artifact-provenance" + } + ], + "repositoryCommitSha": "0123456789abcdef0123456789abcdef01234567", + "repositoryTreeSha": "89abcdef0123456789abcdef0123456789abcdef", + "sbomRefs": [ + { + "id": "artifact-sbom", + "kind": "artifact", + "sha256": "b4f783391e4b7ab46fdb49d5808cd389e1340173eab6afb1a80528664f778ae4", + "summary": "Bounded evidence for artifact-sbom", + "uri": "artifact://deployment-fixture/artifact-sbom" + } + ], + "scanRefs": [ + { + "id": "artifact-scan", + "kind": "test_result", + "sha256": "b5932ac32cf213f10bbaea588f83e9e3dfb0978adce936d8a347f806d6429b73", + "summary": "Bounded evidence for artifact-scan", + "uri": "artifact://deployment-fixture/artifact-scan" + } + ], + "schema": "hasna.build_artifact.v1", + "signatureRefs": [ + { + "id": "artifact-signature", + "kind": "artifact", + "sha256": "75ecda7b490798542b3f6dbd5de7addd705bdefeacb678981545b6a8a916d759", + "summary": "Bounded evidence for artifact-signature", + "uri": "artifact://deployment-fixture/artifact-signature" + } + ], + "sourceCandidate": { + "digest": "ae0668664ad166aec5e57a7990ce41b611cfa74f478a7e56a95a1a93f4bd70f0", + "id": "source-candidate-example-app", + "schema": "hasna.verified_source_candidate.v1" + }, + "status": "active", + "uri": "artifact://deployment-fixture/example-app-image" +} diff --git a/generated/deployment/v1/fixtures/deployment-approval-decision.valid.json b/generated/deployment/v1/fixtures/deployment-approval-decision.valid.json new file mode 100644 index 0000000..26370c4 --- /dev/null +++ b/generated/deployment/v1/fixtures/deployment-approval-decision.valid.json @@ -0,0 +1,88 @@ +{ + "actionId": null, + "actorRole": "approver", + "attemptScope": { + "maximum": 2, + "minimum": 1 + }, + "authorizationPolicyRevision": 4, + "boundInputDigests": [ + { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "kind": "request" + }, + { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "kind": "plan" + }, + { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "kind": "intent" + } + ], + "createdAt": "2026-08-09T09:10:00.000Z", + "decision": { + "actor": { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "decisionType": "approval", + "evidenceRefs": [ + { + "id": "approval-envelope-evidence", + "kind": "report", + "sha256": "69f3bf4095c3714596d75471fd55a0660b985bbe757d9f8ad682c0db5c89b1d3", + "summary": "Bounded evidence for approval-envelope-evidence", + "uri": "artifact://deployment-fixture/approval-envelope-evidence" + } + ], + "id": "approval-envelope-example-app", + "obligations": [ + "retain immutable receipts", + "verify live outcome" + ], + "reason": "Approved after policy and evidence review", + "redactions": [], + "schema": "hasna.decision_envelope.v1", + "selected": [], + "skipped": [], + "status": "allowed" + }, + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-approval-evidence", + "kind": "report", + "sha256": "e3548ec1c75b17714a582350203a9dc66142ef9433bcfe69f256b0ef23d75e0d", + "summary": "Bounded evidence for deployment-approval-evidence", + "uri": "artifact://deployment-fixture/deployment-approval-evidence" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-approval-example-app", + "issuedAt": "2026-08-09T09:10:00.000Z", + "phaseId": null, + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + }, + "runtimeMaterial": null, + "schema": "hasna.deployment_approval_decision.v1", + "scope": "plan", + "separationOfDutiesPassed": true, + "unchangedRetryPolicy": "allowed" +} diff --git a/generated/deployment/v1/fixtures/deployment-attempt.valid.json b/generated/deployment/v1/fixtures/deployment-attempt.valid.json new file mode 100644 index 0000000..328120a --- /dev/null +++ b/generated/deployment/v1/fixtures/deployment-attempt.valid.json @@ -0,0 +1,104 @@ +{ + "actionSteps": [ + { + "actionId": "apply-workload", + "evidenceRefs": [ + { + "id": "attempt-action-evidence", + "kind": "test_result", + "sha256": "4af04476abe762b8d7a3c55cbb03107ecd1ee3311716216c2731b728ec938eba", + "summary": "Bounded evidence for attempt-action-evidence", + "uri": "artifact://deployment-fixture/attempt-action-evidence" + } + ], + "finishedAt": "2026-08-09T09:18:00.000Z", + "providerCorrelationId": "provider-operation-example-app", + "sequence": 1, + "startedAt": "2026-08-09T09:11:00.000Z", + "state": "succeeded" + } + ], + "approvals": [ + { + "actionId": null, + "decision": { + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "id": "deployment-approval-example-app", + "schema": "hasna.deployment_approval_decision.v1" + }, + "phaseId": null, + "runtimeMaterialDigest": null, + "scope": "plan" + } + ], + "attemptNumber": 1, + "createdAt": "2026-08-09T09:10:00.000Z", + "decisionActors": [ + { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + } + ], + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "environmentLock": { + "fencingToken": 19, + "id": "environment-production-lock" + }, + "evidenceRefs": [ + { + "id": "attempt-evidence", + "kind": "report", + "sha256": "1bf89d5d5cfa2f47a382b6e1b2baf416291269eb2c8612692014b10db274c7d1", + "summary": "Bounded evidence for attempt-evidence", + "uri": "artifact://deployment-fixture/attempt-evidence" + } + ], + "executorActors": [ + { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + } + ], + "failureReason": null, + "finalReceipt": null, + "id": "deployment-attempt-example-app", + "inboxCorrelationRef": { + "id": "inbox-correlation", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/inbox-correlation" + }, + "outboxCorrelationRef": { + "id": "outbox-correlation", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/outbox-correlation" + }, + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + }, + "providerReceipts": [], + "requester": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "retryOf": null, + "revision": 1, + "schema": "hasna.deployment_attempt.v1", + "state": "succeeded", + "updatedAt": "2026-08-09T09:20:00.000Z" +} diff --git a/generated/deployment/v1/fixtures/deployment-plan.valid.json b/generated/deployment/v1/fixtures/deployment-plan.valid.json new file mode 100644 index 0000000..e59b481 --- /dev/null +++ b/generated/deployment/v1/fixtures/deployment-plan.valid.json @@ -0,0 +1,131 @@ +{ + "actions": [ + { + "approvalScope": "plan", + "compensationOperationId": "provider.rollback", + "dependsOn": [], + "evidenceRequirements": [ + "provider-receipt", + "health-check" + ], + "fencingRequired": true, + "id": "apply-workload", + "idempotencyRequired": true, + "inputs": [ + { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + } + ], + "lockClass": "environment-exclusive", + "maxAttempts": 2, + "operationId": "provider.deploy", + "operationVersion": 1, + "outputSchema": "hasna.provider_receipt.v1", + "postconditions": [ + "provider-observed", + "health-verified" + ], + "preconditions": [ + "immutable-inputs", + "approval-valid" + ], + "providerCapabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "providerOperation": "provider.deploy", + "reconciliationRequired": true, + "retryClass": "reconcile_first", + "riskClass": "high", + "runtimeMaterialKind": null, + "sideEffectClass": "compute_or_infra_mutation", + "timeoutClass": "deployment-standard" + } + ], + "authorizationRequirements": [ + "production-deployer" + ], + "compiler": { + "actor": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "contractKitVersion": "1.0.0", + "version": "1.0.0" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "estimatedCost": { + "amountMicros": 125000, + "basis": "estimated", + "createdAt": "2026-08-09T09:00:00.000Z", + "currency": "USD", + "id": "cost-deployment-fixture", + "provider": "fixture-provider", + "resourceRefs": [], + "schema": "hasna.cost_estimate.v1" + }, + "evidenceRequirements": [ + "provider-receipt", + "live-verification" + ], + "expectedStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-plan-example-app", + "inputs": [ + { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + } + ], + "issuedAt": "2026-08-09T09:10:00.000Z", + "kind": "deployment", + "policyRequirements": [ + "production-policy" + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "providerCapabilityDigests": [ + "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283" + ], + "request": { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "id": "deployment-request-example-app", + "schema": "hasna.deployment_request.v1" + }, + "riskClass": "high", + "rollbackInputs": [], + "schema": "hasna.deployment_plan.v1", + "verificationCriteria": [ + "health", + "readiness", + "version" + ] +} diff --git a/generated/deployment/v1/fixtures/deployment-receipt.valid.json b/generated/deployment/v1/fixtures/deployment-receipt.valid.json new file mode 100644 index 0000000..31efb78 --- /dev/null +++ b/generated/deployment/v1/fixtures/deployment-receipt.valid.json @@ -0,0 +1,148 @@ +{ + "approvals": [ + { + "digest": "41a0daa144612fdd8d0862c93f22ad0378951a8b25fe2212052bb6f3505f77cb", + "id": "deployment-approval-example-app", + "schema": "hasna.deployment_approval_decision.v1" + } + ], + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "attempt": { + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "id": "deployment-attempt-example-app", + "revision": 1, + "schema": "hasna.deployment_attempt.v1" + }, + "attestations": [ + { + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "id": "attestation-example-app", + "schema": "hasna.artifact_attestation.v1" + } + ], + "createdAt": "2026-08-09T09:20:00.000Z", + "desiredStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "digest": "5ac775c2791b494ee5f9753c9433a962747d122b255e3e70c6f90bb3657e51ec", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-receipt-evidence", + "kind": "report", + "sha256": "43000f198554ad25fae77c3183d3d94c05337ce86583c49496a2c9908753d191", + "summary": "Bounded evidence for deployment-receipt-evidence", + "uri": "artifact://deployment-fixture/deployment-receipt-evidence" + } + ], + "id": "deployment-receipt-example-app", + "infrastructurePlanRef": { + "id": "infrastructure-plan", + "kind": "artifact", + "sha256": "69729e2f9a9f80c6628533f90f5a7d2a2b74e4c679d5f951993d7e43779a4687", + "summary": "Bounded evidence for infrastructure-plan", + "uri": "artifact://deployment-fixture/infrastructure-plan" + }, + "infrastructureStateLineageRef": { + "id": "infrastructure-state-lineage", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/infrastructure-state-lineage" + }, + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "observedStateDigest": "2552b3bff4aa513c329bf2d5c0edd0d68714ed6c3c6adeaa358934f0e779f56c", + "outcome": "succeeded", + "plan": { + "digest": "ac1168d43503c1d1505c3271ceb4a92a9803af75ac37739c5e46ea540d036274", + "id": "deployment-plan-example-app", + "schema": "hasna.deployment_plan.v1" + }, + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "providerReceipts": [ + { + "digest": "d1bac8566b71d857174f3d12fd955618b60d8e41583a19779e6f769df5e27f2f", + "id": "provider-receipt-example-app", + "schema": "hasna.provider_receipt.v1" + } + ], + "request": { + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "id": "deployment-request-example-app", + "schema": "hasna.deployment_request.v1" + }, + "schema": "hasna.deployment_receipt.v1", + "verification": [ + { + "evidenceRefs": [ + { + "id": "health-evidence", + "kind": "test_result", + "sha256": "2c71b1cac3f7d547901e9770c7d83e53fd42c3a1d19aca13a5a6803c99b538c9", + "summary": "Bounded evidence for health-evidence", + "uri": "artifact://deployment-fixture/health-evidence" + } + ], + "id": "health", + "kind": "health", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "readiness-evidence", + "kind": "test_result", + "sha256": "72dcfffdba62e929fbbf8694685a95b63a13fd80fb8e0c76cbad3c99520212b1", + "summary": "Bounded evidence for readiness-evidence", + "uri": "artifact://deployment-fixture/readiness-evidence" + } + ], + "id": "readiness", + "kind": "readiness", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "version-evidence", + "kind": "test_result", + "sha256": "b167aee71fede4fff20a9877818c55560eea193018efbd52fd309e04acc70142", + "summary": "Bounded evidence for version-evidence", + "uri": "artifact://deployment-fixture/version-evidence" + } + ], + "id": "version", + "kind": "version", + "status": "passed" + } + ], + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] +} diff --git a/generated/deployment/v1/fixtures/deployment-request.valid.json b/generated/deployment/v1/fixtures/deployment-request.valid.json new file mode 100644 index 0000000..9c829db --- /dev/null +++ b/generated/deployment/v1/fixtures/deployment-request.valid.json @@ -0,0 +1,71 @@ +{ + "artifact": { + "digest": "4aab79eca4eca7079eb990dbb8c31f94b5ea784fb34d0dd7619f307136ea2fcb", + "id": "artifact-example-app", + "schema": "hasna.build_artifact.v1" + }, + "attestations": [ + { + "digest": "e8227f0a659ad3224a6f0c6c5d96e2fb41ea18000b14c09c060f33c1da45cd55", + "id": "attestation-example-app", + "schema": "hasna.artifact_attestation.v1" + } + ], + "auditCorrelationId": "audit-correlation-example-app", + "costEstimate": { + "amountMicros": 125000, + "basis": "estimated", + "createdAt": "2026-08-09T09:00:00.000Z", + "currency": "USD", + "id": "cost-deployment-fixture", + "provider": "fixture-provider", + "resourceRefs": [], + "schema": "hasna.cost_estimate.v1" + }, + "createdAt": "2026-08-09T09:10:00.000Z", + "digest": "083e9014634a6c88119a5d0e541cc404cf494a171584573851f78c92ba48f0aa", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "evidenceRefs": [ + { + "id": "deployment-request-evidence", + "kind": "report", + "sha256": "c49d9e0621a055a25676566c00cfcb0c62fa95ffb7d76dde3e3fde8ac38158ab", + "summary": "Bounded evidence for deployment-request-evidence", + "uri": "artifact://deployment-fixture/deployment-request-evidence" + } + ], + "expiresAt": "2026-08-10T09:00:00.000Z", + "id": "deployment-request-example-app", + "idempotencyKeyFingerprint": "e479de86d15e079ff8c219763d1e022f828eaa2444e68dbd7d9e4286acabed37", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "kind": "deployment", + "policyProfile": "production-policy", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "requestAt": "2026-08-09T09:10:00.000Z", + "requester": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "schema": "hasna.deployment_request.v1", + "sourceRequestId": "source-request-example-app" +} diff --git a/generated/deployment/v1/fixtures/environment-binding.valid.json b/generated/deployment/v1/fixtures/environment-binding.valid.json new file mode 100644 index 0000000..a3b5a42 --- /dev/null +++ b/generated/deployment/v1/fixtures/environment-binding.valid.json @@ -0,0 +1,134 @@ +{ + "authorizationProfile": "production-authorization", + "backupProfile": "daily-snapshot", + "changeEvidenceRefs": [ + { + "id": "environment-change-evidence", + "kind": "report", + "sha256": "b8b88001421f6a0d07ad16ca06326ee476bf409e362b67a17c2bcbb60809d38b", + "summary": "Bounded evidence for environment-change-evidence", + "uri": "artifact://deployment-fixture/environment-change-evidence" + } + ], + "commercialBindingRef": { + "id": "commercial-binding", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/commercial-binding" + }, + "createdAt": "2026-08-09T09:00:00.000Z", + "dataBackend": "postgresql", + "dataClassification": "private", + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "environment": { + "classification": "production", + "id": "production" + }, + "etag": "65b1cd6489c7c3ec86bee822ab666f6cb33efceaac938a75b53f94f21ef65909", + "id": "environment-production", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "policyProfile": "production-policy", + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "providerCapabilityCard": { + "adapterId": "fixture-adapter", + "appId": "example-app", + "auditEvents": [ + "deployment.requested", + "deployment.observed" + ], + "costPosture": "pre-authorized estimate required", + "credentialRequirements": [ + { + "allowedSecretInputs": [ + "credential_ref" + ], + "failClosedDiagnostic": "Provider credential reference is unavailable", + "refName": "deployment-credential-reference", + "requiredForModes": [ + "live_mutating" + ], + "revocationCheck": true + } + ], + "defaultMode": "sandbox", + "evidenceRefs": [ + { + "id": "provider-capability-evidence", + "kind": "report", + "sha256": "0ab44bc669befdb8ef57aacad9443cef9fffb1f0aa8bf0cf7006c682fad4f7f0", + "summary": "Bounded evidence for provider-capability-evidence", + "uri": "artifact://deployment-fixture/provider-capability-evidence" + } + ], + "modes": [ + "sandbox", + "live_mutating" + ], + "operations": [ + { + "noSideEffectSmoke": "provider.observe", + "operation": "provider.deploy", + "reconciliation": "provider.reconcile", + "requiresApproval": true, + "requiresIdempotencyKey": true, + "requiresRollbackOrRevocation": true, + "requiresSandboxEvidence": true, + "rollbackOrRevocation": "provider.rollback", + "sideEffectClass": "compute_or_infra_mutation", + "supportedModes": [ + "sandbox", + "live_mutating" + ] + } + ], + "ownerPackage": "@hasna/contracts", + "providerId": "fixture-provider", + "rateLimitPosture": "bounded", + "redactionRules": [ + "opaque references only" + ] + }, + "providerCapabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "providerConnectionRef": { + "id": "provider-connection", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/provider-connection" + }, + "providerIdentity": { + "accountId": "account-production", + "clusterId": "provider-cluster-production", + "networkId": "provider-network-production", + "projectId": "provider-project-example-app", + "region": "eu-central-1", + "routingId": "provider-routing-production", + "storageId": "provider-storage-production" + }, + "revision": 2, + "rollbackProfile": "prior-artifact", + "schema": "hasna.environment_binding.v1", + "updatedAt": "2026-08-09T09:05:00.000Z", + "writer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + } +} diff --git a/generated/deployment/v1/fixtures/intent-snapshot.valid.json b/generated/deployment/v1/fixtures/intent-snapshot.valid.json new file mode 100644 index 0000000..9c8fbd3 --- /dev/null +++ b/generated/deployment/v1/fixtures/intent-snapshot.valid.json @@ -0,0 +1,126 @@ +{ + "accessClass": "private-service", + "alarmClass": "service-slo", + "backupClass": "daily-snapshot", + "commitSha": "0123456789abcdef0123456789abcdef01234567", + "configurationRequirements": [ + { + "kind": "secret_reference", + "name": "APP_DATABASE_REF", + "referenceClass": "vault-reference", + "required": true + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "evidenceRefs": [ + { + "id": "intent-evidence", + "kind": "report", + "sha256": "f00eae14e40e96fd35f4747f41aa0bb36862620cd3426e8f76663a4e540a75cf", + "summary": "Bounded evidence for intent-evidence", + "uri": "artifact://deployment-fixture/intent-evidence" + } + ], + "id": "intent-example-app", + "intentDocument": { + "digest": "509bffa5170ea51bba03de7bc52e83c69563d4fd92e933037f8ac68089706a5c", + "path": "deploy/intent.json" + }, + "migration": { + "compatibility": "backward_compatible", + "order": "before_workload", + "rollbackClass": "restore-snapshot" + }, + "networkClass": "private-egress-fenced", + "processes": [ + { + "id": "web", + "liveness": { + "expectedStatuses": [ + 200 + ], + "path": "/health", + "protocol": "https" + }, + "ports": [ + 8080 + ], + "readiness": { + "expectedStatuses": [ + 200 + ], + "path": "/ready", + "protocol": "https" + }, + "resources": { + "cpuMillicores": 250, + "maxReplicas": 3, + "memoryMiB": 512, + "minReplicas": 1 + }, + "role": "web", + "version": { + "expectedStatuses": [ + 200 + ], + "path": "/version", + "protocol": "https" + } + } + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "restoreClass": "point-in-time", + "rollbackClass": "prior-artifact", + "schema": "hasna.intent_snapshot.v1", + "serviceRequirements": [ + { + "class": "postgresql", + "id": "primary-database", + "kind": "database", + "required": true + } + ], + "treeSha": "89abcdef0123456789abcdef0123456789abcdef", + "validationPlan": { + "checks": [ + { + "expected": "Immutable evidence reviewed", + "id": "evidence-review", + "kind": "manual", + "required": true, + "resourceRefs": [] + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "id": "validation-intent", + "objective": "Verify immutable deployment inputs and observable outcomes", + "requiredEvidenceKinds": [ + "test_result" + ], + "schema": "hasna.validation_plan.v1", + "verifier": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + } +} diff --git a/generated/deployment/v1/fixtures/launch-evidence.valid.json b/generated/deployment/v1/fixtures/launch-evidence.valid.json new file mode 100644 index 0000000..46425a1 --- /dev/null +++ b/generated/deployment/v1/fixtures/launch-evidence.valid.json @@ -0,0 +1,109 @@ +{ + "compiledAt": "2026-08-09T09:25:00.000Z", + "createdAt": "2026-08-09T09:25:00.000Z", + "deploymentReceipt": { + "digest": "5ac775c2791b494ee5f9753c9433a962747d122b255e3e70c6f90bb3657e51ec", + "id": "deployment-receipt-example-app", + "schema": "hasna.deployment_receipt.v1" + }, + "digest": "0a5f3b4b9ff46b9f01996845c0164f94099e6a2203c8800567927190254cfd98", + "environment": { + "digest": "9760cb4f172b160d2c3257a63e8ad94683a45c985ed62511a1a2c01740636278", + "id": "environment-production", + "revision": 2, + "schema": "hasna.environment_binding.v1" + }, + "expiresAt": "2026-08-10T09:00:00.000Z", + "findings": [ + { + "evidenceRefs": [ + { + "id": "launch-follow-up-evidence", + "kind": "report", + "sha256": "b0423bd973dc39dad4635fd501014890d054d806e490821ceb1147222d9827bd", + "summary": "Bounded evidence for launch-follow-up-evidence", + "uri": "artifact://deployment-fixture/launch-follow-up-evidence" + } + ], + "id": "documentation-follow-up", + "severity": "p3", + "status": "accepted" + } + ], + "id": "launch-evidence-example-app", + "independentReview": true, + "producer": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "product": { + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "id": "product-example-app", + "revision": 1, + "schema": "hasna.product_projection.v1" + }, + "proofBundleRefs": [ + { + "id": "launch-proof-bundle", + "kind": "proof_bundle", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/launch-proof-bundle" + } + ], + "requiredChecks": [ + { + "evidenceRefs": [ + { + "id": "health-evidence", + "kind": "test_result", + "sha256": "2c71b1cac3f7d547901e9770c7d83e53fd42c3a1d19aca13a5a6803c99b538c9", + "summary": "Bounded evidence for health-evidence", + "uri": "artifact://deployment-fixture/health-evidence" + } + ], + "id": "health", + "kind": "health", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "readiness-evidence", + "kind": "test_result", + "sha256": "72dcfffdba62e929fbbf8694685a95b63a13fd80fb8e0c76cbad3c99520212b1", + "summary": "Bounded evidence for readiness-evidence", + "uri": "artifact://deployment-fixture/readiness-evidence" + } + ], + "id": "readiness", + "kind": "readiness", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "version-evidence", + "kind": "test_result", + "sha256": "b167aee71fede4fff20a9877818c55560eea193018efbd52fd309e04acc70142", + "summary": "Bounded evidence for version-evidence", + "uri": "artifact://deployment-fixture/version-evidence" + } + ], + "id": "version", + "kind": "version", + "status": "passed" + } + ], + "schema": "hasna.launch_evidence.v1", + "status": "launched", + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] +} diff --git a/generated/deployment/v1/fixtures/product-projection.valid.json b/generated/deployment/v1/fixtures/product-projection.valid.json new file mode 100644 index 0000000..ec6bad8 --- /dev/null +++ b/generated/deployment/v1/fixtures/product-projection.valid.json @@ -0,0 +1,57 @@ +{ + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "53497f71c3fd58dac6c1d32b77c126de3d132ffeac28a4494abc1fae2f6e5556", + "displayName": "Example App", + "id": "product-example-app", + "lifecycle": "active", + "ownerRefs": [ + { + "id": "owner-approver", + "kind": "human", + "name": "Deployment Approver" + } + ], + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "projectedAt": "2026-08-09T09:00:00.000Z", + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "revision": 1, + "schema": "hasna.product_projection.v1", + "slug": "example-app", + "sourceEvidenceRefs": [ + { + "id": "product-projection-source", + "kind": "report", + "sha256": "ff6415fb8dc367fce3945c107dc3322c63adaa35265dea3b4fc8e3d4e323f772", + "summary": "Bounded evidence for product-projection-source", + "uri": "artifact://deployment-fixture/product-projection-source" + } + ], + "sourceProjectRef": { + "id": "project-contract-fixture", + "kind": "project", + "tags": [ + "deployment-fixture" + ], + "uri": "project://example-app" + }, + "sourceRevision": 7, + "workspaceRef": { + "id": "project-contract-fixture", + "kind": "project", + "tags": [ + "deployment-fixture" + ], + "uri": "project://example-app" + } +} diff --git a/generated/deployment/v1/fixtures/provider-receipt.valid.json b/generated/deployment/v1/fixtures/provider-receipt.valid.json new file mode 100644 index 0000000..5fdfe07 --- /dev/null +++ b/generated/deployment/v1/fixtures/provider-receipt.valid.json @@ -0,0 +1,66 @@ +{ + "adapter": "fixture-adapter", + "attempt": { + "digest": "c5b700016c1e1453be1c295e44ba6e92af39cc685942a510d35a9ef691a953a4", + "id": "deployment-attempt-example-app", + "revision": 1, + "schema": "hasna.deployment_attempt.v1" + }, + "capabilityDigest": "59b4a5db6aaa44ef1e38cdbc6ef31fc0690e178c066a68d249ce1bb23856e283", + "connectionRef": { + "id": "provider-connection", + "kind": "integration", + "tags": [ + "deployment-fixture" + ], + "uri": "integration://deployment-fixture/provider-connection" + }, + "createdAt": "2026-08-09T09:18:00.000Z", + "digest": "d1bac8566b71d857174f3d12fd955618b60d8e41583a19779e6f769df5e27f2f", + "id": "provider-receipt-example-app", + "normalizedResult": "succeeded", + "observationEvidenceRefs": [ + { + "id": "provider-observation-evidence", + "kind": "test_result", + "sha256": "415be35f669a860a71be2e6c80d391eaf62fe048c2bc51b04cd9827c4b11815d", + "summary": "Bounded evidence for provider-observation-evidence", + "uri": "artifact://deployment-fixture/provider-observation-evidence" + } + ], + "observedAt": "2026-08-09T09:19:00.000Z", + "observedProviderRevision": "provider-revision-19", + "operationId": "provider.deploy", + "operationVersion": 1, + "producer": { + "id": "deployment-executor", + "kind": "service", + "name": "Deployment Executor" + }, + "provider": "fixture-provider", + "providerIdentity": { + "deploymentId": "provider-deployment-example-app", + "eventId": "provider-event-example-app", + "operationId": "provider-operation-example-app", + "projectId": "provider-project-example-app", + "resourceIds": [ + "provider-service-example-app" + ] + }, + "providerStatus": "ready", + "reconciliationState": "confirmed", + "redaction": "full", + "requestFingerprint": "e479de86d15e079ff8c219763d1e022f828eaa2444e68dbd7d9e4286acabed37", + "responseEvidenceRefs": [ + { + "id": "provider-response-evidence", + "kind": "report", + "sha256": "9114b94c75d69425bc62fe93e08fdf2d7ca4cc5b4b911f11833214a256daafae", + "summary": "Bounded evidence for provider-response-evidence", + "uri": "artifact://deployment-fixture/provider-response-evidence" + } + ], + "retryClass": "reconcile_first", + "schema": "hasna.provider_receipt.v1", + "unknownOutcome": false +} diff --git a/generated/deployment/v1/fixtures/verified-source-candidate.valid.json b/generated/deployment/v1/fixtures/verified-source-candidate.valid.json new file mode 100644 index 0000000..385827a --- /dev/null +++ b/generated/deployment/v1/fixtures/verified-source-candidate.valid.json @@ -0,0 +1,144 @@ +{ + "branchRef": { + "id": "branch-release", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/branch-release" + }, + "commitSha": "0123456789abcdef0123456789abcdef01234567", + "createdAt": "2026-08-09T09:00:00.000Z", + "digest": "ae0668664ad166aec5e57a7990ce41b611cfa74f478a7e56a95a1a93f4bd70f0", + "evidenceRefs": [ + { + "id": "verified-source-evidence", + "kind": "test_result", + "sha256": "6a23b335f15d09227dd883fe55efdea5febf6fb1ad360ab9d0af5e5a209ea3ec", + "summary": "Bounded evidence for verified-source-evidence", + "uri": "artifact://deployment-fixture/verified-source-evidence" + } + ], + "id": "source-candidate-example-app", + "intent": { + "digest": "6bc75f992f681a5cf96083897b0bfffdd3bb9304b4ec32891c944ecb3af522b9", + "id": "intent-example-app", + "schema": "hasna.intent_snapshot.v1" + }, + "producer": { + "id": "agent-builder", + "kind": "agent", + "name": "Deployment Builder" + }, + "pullRequestRef": { + "id": "pull-request-42", + "kind": "artifact", + "tags": [ + "deployment-fixture" + ], + "uri": "artifact://deployment-fixture/pull-request-42" + }, + "repositoryRef": { + "id": "repo-contract-fixture", + "kind": "repo", + "tags": [ + "deployment-fixture" + ], + "uri": "repo://hasna/example-app" + }, + "results": [ + { + "evidenceRefs": [ + { + "id": "source-integrity-result", + "kind": "test_result", + "sha256": "2d547e433715c3c6462aad9ea126032b600a244626cd38a8f2f65f829fd5e069", + "summary": "Bounded evidence for source-integrity-result", + "uri": "artifact://deployment-fixture/source-integrity-result" + } + ], + "id": "source-integrity", + "kind": "source_integrity", + "status": "passed" + }, + { + "evidenceRefs": [ + { + "id": "source-review-result", + "kind": "test_result", + "sha256": "5858811c63f859f6062e26d72d4969afa6a24e1278e8247d832186a1bd6e9263", + "summary": "Bounded evidence for source-review-result", + "uri": "artifact://deployment-fixture/source-review-result" + } + ], + "id": "independent-review", + "kind": "review", + "status": "passed" + } + ], + "schema": "hasna.verified_source_candidate.v1", + "status": "verified", + "treeSha": "89abcdef0123456789abcdef0123456789abcdef", + "validationPlan": { + "checks": [ + { + "expected": "Immutable evidence reviewed", + "id": "evidence-review", + "kind": "manual", + "required": true, + "resourceRefs": [] + } + ], + "createdAt": "2026-08-09T09:00:00.000Z", + "id": "validation-source", + "objective": "Verify immutable deployment inputs and observable outcomes", + "requiredEvidenceKinds": [ + "test_result" + ], + "schema": "hasna.validation_plan.v1", + "verifier": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + }, + "verificationRun": { + "actor": { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + }, + "constraints": [ + "credential-zero execution" + ], + "costEstimates": [], + "createdAt": "2026-08-09T09:00:00.000Z", + "decisions": [], + "evidenceRefs": [ + { + "id": "verification-run-evidence", + "kind": "test_result", + "sha256": "8f1d2268bd8998f5c15af7b1de37de301238114e3f69d85de0f7f712ddcdeb25", + "summary": "Bounded evidence for verification-run-evidence", + "uri": "artifact://deployment-fixture/verification-run-evidence" + } + ], + "finishedAt": "2026-08-09T09:05:00.000Z", + "id": "verification-run", + "objective": "Produce verified deployment evidence", + "proofBundleRefs": [], + "resourceRefs": [], + "schema": "hasna.work_run.v1", + "startedAt": "2026-08-09T09:00:00.000Z", + "status": "succeeded", + "validationPlanRefs": [] + }, + "verifiedAt": "2026-08-09T09:10:00.000Z", + "verifiers": [ + { + "id": "agent-verifier", + "kind": "agent", + "name": "Independent Verifier" + } + ] +} diff --git a/generated/deployment/v1/schema-bundle.json b/generated/deployment/v1/schema-bundle.json new file mode 100644 index 0000000..f6593e4 --- /dev/null +++ b/generated/deployment/v1/schema-bundle.json @@ -0,0 +1,6600 @@ +{ + "contractVersion": "1.0.0", + "crossRecordValidationRequired": true, + "runtimeValidationRequired": true, + "schema": "hasna.deployment.schema_bundle.v1", + "schemaDigest": "57f6502c555b25fa459d6dd89b598688702ec02de743050c53f33457b0aba941", + "schemas": { + "hasna.artifact_attestation.v1": { + "$id": "hasna.artifact_attestation.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "artifact": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.build_artifact.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "artifactDigest": { + "$ref": "#/properties/digest" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "evidenceRefs": { + "items": { + "$ref": "#/properties/signatureRef" + }, + "minItems": 1, + "type": "array" + }, + "expiresAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "issuer": { + "$ref": "#/properties/producer" + }, + "keyRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/keyRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/keyRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "policyResult": { + "enum": [ + "passed", + "failed" + ], + "type": "string" + }, + "policyRevision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "predicateKind": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "predicateSchemaVersion": { + "pattern": "^v?[0-9]+(?:\\.[0-9]+){0,2}$", + "type": "string" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "schema": { + "const": "hasna.artifact_attestation.v1", + "type": "string" + }, + "signatureRef": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/keyRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "artifact", + "artifactDigest", + "predicateKind", + "predicateSchemaVersion", + "issuer", + "keyRef", + "signatureRef", + "policyResult", + "policyRevision", + "evidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.build_artifact.v1": { + "$id": "hasna.build_artifact.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "artifactDigest": { + "$ref": "#/properties/digest" + }, + "buildRun": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "constraints": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "costEstimates": { + "default": [], + "items": { + "$ref": "#/properties/buildRun/properties/decisions/items/properties/costEstimate" + }, + "type": "array" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "decisions": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "costEstimate": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "amountMicros": { + "minimum": 0, + "type": "integer" + }, + "basis": { + "default": "estimated", + "enum": [ + "actual", + "estimated", + "budget", + "limit" + ], + "type": "string" + }, + "completionTokens": { + "minimum": 0, + "type": "integer" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "currency": { + "default": "USD", + "pattern": "^[A-Z]{3}$", + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "$ref": "#/properties/buildRun/properties/metadata" + }, + "model": { + "minLength": 1, + "type": "string" + }, + "promptTokens": { + "minimum": 0, + "type": "integer" + }, + "provider": { + "minLength": 1, + "type": "string" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + }, + "schema": { + "const": "hasna.cost_estimate.v1", + "type": "string" + }, + "totalTokens": { + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "$ref": "#/properties/buildRun/properties/updatedAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "amountMicros" + ], + "type": "object" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "decisionType": { + "enum": [ + "guardrail", + "model_route", + "tool_select", + "budget", + "secret_access", + "approval", + "policy", + "other" + ], + "type": "string" + }, + "evidenceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "inputHash": { + "pattern": "^(sha256:)?[a-fA-F0-9]{64}$", + "type": "string" + }, + "metadata": { + "$ref": "#/properties/buildRun/properties/metadata" + }, + "obligations": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "policyBundleId": { + "minLength": 1, + "type": "string" + }, + "reason": { + "minLength": 1, + "type": "string" + }, + "redactions": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "schema": { + "const": "hasna.decision_envelope.v1", + "type": "string" + }, + "selected": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + }, + "skipped": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + }, + "status": { + "enum": [ + "allowed", + "denied", + "warned", + "approval_required", + "selected", + "skipped", + "unknown" + ], + "type": "string" + }, + "traceId": { + "minLength": 1, + "type": "string" + }, + "updatedAt": { + "$ref": "#/properties/buildRun/properties/updatedAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "decisionType", + "status", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "evidenceRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildRun/properties/decisions/items/properties/evidenceRefs/items" + }, + "type": "array" + }, + "finishedAt": { + "$ref": "#/properties/buildRun/properties/updatedAt" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "objective": { + "minLength": 1, + "type": "string" + }, + "proofBundleRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + }, + "schema": { + "const": "hasna.work_run.v1", + "type": "string" + }, + "startedAt": { + "$ref": "#/properties/buildRun/properties/updatedAt" + }, + "status": { + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled", + "blocked", + "skipped", + "unknown" + ], + "type": "string" + }, + "traceId": { + "minLength": 1, + "type": "string" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "validationPlanRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildWorkflowRef" + }, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "objective", + "status", + "actor" + ], + "type": "object" + }, + "buildWorkflowRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "$ref": "#/properties/uri" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "builder": { + "$ref": "#/properties/producer" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "kind": { + "enum": [ + "oci_image", + "archive", + "binary" + ], + "type": "string" + }, + "mediaType": { + "maxLength": 160, + "minLength": 1, + "type": "string" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "provenanceRefs": { + "$ref": "#/properties/sbomRefs" + }, + "repositoryCommitSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "repositoryTreeSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "sbomRefs": { + "default": [], + "items": { + "$ref": "#/properties/buildRun/properties/decisions/items/properties/evidenceRefs/items" + }, + "type": "array" + }, + "scanRefs": { + "$ref": "#/properties/sbomRefs" + }, + "schema": { + "const": "hasna.build_artifact.v1", + "type": "string" + }, + "signatureRefs": { + "$ref": "#/properties/sbomRefs" + }, + "sourceCandidate": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.verified_source_candidate.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "status": { + "enum": [ + "active", + "superseded", + "revoked" + ], + "type": "string" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "kind", + "mediaType", + "uri", + "artifactDigest", + "sourceCandidate", + "repositoryCommitSha", + "repositoryTreeSha", + "buildWorkflowRef", + "buildRun", + "builder", + "status" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.deployment_approval_decision.v1": { + "$id": "hasna.deployment_approval_decision.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "actionId": { + "anyOf": [ + { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "actorRole": { + "enum": [ + "requester", + "planner", + "approver", + "executor", + "auditor", + "administrator" + ], + "type": "string" + }, + "attemptScope": { + "additionalProperties": false, + "properties": { + "maximum": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "minimum": { + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "minimum", + "maximum" + ], + "type": "object" + }, + "authorizationPolicyRevision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "boundInputDigests": { + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "kind": { + "$ref": "#/properties/actionId/anyOf/0" + } + }, + "required": [ + "kind", + "digest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "decision": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "costEstimate": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "amountMicros": { + "minimum": 0, + "type": "integer" + }, + "basis": { + "default": "estimated", + "enum": [ + "actual", + "estimated", + "budget", + "limit" + ], + "type": "string" + }, + "completionTokens": { + "minimum": 0, + "type": "integer" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "currency": { + "default": "USD", + "pattern": "^[A-Z]{3}$", + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "$ref": "#/properties/decision/properties/metadata" + }, + "model": { + "minLength": 1, + "type": "string" + }, + "promptTokens": { + "minimum": 0, + "type": "integer" + }, + "provider": { + "minLength": 1, + "type": "string" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/decision/properties/selected/items" + }, + "type": "array" + }, + "schema": { + "const": "hasna.cost_estimate.v1", + "type": "string" + }, + "totalTokens": { + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "$ref": "#/properties/decision/properties/updatedAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "amountMicros" + ], + "type": "object" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "decisionType": { + "enum": [ + "guardrail", + "model_route", + "tool_select", + "budget", + "secret_access", + "approval", + "policy", + "other" + ], + "type": "string" + }, + "evidenceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/decision/properties/selected/items/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "inputHash": { + "pattern": "^(sha256:)?[a-fA-F0-9]{64}$", + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "obligations": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "policyBundleId": { + "minLength": 1, + "type": "string" + }, + "reason": { + "minLength": 1, + "type": "string" + }, + "redactions": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "schema": { + "const": "hasna.decision_envelope.v1", + "type": "string" + }, + "selected": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/decision/properties/selected/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/decision/properties/selected/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "skipped": { + "default": [], + "items": { + "$ref": "#/properties/decision/properties/selected/items" + }, + "type": "array" + }, + "status": { + "enum": [ + "allowed", + "denied", + "warned", + "approval_required", + "selected", + "skipped", + "unknown" + ], + "type": "string" + }, + "traceId": { + "minLength": 1, + "type": "string" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "schema", + "id", + "createdAt", + "decisionType", + "status", + "reason" + ], + "type": "object" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environment": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.environment_binding.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "evidenceRefs": { + "items": { + "$ref": "#/properties/decision/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "expiresAt": { + "$ref": "#/properties/createdAt" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "issuedAt": { + "$ref": "#/properties/createdAt" + }, + "phaseId": { + "anyOf": [ + { + "$ref": "#/properties/actionId/anyOf/0" + }, + { + "type": "null" + } + ] + }, + "plan": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_plan.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "runtimeMaterial": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "kind": { + "$ref": "#/properties/actionId/anyOf/0" + }, + "preActionStateSerial": { + "minimum": 0, + "type": "integer" + }, + "stateLineage": { + "$ref": "#/properties/id" + } + }, + "required": [ + "kind", + "digest", + "stateLineage", + "preActionStateSerial" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "schema": { + "const": "hasna.deployment_approval_decision.v1", + "type": "string" + }, + "scope": { + "enum": [ + "plan", + "action", + "phase" + ], + "type": "string" + }, + "separationOfDutiesPassed": { + "type": "boolean" + }, + "unchangedRetryPolicy": { + "enum": [ + "allowed", + "denied" + ], + "type": "string" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "decision", + "plan", + "scope", + "actionId", + "phaseId", + "runtimeMaterial", + "boundInputDigests", + "environment", + "actorRole", + "attemptScope", + "unchangedRetryPolicy", + "issuedAt", + "expiresAt", + "separationOfDutiesPassed", + "authorizationPolicyRevision", + "evidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.deployment_attempt.v1": { + "$id": "hasna.deployment_attempt.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "actionSteps": { + "items": { + "additionalProperties": false, + "properties": { + "actionId": { + "$ref": "#/properties/approvals/items/properties/actionId/anyOf/0" + }, + "evidenceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "finishedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "providerCorrelationId": { + "anyOf": [ + { + "$ref": "#/properties/id" + }, + { + "type": "null" + } + ] + }, + "sequence": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "startedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "state": { + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled", + "unknown_outcome" + ], + "type": "string" + } + }, + "required": [ + "sequence", + "actionId", + "state", + "providerCorrelationId", + "startedAt", + "finishedAt" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "approvals": { + "items": { + "additionalProperties": false, + "properties": { + "actionId": { + "anyOf": [ + { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "decision": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_approval_decision.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "phaseId": { + "anyOf": [ + { + "$ref": "#/properties/approvals/items/properties/actionId/anyOf/0" + }, + { + "type": "null" + } + ] + }, + "runtimeMaterialDigest": { + "anyOf": [ + { + "$ref": "#/properties/digest" + }, + { + "type": "null" + } + ] + }, + "scope": { + "enum": [ + "plan", + "action", + "phase" + ], + "type": "string" + } + }, + "required": [ + "decision", + "scope", + "actionId", + "phaseId", + "runtimeMaterialDigest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "attemptNumber": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "decisionActors": { + "items": { + "$ref": "#/properties/producer" + }, + "minItems": 1, + "type": "array" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environmentLock": { + "additionalProperties": false, + "properties": { + "fencingToken": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "id": { + "$ref": "#/properties/id" + } + }, + "required": [ + "id", + "fencingToken" + ], + "type": "object" + }, + "evidenceRefs": { + "$ref": "#/properties/actionSteps/items/properties/evidenceRefs" + }, + "executorActors": { + "$ref": "#/properties/decisionActors" + }, + "failureReason": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ] + }, + "finalReceipt": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "inboxCorrelationRef": { + "$ref": "#/properties/outboxCorrelationRef" + }, + "outboxCorrelationRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/actionSteps/items/properties/evidenceRefs/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/actionSteps/items/properties/evidenceRefs/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "$ref": "#/properties/actionSteps/items/properties/evidenceRefs/items/properties/uri" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "plan": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_plan.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "providerReceipts": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.provider_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "type": "array" + }, + "requester": { + "$ref": "#/properties/producer" + }, + "retryOf": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.deployment_attempt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.deployment_attempt.v1", + "type": "string" + }, + "state": { + "enum": [ + "queued", + "running", + "reconciling", + "unknown_outcome", + "succeeded", + "failed", + "cancelled" + ], + "type": "string" + }, + "updatedAt": { + "$ref": "#/properties/createdAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "updatedAt", + "revision", + "plan", + "approvals", + "requester", + "decisionActors", + "executorActors", + "environmentLock", + "attemptNumber", + "retryOf", + "state", + "actionSteps", + "outboxCorrelationRef", + "inboxCorrelationRef", + "failureReason", + "finalReceipt" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.deployment_plan.v1": { + "$id": "hasna.deployment_plan.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "additionalProperties": false, + "properties": { + "approvalScope": { + "enum": [ + "none", + "plan", + "action", + "phase" + ], + "type": "string" + }, + "compensationOperationId": { + "anyOf": [ + { + "$ref": "#/properties/actions/items/properties/operationId" + }, + { + "type": "null" + } + ] + }, + "dependsOn": { + "default": [], + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "type": "array" + }, + "evidenceRequirements": { + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "minItems": 1, + "type": "array" + }, + "fencingRequired": { + "type": "boolean" + }, + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "idempotencyRequired": { + "type": "boolean" + }, + "inputs": { + "default": [], + "items": { + "$ref": "#/properties/inputs/items" + }, + "type": "array" + }, + "lockClass": { + "$ref": "#/properties/actions/items/properties/id" + }, + "maxAttempts": { + "exclusiveMinimum": 0, + "maximum": 20, + "type": "integer" + }, + "operationId": { + "pattern": "^[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)+$", + "type": "string" + }, + "operationVersion": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "outputSchema": { + "$ref": "#/properties/inputs/items/properties/schema" + }, + "postconditions": { + "default": [], + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "type": "array" + }, + "preconditions": { + "default": [], + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "type": "array" + }, + "providerCapabilityDigest": { + "anyOf": [ + { + "$ref": "#/properties/digest" + }, + { + "type": "null" + } + ] + }, + "providerOperation": { + "anyOf": [ + { + "$ref": "#/properties/actions/items/properties/operationId" + }, + { + "type": "null" + } + ] + }, + "reconciliationRequired": { + "type": "boolean" + }, + "retryClass": { + "enum": [ + "none", + "safe", + "reconcile_first" + ], + "type": "string" + }, + "riskClass": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "runtimeMaterialKind": { + "anyOf": [ + { + "$ref": "#/properties/actions/items/properties/id" + }, + { + "type": "null" + } + ] + }, + "sideEffectClass": { + "enum": [ + "none", + "read_only", + "external_notification", + "external_mutation", + "money_movement", + "dns_or_domain_change", + "bulk_message_or_call", + "legal_or_filing", + "compute_or_infra_mutation", + "irreversible" + ], + "type": "string" + }, + "timeoutClass": { + "$ref": "#/properties/actions/items/properties/id" + } + }, + "required": [ + "id", + "operationId", + "operationVersion", + "outputSchema", + "lockClass", + "fencingRequired", + "sideEffectClass", + "riskClass", + "approvalScope", + "runtimeMaterialKind", + "providerOperation", + "providerCapabilityDigest", + "retryClass", + "maxAttempts", + "timeoutClass", + "compensationOperationId", + "idempotencyRequired", + "reconciliationRequired", + "evidenceRequirements" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "authorizationRequirements": { + "default": [], + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "type": "array" + }, + "compiler": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "contractKitVersion": { + "const": "1.0.0", + "type": "string" + }, + "version": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "actor", + "version", + "contractKitVersion" + ], + "type": "object" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "estimatedCost": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "amountMicros": { + "minimum": 0, + "type": "integer" + }, + "basis": { + "default": "estimated", + "enum": [ + "actual", + "estimated", + "budget", + "limit" + ], + "type": "string" + }, + "completionTokens": { + "minimum": 0, + "type": "integer" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "currency": { + "default": "USD", + "pattern": "^[A-Z]{3}$", + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "model": { + "minLength": 1, + "type": "string" + }, + "promptTokens": { + "minimum": 0, + "type": "integer" + }, + "provider": { + "minLength": 1, + "type": "string" + }, + "resourceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/estimatedCost/properties/resourceRefs/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/estimatedCost/properties/resourceRefs/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "schema": { + "const": "hasna.cost_estimate.v1", + "type": "string" + }, + "totalTokens": { + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "schema", + "id", + "createdAt", + "amountMicros" + ], + "type": "object" + }, + "evidenceRequirements": { + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "minItems": 1, + "type": "array" + }, + "expectedStateDigest": { + "$ref": "#/properties/digest" + }, + "expiresAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "inputs": { + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "pattern": "^hasna\\.[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*\\.v[0-9]+$", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "issuedAt": { + "$ref": "#/properties/createdAt" + }, + "kind": { + "enum": [ + "deployment", + "promotion", + "rollback", + "reconciliation" + ], + "type": "string" + }, + "policyRequirements": { + "default": [], + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "type": "array" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "providerCapabilityDigests": { + "default": [], + "items": { + "$ref": "#/properties/digest" + }, + "type": "array" + }, + "request": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_request.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "riskClass": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "rollbackInputs": { + "default": [], + "items": { + "$ref": "#/properties/inputs/items" + }, + "type": "array" + }, + "rollbackTarget": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "schema": { + "const": "hasna.deployment_plan.v1", + "type": "string" + }, + "verificationCriteria": { + "items": { + "$ref": "#/properties/actions/items/properties/id" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "kind", + "request", + "compiler", + "inputs", + "actions", + "riskClass", + "evidenceRequirements", + "expectedStateDigest", + "verificationCriteria", + "issuedAt" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.deployment_receipt.v1": { + "$id": "hasna.deployment_receipt.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "approvals": { + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_approval_decision.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "artifact": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.build_artifact.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "attempt": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.deployment_attempt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "attestations": { + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.artifact_attestation.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "desiredStateDigest": { + "$ref": "#/properties/digest" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environment": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.environment_binding.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "evidenceRefs": { + "items": { + "$ref": "#/properties/verification/items/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "infrastructurePlanRef": { + "$ref": "#/properties/verification/items/properties/evidenceRefs/items" + }, + "infrastructureStateLineageRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/verification/items/properties/evidenceRefs/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/verification/items/properties/evidenceRefs/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "$ref": "#/properties/verification/items/properties/evidenceRefs/items/properties/uri" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "intent": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.intent_snapshot.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "observedStateDigest": { + "$ref": "#/properties/digest" + }, + "outcome": { + "enum": [ + "succeeded", + "failed", + "cancelled", + "unknown_outcome" + ], + "type": "string" + }, + "plan": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_plan.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "product": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "providerReceipts": { + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.provider_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "request": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_request.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "rollbackTarget": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + }, + "verification": { + "items": { + "additionalProperties": false, + "properties": { + "evidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "kind": { + "enum": [ + "health", + "readiness", + "version", + "migration", + "alarm", + "access", + "restore", + "rollback", + "security", + "contract" + ], + "type": "string" + }, + "status": { + "enum": [ + "passed", + "failed", + "missing", + "expired", + "blocked" + ], + "type": "string" + } + }, + "required": [ + "id", + "kind", + "status", + "evidenceRefs" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "verifiers": { + "items": { + "$ref": "#/properties/producer" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "request", + "plan", + "approvals", + "attempt", + "product", + "intent", + "artifact", + "attestations", + "environment", + "providerReceipts", + "desiredStateDigest", + "observedStateDigest", + "verification", + "verifiers", + "evidenceRefs", + "outcome" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.deployment_request.v1": { + "$id": "hasna.deployment_request.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "artifact": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.build_artifact.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "attestations": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.artifact_attestation.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "type": "array" + }, + "auditCorrelationId": { + "$ref": "#/properties/id" + }, + "costEstimate": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "amountMicros": { + "minimum": 0, + "type": "integer" + }, + "basis": { + "default": "estimated", + "enum": [ + "actual", + "estimated", + "budget", + "limit" + ], + "type": "string" + }, + "completionTokens": { + "minimum": 0, + "type": "integer" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "currency": { + "default": "USD", + "pattern": "^[A-Z]{3}$", + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "model": { + "minLength": 1, + "type": "string" + }, + "promptTokens": { + "minimum": 0, + "type": "integer" + }, + "provider": { + "minLength": 1, + "type": "string" + }, + "resourceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/costEstimate/properties/resourceRefs/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/costEstimate/properties/resourceRefs/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "schema": { + "const": "hasna.cost_estimate.v1", + "type": "string" + }, + "totalTokens": { + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "schema", + "id", + "createdAt", + "amountMicros" + ], + "type": "object" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environment": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.environment_binding.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "evidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/costEstimate/properties/resourceRefs/items/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "expiresAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "idempotencyKeyFingerprint": { + "$ref": "#/properties/digest" + }, + "intent": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.intent_snapshot.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "kind": { + "enum": [ + "deployment", + "promotion", + "rollback", + "reconciliation" + ], + "type": "string" + }, + "policyProfile": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "priorReceipt": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "product": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "requestAt": { + "$ref": "#/properties/createdAt" + }, + "requester": { + "$ref": "#/properties/producer" + }, + "schema": { + "const": "hasna.deployment_request.v1", + "type": "string" + }, + "sourceRequestId": { + "$ref": "#/properties/id" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "kind", + "requester", + "product", + "environment", + "intent", + "policyProfile", + "idempotencyKeyFingerprint", + "requestAt", + "sourceRequestId", + "auditCorrelationId", + "evidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.environment_binding.v1": { + "$id": "hasna.environment_binding.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "authorizationProfile": { + "$ref": "#/properties/environment/properties/id" + }, + "backupProfile": { + "$ref": "#/properties/environment/properties/id" + }, + "changeEvidenceRefs": { + "items": { + "$ref": "#/properties/providerCapabilityCard/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "commercialBindingRef": { + "$ref": "#/properties/providerConnectionRef" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "dataBackend": { + "enum": [ + "sqlite", + "postgresql" + ], + "type": "string" + }, + "dataClassification": { + "enum": [ + "public", + "internal", + "private", + "sensitive" + ], + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environment": { + "additionalProperties": false, + "properties": { + "classification": { + "enum": [ + "development", + "staging", + "production", + "disaster_recovery" + ], + "type": "string" + }, + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + } + }, + "required": [ + "id", + "classification" + ], + "type": "object" + }, + "etag": { + "$ref": "#/properties/digest" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "intent": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.intent_snapshot.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "policyProfile": { + "$ref": "#/properties/environment/properties/id" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "product": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "providerCapabilityCard": { + "additionalProperties": false, + "properties": { + "adapterId": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "appId": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "auditEvents": { + "default": [], + "items": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "type": "array" + }, + "costPosture": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "credentialRequirements": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "allowedSecretInputs": { + "default": [ + "credential_ref" + ], + "items": { + "enum": [ + "credential_ref", + "lease_ref" + ], + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "failClosedDiagnostic": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "refName": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "requiredForModes": { + "items": { + "$ref": "#/properties/providerCapabilityCard/properties/modes/items" + }, + "minItems": 1, + "type": "array" + }, + "revocationCheck": { + "default": true, + "type": "boolean" + } + }, + "required": [ + "refName", + "requiredForModes", + "failClosedDiagnostic" + ], + "type": "object" + }, + "type": "array" + }, + "defaultMode": { + "$ref": "#/properties/providerCapabilityCard/properties/modes/items" + }, + "evidenceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "modes": { + "items": { + "enum": [ + "mock", + "fixture", + "sandbox", + "read_only_live", + "live_mutating" + ], + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "operations": { + "items": { + "additionalProperties": false, + "properties": { + "noSideEffectSmoke": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "operation": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "reconciliation": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "requiresApproval": { + "default": false, + "type": "boolean" + }, + "requiresIdempotencyKey": { + "default": false, + "type": "boolean" + }, + "requiresRollbackOrRevocation": { + "default": false, + "type": "boolean" + }, + "requiresSandboxEvidence": { + "default": false, + "type": "boolean" + }, + "rollbackOrRevocation": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "sideEffectClass": { + "enum": [ + "none", + "read_only", + "external_notification", + "external_mutation", + "money_movement", + "dns_or_domain_change", + "bulk_message_or_call", + "legal_or_filing", + "compute_or_infra_mutation", + "irreversible" + ], + "type": "string" + }, + "supportedModes": { + "items": { + "$ref": "#/properties/providerCapabilityCard/properties/modes/items" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "operation", + "supportedModes", + "sideEffectClass" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "ownerPackage": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "providerId": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "rateLimitPosture": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "redactionRules": { + "default": [], + "items": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "type": "array" + } + }, + "required": [ + "providerId", + "appId", + "adapterId", + "ownerPackage", + "modes", + "defaultMode", + "operations", + "rateLimitPosture" + ], + "type": "object" + }, + "providerCapabilityDigest": { + "$ref": "#/properties/digest" + }, + "providerConnectionRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/providerConnectionRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "providerIdentity": { + "additionalProperties": false, + "properties": { + "accountId": { + "$ref": "#/properties/id" + }, + "clusterId": { + "$ref": "#/properties/id" + }, + "networkId": { + "$ref": "#/properties/id" + }, + "projectId": { + "$ref": "#/properties/id" + }, + "region": { + "$ref": "#/properties/environment/properties/id" + }, + "routingId": { + "$ref": "#/properties/id" + }, + "storageId": { + "$ref": "#/properties/id" + } + }, + "required": [ + "accountId", + "region" + ], + "type": "object" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "rollbackProfile": { + "$ref": "#/properties/environment/properties/id" + }, + "schema": { + "const": "hasna.environment_binding.v1", + "type": "string" + }, + "updatedAt": { + "$ref": "#/properties/createdAt" + }, + "writer": { + "$ref": "#/properties/producer" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "updatedAt", + "revision", + "etag", + "product", + "intent", + "environment", + "dataBackend", + "providerConnectionRef", + "providerCapabilityCard", + "providerCapabilityDigest", + "providerIdentity", + "policyProfile", + "authorizationProfile", + "dataClassification", + "backupProfile", + "rollbackProfile", + "writer", + "changeEvidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.intent_snapshot.v1": { + "$id": "hasna.intent_snapshot.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "accessClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "alarmClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "backupClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "commitSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "configurationRequirements": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "configuration", + "secret_reference" + ], + "type": "string" + }, + "name": { + "pattern": "^[A-Z][A-Z0-9_]*$", + "type": "string" + }, + "referenceClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "required": { + "type": "boolean" + } + }, + "required": [ + "name", + "kind", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "evidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "$ref": "#/properties/validationPlan/properties/requiredEvidenceKinds/items" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/repositoryRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "intentDocument": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "path": { + "$ref": "#/properties/repositoryRef/properties/uri" + } + }, + "required": [ + "path", + "digest" + ], + "type": "object" + }, + "migration": { + "additionalProperties": false, + "properties": { + "compatibility": { + "enum": [ + "none", + "backward_compatible", + "forward_compatible", + "breaking" + ], + "type": "string" + }, + "order": { + "enum": [ + "before_workload", + "after_workload", + "independent" + ], + "type": "string" + }, + "rollbackClass": { + "$ref": "#/properties/processes/items/properties/id" + } + }, + "required": [ + "compatibility", + "order", + "rollbackClass" + ], + "type": "object" + }, + "networkClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "processes": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "liveness": { + "additionalProperties": false, + "properties": { + "expectedStatuses": { + "items": { + "maximum": 599, + "minimum": 100, + "type": "integer" + }, + "minItems": 1, + "type": "array" + }, + "path": { + "pattern": "^\\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$", + "type": "string" + }, + "protocol": { + "enum": [ + "http", + "https" + ], + "type": "string" + } + }, + "required": [ + "path", + "protocol", + "expectedStatuses" + ], + "type": "object" + }, + "ports": { + "default": [], + "items": { + "maximum": 65535, + "minimum": 1, + "type": "integer" + }, + "type": "array" + }, + "readiness": { + "$ref": "#/properties/processes/items/properties/liveness" + }, + "resources": { + "additionalProperties": false, + "properties": { + "cpuMillicores": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "maxReplicas": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "memoryMiB": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "minReplicas": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cpuMillicores", + "memoryMiB", + "minReplicas", + "maxReplicas" + ], + "type": "object" + }, + "role": { + "enum": [ + "web", + "worker", + "cron", + "migration", + "scheduler" + ], + "type": "string" + }, + "version": { + "$ref": "#/properties/processes/items/properties/liveness" + } + }, + "required": [ + "id", + "role", + "resources" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "product": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "repositoryRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/repositoryRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/repositoryRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "restoreClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "rollbackClass": { + "$ref": "#/properties/processes/items/properties/id" + }, + "schema": { + "const": "hasna.intent_snapshot.v1", + "type": "string" + }, + "serviceRequirements": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "class": { + "$ref": "#/properties/processes/items/properties/id" + }, + "id": { + "$ref": "#/properties/processes/items/properties/id" + }, + "kind": { + "enum": [ + "database", + "object_storage", + "queue", + "cron", + "worker" + ], + "type": "string" + }, + "required": { + "type": "boolean" + } + }, + "required": [ + "id", + "kind", + "required", + "class" + ], + "type": "object" + }, + "type": "array" + }, + "treeSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "validationPlan": { + "additionalProperties": false, + "properties": { + "checks": { + "items": { + "additionalProperties": false, + "properties": { + "command": { + "minLength": 1, + "type": "string" + }, + "expected": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "command", + "test", + "typecheck", + "lint", + "eval", + "security", + "review", + "deploy", + "smoke", + "manual", + "other" + ], + "type": "string" + }, + "required": { + "default": true, + "type": "boolean" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "timeoutMs": { + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "objective": { + "minLength": 1, + "type": "string" + }, + "requiredEvidenceKinds": { + "default": [], + "items": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "type": "array" + }, + "schema": { + "const": "hasna.validation_plan.v1", + "type": "string" + }, + "subject": { + "$ref": "#/properties/repositoryRef" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "verifier": { + "$ref": "#/properties/producer" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "objective", + "checks" + ], + "type": "object" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "product", + "repositoryRef", + "commitSha", + "treeSha", + "intentDocument", + "processes", + "migration", + "accessClass", + "networkClass", + "backupClass", + "restoreClass", + "alarmClass", + "rollbackClass", + "validationPlan", + "evidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.launch_evidence.v1": { + "$id": "hasna.launch_evidence.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "compiledAt": { + "$ref": "#/properties/createdAt" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "deploymentReceipt": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.deployment_receipt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "environment": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.environment_binding.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "expiresAt": { + "$ref": "#/properties/createdAt" + }, + "findings": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "evidenceRefs": { + "items": { + "$ref": "#/properties/requiredChecks/items/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "$ref": "#/properties/requiredChecks/items/properties/id" + }, + "severity": { + "enum": [ + "p0", + "p1", + "p2", + "p3" + ], + "type": "string" + }, + "status": { + "enum": [ + "open", + "resolved", + "accepted" + ], + "type": "string" + } + }, + "required": [ + "id", + "severity", + "status", + "evidenceRefs" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "independentReview": { + "type": "boolean" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "product": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "proofBundleRefs": { + "items": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/requiredChecks/items/properties/evidenceRefs/items/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/requiredChecks/items/properties/evidenceRefs/items/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "$ref": "#/properties/requiredChecks/items/properties/evidenceRefs/items/properties/uri" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "requiredChecks": { + "items": { + "additionalProperties": false, + "properties": { + "evidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "kind": { + "enum": [ + "health", + "readiness", + "version", + "migration", + "alarm", + "access", + "restore", + "rollback", + "security", + "contract" + ], + "type": "string" + }, + "status": { + "enum": [ + "passed", + "failed", + "missing", + "expired", + "blocked" + ], + "type": "string" + } + }, + "required": [ + "id", + "kind", + "status", + "evidenceRefs" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "schema": { + "const": "hasna.launch_evidence.v1", + "type": "string" + }, + "status": { + "enum": [ + "candidate", + "blocked", + "ready", + "launched", + "rolled_back" + ], + "type": "string" + }, + "verifiers": { + "items": { + "$ref": "#/properties/producer" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "product", + "environment", + "deploymentReceipt", + "requiredChecks", + "proofBundleRefs", + "verifiers", + "independentReview", + "status", + "compiledAt", + "expiresAt" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.product_projection.v1": { + "$id": "hasna.product_projection.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "displayName": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "lifecycle": { + "enum": [ + "draft", + "active", + "paused", + "archived" + ], + "type": "string" + }, + "ownerRefs": { + "items": { + "$ref": "#/properties/producer" + }, + "minItems": 1, + "type": "array" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "projectedAt": { + "$ref": "#/properties/createdAt" + }, + "repositoryRef": { + "$ref": "#/properties/sourceProjectRef" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.product_projection.v1", + "type": "string" + }, + "slug": { + "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", + "type": "string" + }, + "sourceEvidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/sourceProjectRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "sourceProjectRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/sourceProjectRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/sourceProjectRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "sourceRevision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "workspaceRef": { + "$ref": "#/properties/sourceProjectRef" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "revision", + "sourceProjectRef", + "sourceRevision", + "slug", + "displayName", + "repositoryRef", + "workspaceRef", + "lifecycle", + "ownerRefs", + "projectedAt", + "sourceEvidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.provider_receipt.v1": { + "$id": "hasna.provider_receipt.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "adapter": { + "$ref": "#/properties/provider" + }, + "attempt": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "revision": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "schema": { + "const": "hasna.deployment_attempt.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "revision", + "digest" + ], + "type": "object" + }, + "capabilityDigest": { + "$ref": "#/properties/digest" + }, + "connectionRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/connectionRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/connectionRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "normalizedResult": { + "enum": [ + "accepted", + "succeeded", + "failed", + "cancelled", + "unknown" + ], + "type": "string" + }, + "observationEvidenceRefs": { + "default": [], + "items": { + "$ref": "#/properties/responseEvidenceRefs/items" + }, + "type": "array" + }, + "observedAt": { + "$ref": "#/properties/createdAt" + }, + "observedProviderRevision": { + "anyOf": [ + { + "$ref": "#/properties/id" + }, + { + "type": "null" + } + ] + }, + "operationId": { + "pattern": "^[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)+$", + "type": "string" + }, + "operationVersion": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "provider": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "providerIdentity": { + "additionalProperties": false, + "properties": { + "deploymentId": { + "anyOf": [ + { + "$ref": "#/properties/id" + }, + { + "type": "null" + } + ] + }, + "eventId": { + "anyOf": [ + { + "$ref": "#/properties/id" + }, + { + "type": "null" + } + ] + }, + "operationId": { + "$ref": "#/properties/id" + }, + "projectId": { + "anyOf": [ + { + "$ref": "#/properties/id" + }, + { + "type": "null" + } + ] + }, + "resourceIds": { + "default": [], + "items": { + "$ref": "#/properties/id" + }, + "type": "array" + } + }, + "required": [ + "projectId", + "operationId", + "deploymentId", + "eventId" + ], + "type": "object" + }, + "providerStatus": { + "$ref": "#/properties/provider" + }, + "reconciliationState": { + "enum": [ + "not_required", + "pending", + "confirmed", + "diverged" + ], + "type": "string" + }, + "redaction": { + "enum": [ + "none", + "partial", + "full" + ], + "type": "string" + }, + "requestFingerprint": { + "$ref": "#/properties/digest" + }, + "responseEvidenceRefs": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/connectionRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "retryClass": { + "enum": [ + "none", + "safe", + "reconcile_first" + ], + "type": "string" + }, + "schema": { + "const": "hasna.provider_receipt.v1", + "type": "string" + }, + "unknownOutcome": { + "type": "boolean" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "attempt", + "provider", + "adapter", + "connectionRef", + "capabilityDigest", + "operationId", + "operationVersion", + "providerIdentity", + "requestFingerprint", + "providerStatus", + "normalizedResult", + "observedProviderRevision", + "observedAt", + "retryClass", + "reconciliationState", + "unknownOutcome", + "redaction", + "responseEvidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + }, + "hasna.verified_source_candidate.v1": { + "$id": "hasna.verified_source_candidate.v1", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "branchRef": { + "$ref": "#/properties/repositoryRef" + }, + "commitSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "digest": { + "pattern": "^[a-fA-F0-9]{64}$", + "type": "string" + }, + "evidenceRefs": { + "items": { + "$ref": "#/properties/verificationRun/properties/decisions/items/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$", + "type": "string" + }, + "intent": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/properties/digest" + }, + "id": { + "$ref": "#/properties/id" + }, + "schema": { + "const": "hasna.intent_snapshot.v1", + "type": "string" + } + }, + "required": [ + "schema", + "id", + "digest" + ], + "type": "object" + }, + "producer": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "agent", + "human", + "service", + "model", + "workflow", + "system" + ], + "type": "string" + }, + "machineId": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "provider": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "pullRequestRef": { + "$ref": "#/properties/repositoryRef" + }, + "repositoryRef": { + "additionalProperties": false, + "properties": { + "externalId": { + "$ref": "#/properties/repositoryRef/properties/uri" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "task", + "project", + "repo", + "run", + "loop", + "workflow", + "action", + "event", + "integration", + "session", + "machine", + "model", + "tool", + "file", + "document", + "url", + "artifact", + "knowledge", + "email", + "conversation", + "dashboard", + "render", + "panel", + "report", + "commit", + "branch", + "pull_request", + "issue", + "comment", + "verification", + "finding", + "context_pack", + "proof_bundle", + "memento", + "eval", + "budget", + "cost", + "alert", + "incident", + "app", + "release", + "rollout", + "announcement", + "audience", + "feedback", + "unknown" + ], + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "sourcePackage": { + "$ref": "#/properties/repositoryRef/properties/uri" + }, + "tags": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "uri": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + "results": { + "items": { + "additionalProperties": false, + "properties": { + "evidenceRefs": { + "items": { + "$ref": "#/properties/verificationRun/properties/decisions/items/properties/evidenceRefs/items" + }, + "minItems": 1, + "type": "array" + }, + "id": { + "pattern": "^[a-z][a-z0-9._-]{0,127}$", + "type": "string" + }, + "kind": { + "enum": [ + "review", + "test", + "policy", + "source_integrity" + ], + "type": "string" + }, + "status": { + "enum": [ + "passed", + "failed", + "not_run" + ], + "type": "string" + } + }, + "required": [ + "id", + "kind", + "status", + "evidenceRefs" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "schema": { + "const": "hasna.verified_source_candidate.v1", + "type": "string" + }, + "status": { + "enum": [ + "candidate", + "verified", + "rejected", + "superseded" + ], + "type": "string" + }, + "treeSha": { + "pattern": "^[a-f0-9]{40}$", + "type": "string" + }, + "validationPlan": { + "additionalProperties": false, + "properties": { + "checks": { + "items": { + "additionalProperties": false, + "properties": { + "command": { + "minLength": 1, + "type": "string" + }, + "expected": { + "minLength": 1, + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "enum": [ + "command", + "test", + "typecheck", + "lint", + "eval", + "security", + "review", + "deploy", + "smoke", + "manual", + "other" + ], + "type": "string" + }, + "required": { + "default": true, + "type": "boolean" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "timeoutMs": { + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "objective": { + "minLength": 1, + "type": "string" + }, + "requiredEvidenceKinds": { + "default": [], + "items": { + "enum": [ + "file", + "command_output", + "screenshot", + "log", + "diff", + "report", + "artifact", + "url", + "video", + "har", + "test_result", + "metric", + "trace", + "other" + ], + "type": "string" + }, + "type": "array" + }, + "schema": { + "const": "hasna.validation_plan.v1", + "type": "string" + }, + "subject": { + "$ref": "#/properties/repositoryRef" + }, + "updatedAt": { + "anyOf": [ + { + "$ref": "#/properties/createdAt" + }, + { + "type": "null" + } + ] + }, + "verifier": { + "$ref": "#/properties/producer" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "objective", + "checks" + ], + "type": "object" + }, + "verificationRun": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "constraints": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "costEstimates": { + "default": [], + "items": { + "$ref": "#/properties/verificationRun/properties/decisions/items/properties/costEstimate" + }, + "type": "array" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "decisions": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "actor": { + "$ref": "#/properties/producer" + }, + "costEstimate": { + "additionalProperties": false, + "properties": { + "accountId": { + "minLength": 1, + "type": "string" + }, + "amountMicros": { + "minimum": 0, + "type": "integer" + }, + "basis": { + "default": "estimated", + "enum": [ + "actual", + "estimated", + "budget", + "limit" + ], + "type": "string" + }, + "completionTokens": { + "minimum": 0, + "type": "integer" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "currency": { + "default": "USD", + "pattern": "^[A-Z]{3}$", + "type": "string" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "$ref": "#/properties/validationPlan/properties/metadata" + }, + "model": { + "minLength": 1, + "type": "string" + }, + "promptTokens": { + "minimum": 0, + "type": "integer" + }, + "provider": { + "minLength": 1, + "type": "string" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "schema": { + "const": "hasna.cost_estimate.v1", + "type": "string" + }, + "totalTokens": { + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "$ref": "#/properties/validationPlan/properties/updatedAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "amountMicros" + ], + "type": "object" + }, + "createdAt": { + "$ref": "#/properties/createdAt" + }, + "decisionType": { + "enum": [ + "guardrail", + "model_route", + "tool_select", + "budget", + "secret_access", + "approval", + "policy", + "other" + ], + "type": "string" + }, + "evidenceRefs": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "kind": { + "$ref": "#/properties/validationPlan/properties/requiredEvidenceKinds/items" + }, + "sha256": { + "$ref": "#/properties/digest" + }, + "summary": { + "minLength": 1, + "type": "string" + }, + "uri": { + "$ref": "#/properties/repositoryRef/properties/uri" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "inputHash": { + "pattern": "^(sha256:)?[a-fA-F0-9]{64}$", + "type": "string" + }, + "metadata": { + "$ref": "#/properties/validationPlan/properties/metadata" + }, + "obligations": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "policyBundleId": { + "minLength": 1, + "type": "string" + }, + "reason": { + "minLength": 1, + "type": "string" + }, + "redactions": { + "default": [], + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "schema": { + "const": "hasna.decision_envelope.v1", + "type": "string" + }, + "selected": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "skipped": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "status": { + "enum": [ + "allowed", + "denied", + "warned", + "approval_required", + "selected", + "skipped", + "unknown" + ], + "type": "string" + }, + "traceId": { + "minLength": 1, + "type": "string" + }, + "updatedAt": { + "$ref": "#/properties/validationPlan/properties/updatedAt" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "decisionType", + "status", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "evidenceRefs": { + "default": [], + "items": { + "$ref": "#/properties/verificationRun/properties/decisions/items/properties/evidenceRefs/items" + }, + "type": "array" + }, + "finishedAt": { + "$ref": "#/properties/validationPlan/properties/updatedAt" + }, + "id": { + "minLength": 1, + "type": "string" + }, + "metadata": { + "$ref": "#/properties/validationPlan/properties/metadata" + }, + "objective": { + "minLength": 1, + "type": "string" + }, + "proofBundleRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "resourceRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + }, + "schema": { + "const": "hasna.work_run.v1", + "type": "string" + }, + "startedAt": { + "$ref": "#/properties/validationPlan/properties/updatedAt" + }, + "status": { + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled", + "blocked", + "skipped", + "unknown" + ], + "type": "string" + }, + "traceId": { + "minLength": 1, + "type": "string" + }, + "updatedAt": { + "$ref": "#/properties/validationPlan/properties/updatedAt" + }, + "validationPlanRefs": { + "default": [], + "items": { + "$ref": "#/properties/repositoryRef" + }, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "objective", + "status", + "actor" + ], + "type": "object" + }, + "verifiedAt": { + "$ref": "#/properties/createdAt" + }, + "verifiers": { + "items": { + "$ref": "#/properties/producer" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "schema", + "id", + "createdAt", + "producer", + "digest", + "status", + "repositoryRef", + "commitSha", + "treeSha", + "intent", + "validationPlan", + "verificationRun", + "results", + "verifiers", + "verifiedAt", + "evidenceRefs" + ], + "type": "object", + "x-hasna-cross-record-validation-required": true, + "x-hasna-runtime-validation-required": true + } + } +} diff --git a/hasna.contract.json b/hasna.contract.json index 6a0893d..fb63e05 100644 --- a/hasna.contract.json +++ b/hasna.contract.json @@ -4,7 +4,7 @@ "name": "contracts", "class": "library", "contractVersion": "v1", - "kitVersion": "0.10.2", + "kitVersion": "0.10.3", "description": "Shared schemas, validators, and conformance kit for Hasna open-source agent infrastructure. Ships types and CLI checks only; no store.", "bins": [ "contracts", diff --git a/package.json b/package.json index 34bb953..a694ccd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hasna/contracts", - "version": "0.10.2", + "version": "0.10.3", "description": "Shared schemas and validators for Hasna open-source agent infrastructure contracts.", "type": "module", "license": "Apache-2.0", @@ -29,6 +29,15 @@ "types": "./dist/schemas.d.ts", "import": "./dist/schemas.js" }, + "./deployment": { + "types": "./dist/deployment/index.d.ts", + "import": "./dist/deployment/index.js" + }, + "./deployment/artifacts": { + "types": "./dist/deployment-artifacts.d.ts", + "import": "./dist/deployment-artifacts.js" + }, + "./deployment/artifacts/*": "./generated/deployment/v1/*", "./validators": { "types": "./dist/validators.d.ts", "import": "./dist/validators.js" @@ -92,6 +101,7 @@ "examples", "templates/adopter", "generated/todos/v1", + "generated/deployment/v1", "CONTRACT.md", "docker-compose.yml", "hasna.contract.json", @@ -99,7 +109,7 @@ "LICENSE" ], "scripts": { - "build": "bun run todos:check && rm -rf dist && bun build src/index.ts src/schemas.ts src/validators.ts src/no-cloud.ts src/server-backend.ts src/service-contract.ts src/secure-local-store.ts src/conformance.ts src/artifact-scan.ts src/kit/generate.ts src/auth/index.ts src/sdk/generate.ts src/client/transport.ts src/client/storage.ts --root src --outdir dist --target bun && bun build src/todos/index.ts --root src --outdir dist --target bun --packages external && bun build src/cli/index.ts --outdir dist/cli --target bun && cp src/cli/contracts-cli.ts dist/cli/contracts-cli.js && cp src/hasna.contract.schema.json dist/hasna.contract.schema.json && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist", + "build": "bun run deployment:check && bun run todos:check && rm -rf dist && bun build src/index.ts src/schemas.ts src/validators.ts src/deployment.ts src/deployment/index.ts src/deployment-artifacts.ts src/no-cloud.ts src/server-backend.ts src/service-contract.ts src/secure-local-store.ts src/conformance.ts src/artifact-scan.ts src/kit/generate.ts src/auth/index.ts src/sdk/generate.ts src/client/transport.ts src/client/storage.ts --root src --outdir dist --target bun && bun build src/todos/index.ts --root src --outdir dist --target bun --packages external && bun build src/cli/index.ts --outdir dist/cli --target bun && cp src/cli/contracts-cli.ts dist/cli/contracts-cli.js && cp src/hasna.contract.schema.json dist/hasna.contract.schema.json && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist", "typecheck": "tsc --noEmit", "test": "bun test --timeout 120000", "lint": "tsc --noEmit", @@ -110,6 +120,8 @@ "pack:check": "bun pm pack --dry-run --ignore-scripts", "todos:generate": "bun scripts/generate-todos-contract.ts", "todos:check": "bun scripts/generate-todos-contract.ts --check", + "deployment:generate": "bun scripts/generate-deployment-contract.ts", + "deployment:check": "bun scripts/generate-deployment-contract.ts --check", "todos:hygiene": "bun scripts/check-todos-text-hygiene.ts", "dev:cli": "bun run src/cli/index.ts", "prepack": "bun run verify:release", @@ -129,7 +141,8 @@ }, "dependencies": { "commander": "^13.1.0", - "zod": "^3.25.76" + "zod": "^3.25.76", + "zod-to-json-schema": "^3.24.6" }, "devDependencies": { "@types/bun": "^1.2.4", diff --git a/scripts/generate-deployment-contract.ts b/scripts/generate-deployment-contract.ts new file mode 100644 index 0000000..9ccd3ca --- /dev/null +++ b/scripts/generate-deployment-contract.ts @@ -0,0 +1,86 @@ +import { + existsSync, + mkdirSync, + readdirSync, + readFileSync, + rmSync, + writeFileSync, +} from "node:fs"; +import { dirname, join, relative } from "node:path"; +import { + DEPLOYMENT_GENERATED_ARTIFACT_ROOT, +} from "../src/deployment"; +import { + renderDeploymentArtifacts, +} from "../src/deployment-artifacts"; + +const repositoryRoot = join(import.meta.dir, ".."); +const checkOnly = process.argv.includes("--check"); +const checkRootArgument = process.argv.find((argument) => + argument.startsWith("--check-root=")); +const outputRoot = checkRootArgument + ? checkRootArgument.slice("--check-root=".length) + : join(repositoryRoot, DEPLOYMENT_GENERATED_ARTIFACT_ROOT); + +if (checkRootArgument && !checkOnly) { + throw new Error("--check-root requires --check"); +} + +function listFiles(root: string): string[] { + if (!existsSync(root)) { + return []; + } + const files: string[] = []; + const walk = (directory: string) => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const path = join(directory, entry.name); + if (entry.isDirectory()) { + walk(path); + } else if (entry.isFile()) { + files.push(relative(root, path)); + } + } + }; + walk(root); + return files.sort((left, right) => left.localeCompare(right)); +} + +const rendered = renderDeploymentArtifacts(); +const expectedPaths = Object.keys(rendered) + .sort((left, right) => left.localeCompare(right)); + +if (checkOnly) { + const actualPaths = listFiles(outputRoot); + const drift = new Set(); + for (const path of new Set([...expectedPaths, ...actualPaths])) { + const expected = rendered[path]; + const absolutePath = join(outputRoot, path); + if (expected === undefined || !existsSync(absolutePath)) { + drift.add(path); + continue; + } + if (readFileSync(absolutePath, "utf8") !== expected) { + drift.add(path); + } + } + if (drift.size > 0) { + console.error( + `Deployment generated artifacts are stale: ${[...drift].sort().join(", ")}`, + ); + process.exitCode = 1; + } else { + console.log( + `Deployment generated artifacts are current (${expectedPaths.length} files).`, + ); + } +} else { + rmSync(outputRoot, { recursive: true, force: true }); + for (const [path, content] of Object.entries(rendered)) { + const absolutePath = join(outputRoot, path); + mkdirSync(dirname(absolutePath), { recursive: true }); + writeFileSync(absolutePath, content, "utf8"); + } + console.log( + `Wrote ${expectedPaths.length} deployment artifacts to ${DEPLOYMENT_GENERATED_ARTIFACT_ROOT}.`, + ); +} diff --git a/scripts/smoke-todos-pack.ts b/scripts/smoke-todos-pack.ts index eb48243..e8d76b0 100644 --- a/scripts/smoke-todos-pack.ts +++ b/scripts/smoke-todos-pack.ts @@ -101,6 +101,13 @@ try { "package/generated/todos/v1/invariant-registry.json", "package/generated/todos/v1/generator-provenance.json", "package/generated/todos/v1/checksums.json", + "package/dist/deployment/index.js", + "package/dist/deployment/index.d.ts", + "package/dist/deployment-artifacts.js", + "package/dist/deployment-artifacts.d.ts", + "package/generated/deployment/v1/schema-bundle.json", + "package/generated/deployment/v1/fixture-bundle.json", + "package/generated/deployment/v1/checksums.json", ]) { if (!entries.has(required)) { throw new Error(`packed archive is missing ${required}`); @@ -175,7 +182,7 @@ try { consumerRoot, repoRoot: root, archiveEntries: entries, - runtimeDependencies: ["commander", "zod"], + runtimeDependencies: ["commander", "zod", "zod-to-json-schema"], }); installedFromArchive = true; refusal = refuseUnavailableInstall(installOutput.trim()); @@ -192,8 +199,14 @@ try { const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")) as { exports?: Record; }; - if (!packageJson.exports?.["./todos"] || !packageJson.exports?.["./todos/artifacts/*"]) { - throw new Error("packed package is missing Todos export mappings"); + if ( + !packageJson.exports?.["./todos"] + || !packageJson.exports?.["./todos/artifacts/*"] + || !packageJson.exports?.["./deployment"] + || !packageJson.exports?.["./deployment/artifacts"] + || !packageJson.exports?.["./deployment/artifacts/*"] + ) { + throw new Error("packed package is missing Todos or deployment export mappings"); } const todosExportKeys = Object.keys(packageJson.exports) .filter((key) => key.startsWith("./todos")) @@ -209,11 +222,35 @@ try { join(consumerRoot, "smoke.mjs"), `import * as root from "@hasna/contracts"; import * as todos from "@hasna/contracts/todos"; +import * as deployment from "@hasna/contracts/deployment"; +import * as deploymentArtifacts from "@hasna/contracts/deployment/artifacts"; import contract from "@hasna/contracts/todos/artifacts/contract.json" with { type: "json" }; import invariants from "@hasna/contracts/todos/artifacts/invariant-registry.json" with { type: "json" }; +import deploymentSchemaBundle from "@hasna/contracts/deployment/artifacts/schema-bundle.json" with { type: "json" }; +import deploymentFixtureBundle from "@hasna/contracts/deployment/artifacts/fixture-bundle.json" with { type: "json" }; import { z } from "zod"; if ("TodosModeSchema" in root) throw new Error("Todos leaked through the package root"); +if (Object.keys(deployment.DeploymentSchemaRegistry).length !== 13) { + throw new Error("deployment subpath did not expose all registered schemas"); +} +if (deploymentSchemaBundle.runtimeValidationRequired !== true) { + throw new Error("deployment schema bundle lost the runtime-validation gate"); +} +if (Object.keys(deploymentSchemaBundle.schemas).length !== 13) { + throw new Error("deployment schema bundle is incomplete"); +} +if (deploymentFixtureBundle.fixtures.launchEvidence.length !== 1) { + throw new Error("deployment fixture bundle is incomplete"); +} +const renderedDeployment = deploymentArtifacts.renderDeploymentArtifacts(); +if (Object.keys(renderedDeployment).length !== 16) { + throw new Error("deployment artifact renderer is incomplete"); +} +const packedProduct = deploymentFixtureBundle.fixtures.productProjections[0]; +if (!deployment.ProductProjectionSchema.safeParse(packedProduct).success) { + throw new Error("packed deployment fixture did not parse through the public schema"); +} if (todos.TodosModeSchema.parse("local") !== "local") throw new Error("Todos subpath did not load"); if (todos.TodosModeSchema.safeParse("remote").success) throw new Error("Todos mode validation drifted"); if ("createTodosTransferBundleWithDigests" in todos) throw new Error("structural transfer builder leaked publicly"); diff --git a/src/deployment-artifacts.ts b/src/deployment-artifacts.ts new file mode 100644 index 0000000..c1f1c1f --- /dev/null +++ b/src/deployment-artifacts.ts @@ -0,0 +1,137 @@ +import { zodToJsonSchema } from "zod-to-json-schema"; +import { + DeploymentSchemaRegistry, +} from "./schemas"; +import { + createDeploymentFixtureSet, + deploymentFixtureSetToContractSet, + deploymentFixturesBySchemaId, +} from "./deployment-fixtures"; +import { + DEPLOYMENT_CONTRACT_VERSION, + DEPLOYMENT_SCHEMA_IDS, + canonicalizeDeploymentValue, + sha256DeploymentText, + sha256DeploymentValue, + stableDeploymentJson, + type DeploymentSchemaId, +} from "./deployment"; + +export const DEPLOYMENT_SCHEMA_BUNDLE_ID = + "hasna.deployment.schema_bundle.v1" as const; +export const DEPLOYMENT_FIXTURE_BUNDLE_ID = + "hasna.deployment.fixture_bundle.v1" as const; + +export interface DeploymentSchemaBundle { + schema: typeof DEPLOYMENT_SCHEMA_BUNDLE_ID; + contractVersion: typeof DEPLOYMENT_CONTRACT_VERSION; + schemaDigest: string; + runtimeValidationRequired: true; + crossRecordValidationRequired: true; + schemas: Readonly>>; +} + +export interface DeploymentFixtureBundle { + schema: typeof DEPLOYMENT_FIXTURE_BUNDLE_ID; + contractVersion: typeof DEPLOYMENT_CONTRACT_VERSION; + fixtureDigest: string; + fixtures: ReturnType; +} + +function prettyDeploymentJson(value: unknown): string { + return `${JSON.stringify(canonicalizeDeploymentValue(value), null, 2)}\n`; +} + +function fixtureName(schemaId: DeploymentSchemaId): string { + return schemaId + .replace(/^hasna\./, "") + .replace(/\.v[0-9]+$/, "") + .replaceAll("_", "-"); +} + +export function buildDeploymentJsonSchemas(): + Readonly>> { + const schemas = Object.fromEntries( + Object.entries(DeploymentSchemaRegistry) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([schemaId, schema]) => { + const jsonSchema = zodToJsonSchema(schema, { + target: "jsonSchema7", + $refStrategy: "root", + effectStrategy: "input", + }) as Record; + return [ + schemaId, + { + ...jsonSchema, + $id: schemaId, + "x-hasna-runtime-validation-required": true, + "x-hasna-cross-record-validation-required": true, + }, + ]; + }), + ) as unknown as Record>; + return Object.freeze(schemas); +} + +export function buildDeploymentSchemaBundle(): DeploymentSchemaBundle { + const schemas = buildDeploymentJsonSchemas(); + return { + schema: DEPLOYMENT_SCHEMA_BUNDLE_ID, + contractVersion: DEPLOYMENT_CONTRACT_VERSION, + schemaDigest: sha256DeploymentValue(schemas), + runtimeValidationRequired: true, + crossRecordValidationRequired: true, + schemas, + }; +} + +export function buildDeploymentFixtureBundle(): DeploymentFixtureBundle { + const fixtureSet = createDeploymentFixtureSet(); + const fixtures = deploymentFixtureSetToContractSet(fixtureSet); + return { + schema: DEPLOYMENT_FIXTURE_BUNDLE_ID, + contractVersion: DEPLOYMENT_CONTRACT_VERSION, + fixtureDigest: sha256DeploymentValue(fixtures), + fixtures, + }; +} + +export function renderDeploymentArtifacts(): Readonly> { + const fixtureSet = createDeploymentFixtureSet(); + const fixturesBySchemaId = deploymentFixturesBySchemaId(fixtureSet); + const schemaBundle = buildDeploymentSchemaBundle(); + const fixtureBundle = buildDeploymentFixtureBundle(); + const artifacts: Record = { + "schema-bundle.json": prettyDeploymentJson(schemaBundle), + "fixture-bundle.json": prettyDeploymentJson(fixtureBundle), + }; + + for (const schemaId of Object.values(DEPLOYMENT_SCHEMA_IDS)) { + artifacts[`fixtures/${fixtureName(schemaId)}.valid.json`] = + prettyDeploymentJson(fixturesBySchemaId[schemaId]); + } + + const checksums = Object.fromEntries( + Object.entries(artifacts) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([path, content]) => [path, sha256DeploymentText(content)]), + ); + artifacts["checksums.json"] = prettyDeploymentJson({ + schema: "hasna.deployment.artifact_checksums.v1", + contractVersion: DEPLOYMENT_CONTRACT_VERSION, + files: checksums, + manifestDigest: sha256DeploymentValue(checksums), + }); + + return Object.freeze( + Object.fromEntries( + Object.entries(artifacts) + .sort(([left], [right]) => left.localeCompare(right)), + ), + ); +} + +export function deploymentArtifactsDigest(): string { + return sha256DeploymentText(stableDeploymentJson(renderDeploymentArtifacts())); +} diff --git a/src/deployment-fixtures.ts b/src/deployment-fixtures.ts new file mode 100644 index 0000000..0b6cc2e --- /dev/null +++ b/src/deployment-fixtures.ts @@ -0,0 +1,817 @@ +import { + ArtifactAttestationSchema, + BuildArtifactSchema, + DeploymentApprovalDecisionSchema, + DeploymentAttemptSchema, + DeploymentPlanSchema, + DeploymentReceiptSchema, + DeploymentRequestSchema, + EnvironmentBindingSchema, + IntentSnapshotSchema, + LaunchEvidenceSchema, + ProductProjectionSchema, + ProviderReceiptSchema, + SCHEMA_IDS, + VerifiedSourceCandidateSchema, + type ArtifactAttestation, + type BuildArtifact, + type DeploymentApprovalDecision, + type DeploymentAttempt, + type DeploymentPlan, + type DeploymentReceipt, + type DeploymentRequest, + type EnvironmentBinding, + type IntentSnapshot, + type LaunchEvidence, + type ProductProjection, + type ProviderReceipt, + type VerifiedSourceCandidate, +} from "./schemas"; +import { + DEPLOYMENT_SCHEMA_IDS, + computeEnvironmentBindingEtag, + sha256DeploymentText, + sha256DeploymentValue, + withDeploymentRecordDigest, + type DeploymentContractSet, + type DeploymentSchemaId, +} from "./deployment"; + +const CREATED_AT = "2026-08-09T09:00:00.000Z"; +const UPDATED_AT = "2026-08-09T09:05:00.000Z"; +const VERIFIED_AT = "2026-08-09T09:10:00.000Z"; +const EXPIRES_AT = "2026-08-10T09:00:00.000Z"; +const COMMIT_SHA = "0123456789abcdef0123456789abcdef01234567"; +const TREE_SHA = "89abcdef0123456789abcdef0123456789abcdef"; + +const builder = { + kind: "agent" as const, + id: "agent-builder", + name: "Deployment Builder", +}; + +const approver = { + kind: "human" as const, + id: "owner-approver", + name: "Deployment Approver", +}; + +const verifier = { + kind: "agent" as const, + id: "agent-verifier", + name: "Independent Verifier", +}; + +const executor = { + kind: "service" as const, + id: "deployment-executor", + name: "Deployment Executor", +}; + +const repositoryRef = { + kind: "repo" as const, + id: "repo-contract-fixture", + uri: "repo://hasna/example-app", + tags: ["deployment-fixture"], +}; + +const workspaceRef = { + kind: "project" as const, + id: "project-contract-fixture", + uri: "project://example-app", + tags: ["deployment-fixture"], +}; + +const evidence = (id: string, kind: "test_result" | "artifact" | "report" = "test_result") => ({ + id, + kind, + uri: `artifact://deployment-fixture/${id}`, + sha256: sha256DeploymentText(id), + summary: `Bounded evidence for ${id}`, +}); + +const resource = ( + id: string, + kind: "workflow" | "integration" | "artifact" | "proof_bundle", + uri: string, +) => ({ + kind, + id, + uri, + tags: ["deployment-fixture"], +}); + +const validationPlan = (id: string) => ({ + schema: SCHEMA_IDS.validationPlan, + id, + createdAt: CREATED_AT, + objective: "Verify immutable deployment inputs and observable outcomes", + checks: [ + { + id: "evidence-review", + kind: "manual" as const, + required: true, + expected: "Immutable evidence reviewed", + resourceRefs: [], + }, + ], + verifier, + requiredEvidenceKinds: ["test_result" as const], +}); + +const workRun = (id: string, actor = builder) => ({ + schema: SCHEMA_IDS.workRun, + id, + createdAt: CREATED_AT, + objective: "Produce verified deployment evidence", + status: "succeeded" as const, + actor, + startedAt: CREATED_AT, + finishedAt: UPDATED_AT, + constraints: ["credential-zero execution"], + resourceRefs: [], + decisions: [], + costEstimates: [], + evidenceRefs: [evidence(`${id}-evidence`)], + validationPlanRefs: [], + proofBundleRefs: [], +}); + +const costEstimate = { + schema: SCHEMA_IDS.costEstimate, + id: "cost-deployment-fixture", + createdAt: CREATED_AT, + currency: "USD", + amountMicros: 125_000, + provider: "fixture-provider", + basis: "estimated" as const, + resourceRefs: [], +}; + +const providerCapabilityCard = { + providerId: "fixture-provider", + appId: "example-app", + adapterId: "fixture-adapter", + ownerPackage: "@hasna/contracts", + modes: ["sandbox", "live_mutating"] as const, + defaultMode: "sandbox" as const, + credentialRequirements: [ + { + refName: "deployment-credential-reference", + requiredForModes: ["live_mutating"] as const, + allowedSecretInputs: ["credential_ref"] as const, + failClosedDiagnostic: "Provider credential reference is unavailable", + revocationCheck: true, + }, + ], + operations: [ + { + operation: "provider.deploy", + supportedModes: ["sandbox", "live_mutating"] as const, + sideEffectClass: "compute_or_infra_mutation" as const, + requiresApproval: true, + requiresIdempotencyKey: true, + requiresSandboxEvidence: true, + requiresRollbackOrRevocation: true, + rollbackOrRevocation: "provider.rollback", + noSideEffectSmoke: "provider.observe", + reconciliation: "provider.reconcile", + }, + ], + rateLimitPosture: "bounded", + costPosture: "pre-authorized estimate required", + auditEvents: ["deployment.requested", "deployment.observed"], + redactionRules: ["opaque references only"], + evidenceRefs: [evidence("provider-capability-evidence", "report")], +}; + +function ref(record: T): { + schema: T["schema"]; + id: string; + digest: string; + revision?: number; +} { + return { + schema: record.schema, + id: record.id, + ...(record.revision === undefined ? {} : { revision: record.revision }), + digest: record.digest, + }; +} + +export interface DeploymentFixtureSet { + productProjection: ProductProjection; + intentSnapshot: IntentSnapshot; + verifiedSourceCandidate: VerifiedSourceCandidate; + buildArtifact: BuildArtifact; + artifactAttestation: ArtifactAttestation; + environmentBinding: EnvironmentBinding; + deploymentRequest: DeploymentRequest; + deploymentPlan: DeploymentPlan; + deploymentApprovalDecision: DeploymentApprovalDecision; + deploymentAttempt: DeploymentAttempt; + providerReceipt: ProviderReceipt; + deploymentReceipt: DeploymentReceipt; + launchEvidence: LaunchEvidence; +} + +export function createDeploymentFixtureSet(): DeploymentFixtureSet { + const productProjection = ProductProjectionSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.productProjection, + id: "product-example-app", + createdAt: CREATED_AT, + producer: builder, + revision: 1, + sourceProjectRef: workspaceRef, + sourceRevision: 7, + slug: "example-app", + displayName: "Example App", + repositoryRef, + workspaceRef, + lifecycle: "active", + ownerRefs: [approver], + projectedAt: CREATED_AT, + sourceEvidenceRefs: [evidence("product-projection-source", "report")], + })); + + const intentSnapshot = IntentSnapshotSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.intentSnapshot, + id: "intent-example-app", + createdAt: CREATED_AT, + producer: builder, + product: ref(productProjection), + repositoryRef, + commitSha: COMMIT_SHA, + treeSha: TREE_SHA, + intentDocument: { + path: "deploy/intent.json", + digest: sha256DeploymentText("intent-document"), + }, + processes: [ + { + id: "web", + role: "web", + ports: [8080], + liveness: { + path: "/health", + protocol: "https", + expectedStatuses: [200], + }, + readiness: { + path: "/ready", + protocol: "https", + expectedStatuses: [200], + }, + version: { + path: "/version", + protocol: "https", + expectedStatuses: [200], + }, + resources: { + cpuMillicores: 250, + memoryMiB: 512, + minReplicas: 1, + maxReplicas: 3, + }, + }, + ], + serviceRequirements: [ + { + id: "primary-database", + kind: "database", + required: true, + class: "postgresql", + }, + ], + migration: { + compatibility: "backward_compatible", + order: "before_workload", + rollbackClass: "restore-snapshot", + }, + accessClass: "private-service", + networkClass: "private-egress-fenced", + backupClass: "daily-snapshot", + restoreClass: "point-in-time", + alarmClass: "service-slo", + rollbackClass: "prior-artifact", + configurationRequirements: [ + { + name: "APP_DATABASE_REF", + kind: "secret_reference", + required: true, + referenceClass: "vault-reference", + }, + ], + validationPlan: validationPlan("validation-intent"), + evidenceRefs: [evidence("intent-evidence", "report")], + })); + + const verifiedSourceCandidate = VerifiedSourceCandidateSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate, + id: "source-candidate-example-app", + createdAt: CREATED_AT, + producer: builder, + status: "verified", + repositoryRef, + commitSha: COMMIT_SHA, + treeSha: TREE_SHA, + branchRef: resource( + "branch-release", + "artifact", + "artifact://deployment-fixture/branch-release", + ), + pullRequestRef: resource( + "pull-request-42", + "artifact", + "artifact://deployment-fixture/pull-request-42", + ), + intent: ref(intentSnapshot), + validationPlan: validationPlan("validation-source"), + verificationRun: workRun("verification-run", verifier), + results: [ + { + id: "source-integrity", + kind: "source_integrity", + status: "passed", + evidenceRefs: [evidence("source-integrity-result")], + }, + { + id: "independent-review", + kind: "review", + status: "passed", + evidenceRefs: [evidence("source-review-result")], + }, + ], + verifiers: [verifier], + verifiedAt: VERIFIED_AT, + evidenceRefs: [evidence("verified-source-evidence")], + }), + ); + + const artifactDigest = sha256DeploymentText("immutable-build-artifact"); + const buildArtifact = BuildArtifactSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.buildArtifact, + id: "artifact-example-app", + createdAt: VERIFIED_AT, + producer: builder, + kind: "oci_image", + mediaType: "application/vnd.oci.image.manifest.v1+json", + uri: "artifact://deployment-fixture/example-app-image", + artifactDigest, + sourceCandidate: ref(verifiedSourceCandidate), + repositoryCommitSha: COMMIT_SHA, + repositoryTreeSha: TREE_SHA, + buildWorkflowRef: resource( + "build-workflow", + "workflow", + "artifact://deployment-fixture/build-workflow", + ), + buildRun: workRun("build-run"), + builder, + sbomRefs: [evidence("artifact-sbom", "artifact")], + provenanceRefs: [evidence("artifact-provenance", "artifact")], + scanRefs: [evidence("artifact-scan")], + signatureRefs: [evidence("artifact-signature", "artifact")], + status: "active", + })); + + const artifactAttestation = ArtifactAttestationSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.artifactAttestation, + id: "attestation-example-app", + createdAt: VERIFIED_AT, + producer: verifier, + artifact: ref(buildArtifact), + artifactDigest, + predicateKind: "slsa-provenance", + predicateSchemaVersion: "v1.0", + issuer: verifier, + keyRef: resource( + "signing-key-reference", + "integration", + "integration://deployment-fixture/signing-key-reference", + ), + signatureRef: evidence("attestation-signature", "artifact"), + policyResult: "passed", + policyRevision: 3, + expiresAt: EXPIRES_AT, + evidenceRefs: [evidence("attestation-policy-result")], + }), + ); + + const providerCapabilityDigest = sha256DeploymentValue(providerCapabilityCard); + const environmentBinding = EnvironmentBindingSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.environmentBinding, + id: "environment-production", + createdAt: CREATED_AT, + updatedAt: UPDATED_AT, + producer: builder, + revision: 2, + etag: computeEnvironmentBindingEtag("environment-production", 2), + product: ref(productProjection), + intent: ref(intentSnapshot), + environment: { + id: "production", + classification: "production", + }, + dataBackend: "postgresql", + providerConnectionRef: resource( + "provider-connection", + "integration", + "integration://deployment-fixture/provider-connection", + ), + providerCapabilityCard, + providerCapabilityDigest, + providerIdentity: { + accountId: "account-production", + region: "eu-central-1", + projectId: "provider-project-example-app", + clusterId: "provider-cluster-production", + networkId: "provider-network-production", + storageId: "provider-storage-production", + routingId: "provider-routing-production", + }, + policyProfile: "production-policy", + authorizationProfile: "production-authorization", + dataClassification: "private", + backupProfile: "daily-snapshot", + rollbackProfile: "prior-artifact", + commercialBindingRef: resource( + "commercial-binding", + "integration", + "integration://deployment-fixture/commercial-binding", + ), + writer: builder, + changeEvidenceRefs: [evidence("environment-change-evidence", "report")], + }), + ); + + const deploymentRequest = DeploymentRequestSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.deploymentRequest, + id: "deployment-request-example-app", + createdAt: VERIFIED_AT, + producer: builder, + kind: "deployment", + requester: builder, + product: ref(productProjection), + environment: ref(environmentBinding), + intent: ref(intentSnapshot), + artifact: ref(buildArtifact), + attestations: [ref(artifactAttestation)], + policyProfile: "production-policy", + idempotencyKeyFingerprint: sha256DeploymentText("deployment-request-idempotency"), + requestAt: VERIFIED_AT, + expiresAt: EXPIRES_AT, + sourceRequestId: "source-request-example-app", + auditCorrelationId: "audit-correlation-example-app", + costEstimate, + evidenceRefs: [evidence("deployment-request-evidence", "report")], + }), + ); + + const desiredStateDigest = sha256DeploymentText("desired-production-state"); + const deploymentPlan = DeploymentPlanSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.deploymentPlan, + id: "deployment-plan-example-app", + createdAt: VERIFIED_AT, + producer: builder, + kind: "deployment", + request: ref(deploymentRequest), + compiler: { + actor: builder, + version: "1.0.0", + contractKitVersion: "1.0.0", + }, + inputs: [ + ref(productProjection), + ref(intentSnapshot), + ref(buildArtifact), + ref(environmentBinding), + ], + providerCapabilityDigests: [providerCapabilityDigest], + actions: [ + { + id: "apply-workload", + operationId: "provider.deploy", + operationVersion: 1, + dependsOn: [], + inputs: [ref(buildArtifact), ref(environmentBinding)], + outputSchema: DEPLOYMENT_SCHEMA_IDS.providerReceipt, + preconditions: ["immutable-inputs", "approval-valid"], + postconditions: ["provider-observed", "health-verified"], + lockClass: "environment-exclusive", + fencingRequired: true, + sideEffectClass: "compute_or_infra_mutation", + riskClass: "high", + approvalScope: "plan", + runtimeMaterialKind: null, + providerOperation: "provider.deploy", + providerCapabilityDigest, + retryClass: "reconcile_first", + maxAttempts: 2, + timeoutClass: "deployment-standard", + compensationOperationId: "provider.rollback", + idempotencyRequired: true, + reconciliationRequired: true, + evidenceRequirements: ["provider-receipt", "health-check"], + }, + ], + authorizationRequirements: ["production-deployer"], + policyRequirements: ["production-policy"], + riskClass: "high", + evidenceRequirements: ["provider-receipt", "live-verification"], + expectedStateDigest: desiredStateDigest, + verificationCriteria: ["health", "readiness", "version"], + rollbackInputs: [], + estimatedCost: costEstimate, + issuedAt: VERIFIED_AT, + expiresAt: EXPIRES_AT, + })); + + const approvalEnvelope = { + schema: SCHEMA_IDS.decisionEnvelope, + id: "approval-envelope-example-app", + createdAt: VERIFIED_AT, + decisionType: "approval" as const, + status: "allowed" as const, + actor: approver, + selected: [], + skipped: [], + reason: "Approved after policy and evidence review", + obligations: ["retain immutable receipts", "verify live outcome"], + redactions: [], + evidenceRefs: [evidence("approval-envelope-evidence", "report")], + }; + + const deploymentApprovalDecision = DeploymentApprovalDecisionSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision, + id: "deployment-approval-example-app", + createdAt: VERIFIED_AT, + producer: approver, + decision: approvalEnvelope, + plan: ref(deploymentPlan), + scope: "plan", + actionId: null, + phaseId: null, + runtimeMaterial: null, + boundInputDigests: [ + { kind: "request", digest: deploymentRequest.digest }, + { kind: "plan", digest: deploymentPlan.digest }, + { kind: "intent", digest: intentSnapshot.digest }, + ], + environment: ref(environmentBinding), + actorRole: "approver", + attemptScope: { + minimum: 1, + maximum: 2, + }, + unchangedRetryPolicy: "allowed", + issuedAt: VERIFIED_AT, + expiresAt: EXPIRES_AT, + separationOfDutiesPassed: true, + authorizationPolicyRevision: 4, + evidenceRefs: [evidence("deployment-approval-evidence", "report")], + }), + ); + + const deploymentAttempt = DeploymentAttemptSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.deploymentAttempt, + id: "deployment-attempt-example-app", + createdAt: VERIFIED_AT, + updatedAt: "2026-08-09T09:20:00.000Z", + producer: executor, + revision: 1, + plan: ref(deploymentPlan), + approvals: [ + { + decision: ref(deploymentApprovalDecision), + scope: "plan", + actionId: null, + phaseId: null, + runtimeMaterialDigest: null, + }, + ], + requester: builder, + decisionActors: [approver], + executorActors: [executor], + environmentLock: { + id: "environment-production-lock", + fencingToken: 19, + }, + attemptNumber: 1, + retryOf: null, + state: "succeeded", + actionSteps: [ + { + sequence: 1, + actionId: "apply-workload", + state: "succeeded", + providerCorrelationId: "provider-operation-example-app", + startedAt: "2026-08-09T09:11:00.000Z", + finishedAt: "2026-08-09T09:18:00.000Z", + evidenceRefs: [evidence("attempt-action-evidence")], + }, + ], + outboxCorrelationRef: resource( + "outbox-correlation", + "integration", + "integration://deployment-fixture/outbox-correlation", + ), + inboxCorrelationRef: resource( + "inbox-correlation", + "integration", + "integration://deployment-fixture/inbox-correlation", + ), + failureReason: null, + evidenceRefs: [evidence("attempt-evidence", "report")], + providerReceipts: [], + finalReceipt: null, + }), + ); + + const providerReceipt = ProviderReceiptSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.providerReceipt, + id: "provider-receipt-example-app", + createdAt: "2026-08-09T09:18:00.000Z", + producer: executor, + attempt: ref(deploymentAttempt), + provider: "fixture-provider", + adapter: "fixture-adapter", + connectionRef: resource( + "provider-connection", + "integration", + "integration://deployment-fixture/provider-connection", + ), + capabilityDigest: providerCapabilityDigest, + operationId: "provider.deploy", + operationVersion: 1, + providerIdentity: { + projectId: "provider-project-example-app", + operationId: "provider-operation-example-app", + deploymentId: "provider-deployment-example-app", + resourceIds: ["provider-service-example-app"], + eventId: "provider-event-example-app", + }, + requestFingerprint: deploymentRequest.idempotencyKeyFingerprint, + providerStatus: "ready", + normalizedResult: "succeeded", + observedProviderRevision: "provider-revision-19", + observedAt: "2026-08-09T09:19:00.000Z", + retryClass: "reconcile_first", + reconciliationState: "confirmed", + unknownOutcome: false, + redaction: "full", + responseEvidenceRefs: [evidence("provider-response-evidence", "report")], + observationEvidenceRefs: [evidence("provider-observation-evidence")], + })); + + const verification = [ + { + id: "health", + kind: "health" as const, + status: "passed" as const, + evidenceRefs: [evidence("health-evidence")], + }, + { + id: "readiness", + kind: "readiness" as const, + status: "passed" as const, + evidenceRefs: [evidence("readiness-evidence")], + }, + { + id: "version", + kind: "version" as const, + status: "passed" as const, + evidenceRefs: [evidence("version-evidence")], + }, + ]; + + const deploymentReceipt = DeploymentReceiptSchema.parse( + withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.deploymentReceipt, + id: "deployment-receipt-example-app", + createdAt: "2026-08-09T09:20:00.000Z", + producer: verifier, + request: ref(deploymentRequest), + plan: ref(deploymentPlan), + approvals: [ref(deploymentApprovalDecision)], + attempt: ref(deploymentAttempt), + product: ref(productProjection), + intent: ref(intentSnapshot), + artifact: ref(buildArtifact), + attestations: [ref(artifactAttestation)], + environment: ref(environmentBinding), + providerReceipts: [ref(providerReceipt)], + desiredStateDigest, + observedStateDigest: desiredStateDigest, + verification, + infrastructurePlanRef: evidence("infrastructure-plan", "artifact"), + infrastructureStateLineageRef: resource( + "infrastructure-state-lineage", + "artifact", + "artifact://deployment-fixture/infrastructure-state-lineage", + ), + verifiers: [verifier], + evidenceRefs: [evidence("deployment-receipt-evidence", "report")], + outcome: "succeeded", + }), + ); + + const launchEvidence = LaunchEvidenceSchema.parse(withDeploymentRecordDigest({ + schema: DEPLOYMENT_SCHEMA_IDS.launchEvidence, + id: "launch-evidence-example-app", + createdAt: "2026-08-09T09:25:00.000Z", + producer: verifier, + product: ref(productProjection), + environment: ref(environmentBinding), + deploymentReceipt: ref(deploymentReceipt), + requiredChecks: verification, + proofBundleRefs: [ + resource( + "launch-proof-bundle", + "proof_bundle", + "artifact://deployment-fixture/launch-proof-bundle", + ), + ], + findings: [ + { + id: "documentation-follow-up", + severity: "p3", + status: "accepted", + evidenceRefs: [evidence("launch-follow-up-evidence", "report")], + }, + ], + verifiers: [verifier], + independentReview: true, + status: "launched", + compiledAt: "2026-08-09T09:25:00.000Z", + expiresAt: EXPIRES_AT, + })); + + return { + productProjection, + intentSnapshot, + verifiedSourceCandidate, + buildArtifact, + artifactAttestation, + environmentBinding, + deploymentRequest, + deploymentPlan, + deploymentApprovalDecision, + deploymentAttempt, + providerReceipt, + deploymentReceipt, + launchEvidence, + }; +} + +export function deploymentFixtureSetToContractSet( + fixtures: DeploymentFixtureSet, +): DeploymentContractSet { + return { + productProjections: [fixtures.productProjection], + intentSnapshots: [fixtures.intentSnapshot], + verifiedSourceCandidates: [fixtures.verifiedSourceCandidate], + buildArtifacts: [fixtures.buildArtifact], + artifactAttestations: [fixtures.artifactAttestation], + environmentBindings: [fixtures.environmentBinding], + deploymentRequests: [fixtures.deploymentRequest], + deploymentPlans: [fixtures.deploymentPlan], + deploymentApprovalDecisions: [fixtures.deploymentApprovalDecision], + deploymentAttempts: [fixtures.deploymentAttempt], + providerReceipts: [fixtures.providerReceipt], + deploymentReceipts: [fixtures.deploymentReceipt], + launchEvidence: [fixtures.launchEvidence], + }; +} + +export function deploymentFixturesBySchemaId( + fixtures: DeploymentFixtureSet, +): Readonly> { + return Object.freeze({ + [DEPLOYMENT_SCHEMA_IDS.productProjection]: fixtures.productProjection, + [DEPLOYMENT_SCHEMA_IDS.intentSnapshot]: fixtures.intentSnapshot, + [DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate]: fixtures.verifiedSourceCandidate, + [DEPLOYMENT_SCHEMA_IDS.buildArtifact]: fixtures.buildArtifact, + [DEPLOYMENT_SCHEMA_IDS.artifactAttestation]: fixtures.artifactAttestation, + [DEPLOYMENT_SCHEMA_IDS.environmentBinding]: fixtures.environmentBinding, + [DEPLOYMENT_SCHEMA_IDS.deploymentRequest]: fixtures.deploymentRequest, + [DEPLOYMENT_SCHEMA_IDS.deploymentPlan]: fixtures.deploymentPlan, + [DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision]: + fixtures.deploymentApprovalDecision, + [DEPLOYMENT_SCHEMA_IDS.deploymentAttempt]: fixtures.deploymentAttempt, + [DEPLOYMENT_SCHEMA_IDS.providerReceipt]: fixtures.providerReceipt, + [DEPLOYMENT_SCHEMA_IDS.deploymentReceipt]: fixtures.deploymentReceipt, + [DEPLOYMENT_SCHEMA_IDS.launchEvidence]: fixtures.launchEvidence, + }); +} diff --git a/src/deployment.ts b/src/deployment.ts new file mode 100644 index 0000000..d6d4825 --- /dev/null +++ b/src/deployment.ts @@ -0,0 +1,1401 @@ +import type { + ActorPointer, + CostEstimate, + DecisionEnvelope, + EvidencePointer, + ProviderCapabilityCard, + ResourcePointer, + ValidationPlan, + WorkRun, +} from "./schemas"; +import { + canonicalizeTodosValue, + sha256TodosText, + sha256TodosValue, + stableTodosJson, +} from "./todos/common"; +import { z } from "zod"; + +export const DEPLOYMENT_CONTRACT_VERSION = "1.0.0" as const; + +export const DEPLOYMENT_SCHEMA_IDS = { + productProjection: "hasna.product_projection.v1", + intentSnapshot: "hasna.intent_snapshot.v1", + verifiedSourceCandidate: "hasna.verified_source_candidate.v1", + buildArtifact: "hasna.build_artifact.v1", + artifactAttestation: "hasna.artifact_attestation.v1", + environmentBinding: "hasna.environment_binding.v1", + deploymentRequest: "hasna.deployment_request.v1", + deploymentPlan: "hasna.deployment_plan.v1", + deploymentApprovalDecision: "hasna.deployment_approval_decision.v1", + deploymentAttempt: "hasna.deployment_attempt.v1", + providerReceipt: "hasna.provider_receipt.v1", + deploymentReceipt: "hasna.deployment_receipt.v1", + launchEvidence: "hasna.launch_evidence.v1", +} as const; + +export type DeploymentSchemaId = + (typeof DEPLOYMENT_SCHEMA_IDS)[keyof typeof DEPLOYMENT_SCHEMA_IDS]; + +export const DEPLOYMENT_GENERATED_ARTIFACT_ROOT = + "generated/deployment/v1" as const; + +const DEPLOYMENT_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/; +const DEPLOYMENT_NAME = /^[a-z][a-z0-9._-]{0,127}$/; +const OPERATION_ID = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/; +const ENVIRONMENT_KEY = /^[A-Z][A-Z0-9_]*$/; +const GIT_SHA = /^[a-f0-9]{40}$/; +const UUID = + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; +const SHA256 = /^[a-f0-9]{64}$/; + +const FORBIDDEN_FIELD = + /(?:^|_)(?:command|commands|script|scripts|shell|argv|environment_map|env_map|provider_request_body|raw_provider_state|terraform_state|callback_body|hook|hooks|secret_value|token_value|password|passphrase|private_key|database_url|credential_value)(?:$|_)/i; + +const SECRET_VALUE_PATTERNS = [ + /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/, + /\bBearer\s+[A-Za-z0-9._~+/-]{8,}\b/i, + /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/, + /\bgh[pousr]_[A-Za-z0-9]{20,}\b/, + /\bgithub_pat_[A-Za-z0-9_]{20,}\b/, + /\bsk-[A-Za-z0-9_-]{16,}\b/, + /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/, + /\bhasna_[a-z0-9_]+\.[A-Za-z0-9._-]{12,}\b/, + /^[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^@\s]+@/i, + /^(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis):\/\//i, + /\b(?:password|passphrase|api[_-]?key|access[_-]?key|token|secret)\s*[:=]\s*\S{8,}/i, + /(?:^|[^A-Za-z0-9_-])[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}(?:$|[^A-Za-z0-9_-])/, +] as const; + +const EXECUTABLE_VALUE_PATTERNS = [ + /^#!\//, + /^(?:ba|z|k|c|fi)?sh\s+-c\b/i, + /^(?:sudo|curl|wget|terraform|tofu|kubectl|helm|docker|podman|aws|gcloud|az|npm|bun|node|python|ruby|perl|make)\s+/i, + /(?:&&|\|\||\$\(|`[^`]+`|\$\{[^}]+\})/, +] as const; + +function addDeploymentSafetyIssues( + value: unknown, + ctx: z.RefinementCtx, + path: Array = [], +): void { + if (Array.isArray(value)) { + value.forEach((item, index) => + addDeploymentSafetyIssues(item, ctx, [...path, index])); + return; + } + if (value && typeof value === "object") { + for (const [key, child] of Object.entries(value as Record)) { + const normalized = key + .replace(/([a-z0-9])([A-Z])/g, "$1_$2") + .replace(/[^A-Za-z0-9]+/g, "_") + .toLowerCase(); + if (FORBIDDEN_FIELD.test(normalized)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment contracts cannot contain executable, raw provider, state, or secret-bearing fields", + path: [...path, key], + }); + } + addDeploymentSafetyIssues(child, ctx, [...path, key]); + } + return; + } + if (typeof value === "number" && !Number.isFinite(value)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment contract numbers must be finite", + path, + }); + return; + } + if (typeof value !== "string") return; + if (SECRET_VALUE_PATTERNS.some((pattern) => pattern.test(value))) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment contracts cannot contain secret or credential values", + path, + }); + } + if (EXECUTABLE_VALUE_PATTERNS.some((pattern) => pattern.test(value))) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment contracts cannot contain commands, scripts, or templated executable strings", + path, + }); + } +} + +function assertCanonicalDeploymentValue( + value: unknown, + path = "", +): void { + if (value === undefined) { + throw new TypeError(`Deployment canonical JSON rejects undefined at ${path}`); + } + if ( + typeof value === "bigint" + || typeof value === "function" + || typeof value === "symbol" + ) { + throw new TypeError(`Deployment canonical JSON rejects ${typeof value} at ${path}`); + } + if (typeof value === "number" && !Number.isFinite(value)) { + throw new TypeError(`Deployment canonical JSON rejects non-finite numbers at ${path}`); + } + if (Array.isArray(value)) { + value.forEach((item, index) => + assertCanonicalDeploymentValue(item, `${path}[${index}]`)); + return; + } + if (value && typeof value === "object") { + for (const [key, child] of Object.entries(value as Record)) { + assertCanonicalDeploymentValue(child, `${path}.${key}`); + } + } +} + +export function canonicalizeDeploymentValue(value: unknown): unknown { + assertCanonicalDeploymentValue(value); + return canonicalizeTodosValue(value); +} + +export function stableDeploymentJson(value: unknown): string { + assertCanonicalDeploymentValue(value); + return stableTodosJson(value); +} + +export function sha256DeploymentValue(value: unknown): string { + assertCanonicalDeploymentValue(value); + return sha256TodosValue(value); +} + +export function sha256DeploymentText(value: string): string { + return sha256TodosText(value); +} + +export function computeDeploymentRecordDigest( + value: Record, +): string { + const { digest: _digest, ...unsigned } = value; + return sha256DeploymentValue(unsigned); +} + +export function withDeploymentRecordDigest>( + value: T, +): T & { digest: string } { + const { digest: _digest, ...unsigned } = value; + return { + ...unsigned, + digest: sha256DeploymentValue(unsigned), + } as T & { digest: string }; +} + +export function computeEnvironmentBindingEtag( + id: string, + revision: number, +): string { + return sha256DeploymentText(`${id}\u0000${revision}`); +} + +function uniqueBy( + values: readonly T[], + key: (value: T) => string, + ctx: z.RefinementCtx, + path: Array, + label: string, +): void { + const seen = new Set(); + values.forEach((value, index) => { + const semanticId = key(value); + if (seen.has(semanticId)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `${label} must be unique`, + path: [...path, index], + }); + } + seen.add(semanticId); + }); +} + +function validateDeploymentRecord( + value: { digest: string } & Record, + ctx: z.RefinementCtx, +): void { + addDeploymentSafetyIssues(value, ctx); + let computedDigest: string; + try { + computedDigest = computeDeploymentRecordDigest(value); + } catch (error) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: error instanceof Error + ? error.message + : "Deployment record cannot be canonicalized", + path: [], + }); + return; + } + if (value.digest !== computedDigest) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment record digest does not match canonical content", + path: ["digest"], + }); + } +} + +function validateChronology( + first: string, + second: string | null | undefined, + ctx: z.RefinementCtx, + path: Array, +): void { + if (second && Date.parse(second) < Date.parse(first)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Timestamp must not precede the record start", + path, + }); + } +} + +function isSorted(values: readonly string[]): boolean { + return values.every( + (value, index) => index === 0 || values[index - 1]!.localeCompare(value) <= 0, + ); +} + +export interface DeploymentPrimitiveSchemas { + actorPointer: z.ZodType; + costEstimate: z.ZodType; + decisionEnvelope: z.ZodType; + evidencePointer: z.ZodType; + providerCapabilityCard: z.ZodType; + resourcePointer: z.ZodType; + validationPlan: z.ZodType; + workRun: z.ZodType; + schemaId: z.ZodType; + timestamp: z.ZodType; + uri: z.ZodType; + sha256Digest: z.ZodType; + relativeProjectPath: z.ZodType; + providerSideEffectClass: z.ZodType; +} + +export function createDeploymentSchemas(primitives: DeploymentPrimitiveSchemas) { + const DeploymentIdSchema = z.string().regex(DEPLOYMENT_ID); + const DeploymentNameSchema = z.string().regex(DEPLOYMENT_NAME); + const DeploymentOperationIdSchema = z.string().regex(OPERATION_ID); + const DeploymentTimestampSchema = primitives.timestamp; + const DeploymentDigestSchema = primitives.sha256Digest; + const DeploymentEvidenceArraySchema = + z.array(primitives.evidencePointer).default([]); + const DeploymentActorArraySchema = + z.array(primitives.actorPointer).min(1); + + const recordBase = (schema: TSchema) => ({ + schema: z.literal(schema), + id: DeploymentIdSchema, + createdAt: DeploymentTimestampSchema, + producer: primitives.actorPointer, + digest: DeploymentDigestSchema, + }); + + const refSchema = ( + schema: TSchema, + ) => z.object({ + schema: z.literal(schema), + id: DeploymentIdSchema, + digest: DeploymentDigestSchema, + }).strict(); + + const revisionedRefSchema = ( + schema: TSchema, + ) => z.object({ + schema: z.literal(schema), + id: DeploymentIdSchema, + revision: z.number().int().positive(), + digest: DeploymentDigestSchema, + }).strict(); + + const ProductProjectionRefSchema = revisionedRefSchema( + DEPLOYMENT_SCHEMA_IDS.productProjection, + ); + const IntentSnapshotRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.intentSnapshot, + ); + const VerifiedSourceCandidateRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate, + ); + const BuildArtifactRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.buildArtifact, + ); + const ArtifactAttestationRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.artifactAttestation, + ); + const EnvironmentBindingRefSchema = revisionedRefSchema( + DEPLOYMENT_SCHEMA_IDS.environmentBinding, + ); + const DeploymentRequestRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.deploymentRequest, + ); + const DeploymentPlanRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.deploymentPlan, + ); + const DeploymentApprovalDecisionRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision, + ); + const DeploymentAttemptRefSchema = revisionedRefSchema( + DEPLOYMENT_SCHEMA_IDS.deploymentAttempt, + ); + const ProviderReceiptRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.providerReceipt, + ); + const DeploymentReceiptRefSchema = refSchema( + DEPLOYMENT_SCHEMA_IDS.deploymentReceipt, + ); + + const ProductProjectionSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.productProjection), + revision: z.number().int().positive(), + sourceProjectRef: primitives.resourcePointer, + sourceRevision: z.number().int().positive(), + slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), + displayName: z.string().trim().min(1).max(200), + repositoryRef: primitives.resourcePointer, + workspaceRef: primitives.resourcePointer, + lifecycle: z.enum(["draft", "active", "paused", "archived"]), + ownerRefs: z.array(primitives.actorPointer).min(1), + projectedAt: DeploymentTimestampSchema, + sourceEvidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.ownerRefs, (actor) => `${actor.kind}:${actor.id}`, ctx, ["ownerRefs"], "Product owner identities"); + }); + + const EndpointRequirementSchema = z.object({ + path: z.string().regex(/^\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/), + protocol: z.enum(["http", "https"]), + expectedStatuses: z.array(z.number().int().min(100).max(599)).min(1), + }).strict().superRefine((value, ctx) => { + uniqueBy(value.expectedStatuses, String, ctx, ["expectedStatuses"], "Endpoint statuses"); + }); + + const RuntimeProcessSchema = z.object({ + id: DeploymentNameSchema, + role: z.enum(["web", "worker", "cron", "migration", "scheduler"]), + ports: z.array(z.number().int().min(1).max(65535)).default([]), + liveness: EndpointRequirementSchema.optional(), + readiness: EndpointRequirementSchema.optional(), + version: EndpointRequirementSchema.optional(), + resources: z.object({ + cpuMillicores: z.number().int().positive(), + memoryMiB: z.number().int().positive(), + minReplicas: z.number().int().nonnegative(), + maxReplicas: z.number().int().positive(), + }).strict(), + }).strict().superRefine((value, ctx) => { + uniqueBy(value.ports, String, ctx, ["ports"], "Process ports"); + if (value.resources.maxReplicas < value.resources.minReplicas) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "maxReplicas must be greater than or equal to minReplicas", + path: ["resources", "maxReplicas"], + }); + } + }); + + const ServiceRequirementSchema = z.object({ + id: DeploymentNameSchema, + kind: z.enum(["database", "object_storage", "queue", "cron", "worker"]), + required: z.boolean(), + class: DeploymentNameSchema, + }).strict(); + + const ConfigurationRequirementSchema = z.object({ + name: z.string().regex(ENVIRONMENT_KEY), + kind: z.enum(["configuration", "secret_reference"]), + required: z.boolean(), + referenceClass: DeploymentNameSchema.optional(), + }).strict().superRefine((value, ctx) => { + if (value.kind === "secret_reference" && !value.referenceClass) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Secret-reference requirements require an opaque reference class", + path: ["referenceClass"], + }); + } + }); + + const IntentSnapshotSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.intentSnapshot), + product: ProductProjectionRefSchema, + repositoryRef: primitives.resourcePointer, + commitSha: z.string().regex(GIT_SHA), + treeSha: z.string().regex(GIT_SHA), + intentDocument: z.object({ + path: primitives.relativeProjectPath, + digest: DeploymentDigestSchema, + }).strict(), + processes: z.array(RuntimeProcessSchema).min(1), + serviceRequirements: z.array(ServiceRequirementSchema).default([]), + migration: z.object({ + compatibility: z.enum(["none", "backward_compatible", "forward_compatible", "breaking"]), + order: z.enum(["before_workload", "after_workload", "independent"]), + rollbackClass: DeploymentNameSchema, + }).strict(), + accessClass: DeploymentNameSchema, + networkClass: DeploymentNameSchema, + backupClass: DeploymentNameSchema, + restoreClass: DeploymentNameSchema, + alarmClass: DeploymentNameSchema, + rollbackClass: DeploymentNameSchema, + configurationRequirements: z.array(ConfigurationRequirementSchema).default([]), + validationPlan: primitives.validationPlan, + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.processes, (process) => process.id, ctx, ["processes"], "Process ids"); + uniqueBy(value.serviceRequirements, (requirement) => requirement.id, ctx, ["serviceRequirements"], "Service requirement ids"); + uniqueBy(value.configurationRequirements, (requirement) => requirement.name, ctx, ["configurationRequirements"], "Configuration requirement names"); + }); + + const VerificationResultSchema = z.object({ + id: DeploymentNameSchema, + kind: z.enum(["review", "test", "policy", "source_integrity"]), + status: z.enum(["passed", "failed", "not_run"]), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict(); + + const VerifiedSourceCandidateSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate), + status: z.enum(["candidate", "verified", "rejected", "superseded"]), + repositoryRef: primitives.resourcePointer, + commitSha: z.string().regex(GIT_SHA), + treeSha: z.string().regex(GIT_SHA), + branchRef: primitives.resourcePointer.optional(), + pullRequestRef: primitives.resourcePointer.optional(), + intent: IntentSnapshotRefSchema, + validationPlan: primitives.validationPlan, + verificationRun: primitives.workRun, + results: z.array(VerificationResultSchema).min(1), + verifiers: DeploymentActorArraySchema, + verifiedAt: DeploymentTimestampSchema, + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.results, (result) => result.id, ctx, ["results"], "Verification result ids"); + uniqueBy(value.verifiers, (actor) => `${actor.kind}:${actor.id}`, ctx, ["verifiers"], "Verifier identities"); + if ( + value.status === "verified" + && value.results.some((result) => result.status !== "passed") + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Verified source candidates require every declared result to pass", + path: ["results"], + }); + } + }); + + const BuildArtifactSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.buildArtifact), + kind: z.enum(["oci_image", "archive", "binary"]), + mediaType: z.string().trim().min(1).max(160), + uri: primitives.uri, + artifactDigest: DeploymentDigestSchema, + sourceCandidate: VerifiedSourceCandidateRefSchema, + repositoryCommitSha: z.string().regex(GIT_SHA), + repositoryTreeSha: z.string().regex(GIT_SHA), + buildWorkflowRef: primitives.resourcePointer, + buildRun: primitives.workRun, + builder: primitives.actorPointer, + sbomRefs: DeploymentEvidenceArraySchema, + provenanceRefs: DeploymentEvidenceArraySchema, + scanRefs: DeploymentEvidenceArraySchema, + signatureRefs: DeploymentEvidenceArraySchema, + status: z.enum(["active", "superseded", "revoked"]), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + if (value.buildRun.status !== "succeeded") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Build artifacts require a succeeded build run", + path: ["buildRun", "status"], + }); + } + }); + + const ArtifactAttestationSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.artifactAttestation), + artifact: BuildArtifactRefSchema, + artifactDigest: DeploymentDigestSchema, + predicateKind: DeploymentNameSchema, + predicateSchemaVersion: z.string().regex(/^v?[0-9]+(?:\.[0-9]+){0,2}$/), + issuer: primitives.actorPointer, + keyRef: primitives.resourcePointer, + signatureRef: primitives.evidencePointer, + policyResult: z.enum(["passed", "failed"]), + policyRevision: z.number().int().positive(), + expiresAt: DeploymentTimestampSchema.nullable().optional(), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + validateChronology(value.createdAt, value.expiresAt, ctx, ["expiresAt"]); + }); + + const ProviderIdentitySchema = z.object({ + accountId: DeploymentIdSchema, + region: DeploymentNameSchema, + projectId: DeploymentIdSchema.optional(), + clusterId: DeploymentIdSchema.optional(), + networkId: DeploymentIdSchema.optional(), + storageId: DeploymentIdSchema.optional(), + routingId: DeploymentIdSchema.optional(), + }).strict().superRefine((value, ctx) => { + for (const [key, identity] of Object.entries(value)) { + if (identity && UUID.test(identity)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Provider identity must use provider-issued stable identifiers, not mutable local UUIDs", + path: [key], + }); + } + } + }); + + const EnvironmentBindingSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.environmentBinding), + updatedAt: DeploymentTimestampSchema, + revision: z.number().int().positive(), + etag: DeploymentDigestSchema, + product: ProductProjectionRefSchema, + intent: IntentSnapshotRefSchema, + environment: z.object({ + id: DeploymentNameSchema, + classification: z.enum(["development", "staging", "production", "disaster_recovery"]), + }).strict(), + dataBackend: z.enum(["sqlite", "postgresql"]), + providerConnectionRef: primitives.resourcePointer, + providerCapabilityCard: primitives.providerCapabilityCard, + providerCapabilityDigest: DeploymentDigestSchema, + providerIdentity: ProviderIdentitySchema, + policyProfile: DeploymentNameSchema, + authorizationProfile: DeploymentNameSchema, + dataClassification: z.enum(["public", "internal", "private", "sensitive"]), + backupProfile: DeploymentNameSchema, + rollbackProfile: DeploymentNameSchema, + commercialBindingRef: primitives.resourcePointer.optional(), + writer: primitives.actorPointer, + changeEvidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + if ( + value.providerCapabilityDigest + !== sha256DeploymentValue(value.providerCapabilityCard) + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Provider capability digest does not match the pinned capability card", + path: ["providerCapabilityDigest"], + }); + } + if (value.etag !== computeEnvironmentBindingEtag(value.id, value.revision)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Environment ETag does not match id and revision", + path: ["etag"], + }); + } + validateChronology(value.createdAt, value.updatedAt, ctx, ["updatedAt"]); + }); + + const DeploymentRequestKindSchema = z.enum([ + "deployment", + "promotion", + "rollback", + "reconciliation", + ]); + + const DeploymentRequestSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.deploymentRequest), + kind: DeploymentRequestKindSchema, + requester: primitives.actorPointer, + product: ProductProjectionRefSchema, + environment: EnvironmentBindingRefSchema, + intent: IntentSnapshotRefSchema, + artifact: BuildArtifactRefSchema.optional(), + attestations: z.array(ArtifactAttestationRefSchema).default([]), + priorReceipt: DeploymentReceiptRefSchema.optional(), + policyProfile: DeploymentNameSchema, + idempotencyKeyFingerprint: DeploymentDigestSchema, + requestAt: DeploymentTimestampSchema, + expiresAt: DeploymentTimestampSchema.nullable().optional(), + sourceRequestId: DeploymentIdSchema, + auditCorrelationId: DeploymentIdSchema, + costEstimate: primitives.costEstimate.optional(), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.attestations, (ref) => `${ref.id}:${ref.digest}`, ctx, ["attestations"], "Attestation references"); + validateChronology(value.requestAt, value.expiresAt, ctx, ["expiresAt"]); + if (value.kind === "deployment" && !value.artifact) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment requests require an immutable build artifact", + path: ["artifact"], + }); + } + if ( + (value.kind === "promotion" || value.kind === "rollback") + && !value.priorReceipt + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Promotion and rollback requests require an immutable prior receipt", + path: ["priorReceipt"], + }); + } + }); + + const DeploymentInputRefSchema = z.object({ + schema: primitives.schemaId, + id: DeploymentIdSchema, + revision: z.number().int().positive().optional(), + digest: DeploymentDigestSchema, + }).strict(); + + const DeploymentActionSchema = z.object({ + id: DeploymentNameSchema, + operationId: DeploymentOperationIdSchema, + operationVersion: z.number().int().positive(), + dependsOn: z.array(DeploymentNameSchema).default([]), + inputs: z.array(DeploymentInputRefSchema).default([]), + outputSchema: primitives.schemaId, + preconditions: z.array(DeploymentNameSchema).default([]), + postconditions: z.array(DeploymentNameSchema).default([]), + lockClass: DeploymentNameSchema, + fencingRequired: z.boolean(), + sideEffectClass: primitives.providerSideEffectClass, + riskClass: z.enum(["low", "medium", "high", "critical"]), + approvalScope: z.enum(["none", "plan", "action", "phase"]), + runtimeMaterialKind: DeploymentNameSchema.nullable(), + providerOperation: DeploymentOperationIdSchema.nullable(), + providerCapabilityDigest: DeploymentDigestSchema.nullable(), + retryClass: z.enum(["none", "safe", "reconcile_first"]), + maxAttempts: z.number().int().positive().max(20), + timeoutClass: DeploymentNameSchema, + compensationOperationId: DeploymentOperationIdSchema.nullable(), + idempotencyRequired: z.boolean(), + reconciliationRequired: z.boolean(), + evidenceRequirements: z.array(DeploymentNameSchema).min(1), + }).strict().superRefine((value, ctx) => { + uniqueBy(value.dependsOn, String, ctx, ["dependsOn"], "Action dependency ids"); + uniqueBy(value.inputs, (input) => `${input.schema}:${input.id}`, ctx, ["inputs"], "Action input identities"); + if (Boolean(value.providerOperation) !== Boolean(value.providerCapabilityDigest)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Provider actions require both operation and capability digest", + path: value.providerOperation + ? ["providerCapabilityDigest"] + : ["providerOperation"], + }); + } + if (value.sideEffectClass !== "none" && value.sideEffectClass !== "read_only") { + if (!value.idempotencyRequired) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Side-effecting actions require idempotency", + path: ["idempotencyRequired"], + }); + } + if (!value.reconciliationRequired) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Side-effecting actions require reconciliation", + path: ["reconciliationRequired"], + }); + } + if (!value.compensationOperationId) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Side-effecting actions require compensation or rollback", + path: ["compensationOperationId"], + }); + } + } + if (value.runtimeMaterialKind && value.approvalScope !== "phase") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Runtime execution material requires phase-scoped approval", + path: ["approvalScope"], + }); + } + }); + + const DeploymentPlanSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.deploymentPlan), + kind: DeploymentRequestKindSchema, + request: DeploymentRequestRefSchema, + compiler: z.object({ + actor: primitives.actorPointer, + version: z.string().trim().min(1), + contractKitVersion: z.literal(DEPLOYMENT_CONTRACT_VERSION), + }).strict(), + inputs: z.array(DeploymentInputRefSchema).min(1), + providerCapabilityDigests: z.array(DeploymentDigestSchema).default([]), + actions: z.array(DeploymentActionSchema).min(1), + authorizationRequirements: z.array(DeploymentNameSchema).default([]), + policyRequirements: z.array(DeploymentNameSchema).default([]), + riskClass: z.enum(["low", "medium", "high", "critical"]), + evidenceRequirements: z.array(DeploymentNameSchema).min(1), + expectedStateDigest: DeploymentDigestSchema, + verificationCriteria: z.array(DeploymentNameSchema).min(1), + rollbackTarget: DeploymentReceiptRefSchema.optional(), + rollbackInputs: z.array(DeploymentInputRefSchema).default([]), + estimatedCost: primitives.costEstimate.optional(), + issuedAt: DeploymentTimestampSchema, + expiresAt: DeploymentTimestampSchema.nullable().optional(), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + validateChronology(value.issuedAt, value.expiresAt, ctx, ["expiresAt"]); + uniqueBy(value.inputs, (input) => `${input.schema}:${input.id}`, ctx, ["inputs"], "Plan input identities"); + uniqueBy(value.actions, (action) => action.id, ctx, ["actions"], "Action ids"); + uniqueBy(value.providerCapabilityDigests, String, ctx, ["providerCapabilityDigests"], "Provider capability digests"); + if (!isSorted(value.actions.map((action) => action.id))) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Plan actions must use deterministic lexicographic order", + path: ["actions"], + }); + } + const actionIds = new Set(value.actions.map((action) => action.id)); + const visited = new Set(); + value.actions.forEach((action, index) => { + for (const dependency of action.dependsOn) { + if (!actionIds.has(dependency)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Action dependency must resolve inside the same plan", + path: ["actions", index, "dependsOn"], + }); + } else if (!visited.has(dependency)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Action dependencies must precede dependants in deterministic order", + path: ["actions", index, "dependsOn"], + }); + } + } + visited.add(action.id); + }); + }); + + const RuntimeMaterialBindingSchema = z.object({ + kind: DeploymentNameSchema, + digest: DeploymentDigestSchema, + stateLineage: DeploymentIdSchema, + preActionStateSerial: z.number().int().nonnegative(), + }).strict(); + + const DeploymentApprovalDecisionSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision), + decision: primitives.decisionEnvelope, + plan: DeploymentPlanRefSchema, + scope: z.enum(["plan", "action", "phase"]), + actionId: DeploymentNameSchema.nullable(), + phaseId: DeploymentNameSchema.nullable(), + runtimeMaterial: RuntimeMaterialBindingSchema.nullable(), + boundInputDigests: z.array(z.object({ + kind: DeploymentNameSchema, + digest: DeploymentDigestSchema, + }).strict()).min(1), + environment: EnvironmentBindingRefSchema, + actorRole: z.enum(["requester", "planner", "approver", "executor", "auditor", "administrator"]), + attemptScope: z.object({ + minimum: z.number().int().positive(), + maximum: z.number().int().positive(), + }).strict(), + unchangedRetryPolicy: z.enum(["allowed", "denied"]), + issuedAt: DeploymentTimestampSchema, + expiresAt: DeploymentTimestampSchema, + separationOfDutiesPassed: z.boolean(), + authorizationPolicyRevision: z.number().int().positive(), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + validateChronology(value.issuedAt, value.expiresAt, ctx, ["expiresAt"]); + uniqueBy(value.boundInputDigests, (binding) => binding.kind, ctx, ["boundInputDigests"], "Bound input kinds"); + if (value.decision.decisionType !== "approval") { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Deployment approval decisions must compose an approval DecisionEnvelope", + path: ["decision", "decisionType"], + }); + } + if (value.attemptScope.maximum < value.attemptScope.minimum) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Attempt scope maximum must be greater than or equal to minimum", + path: ["attemptScope", "maximum"], + }); + } + if (value.scope === "plan" && (value.actionId || value.phaseId || value.runtimeMaterial)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Plan-scoped decisions cannot bind action, phase, or runtime material", + path: ["scope"], + }); + } + if (value.scope === "action" && (!value.actionId || value.phaseId || value.runtimeMaterial)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Action-scoped decisions require only an action id", + path: ["actionId"], + }); + } + if (value.scope === "phase" && (!value.actionId || !value.phaseId || !value.runtimeMaterial)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Phase-scoped decisions require action, phase, and runtime material bindings", + path: ["runtimeMaterial"], + }); + } + if (value.decision.status === "allowed" && !value.separationOfDutiesPassed) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Allowed deployment decisions require separation-of-duties evaluation to pass", + path: ["separationOfDutiesPassed"], + }); + } + }); + + const AttemptApprovalRefSchema = z.object({ + decision: DeploymentApprovalDecisionRefSchema, + scope: z.enum(["plan", "action", "phase"]), + actionId: DeploymentNameSchema.nullable(), + phaseId: DeploymentNameSchema.nullable(), + runtimeMaterialDigest: DeploymentDigestSchema.nullable(), + }).strict(); + + const AttemptActionStepSchema = z.object({ + sequence: z.number().int().positive(), + actionId: DeploymentNameSchema, + state: z.enum(["pending", "running", "succeeded", "failed", "cancelled", "unknown_outcome"]), + providerCorrelationId: DeploymentIdSchema.nullable(), + startedAt: DeploymentTimestampSchema.nullable(), + finishedAt: DeploymentTimestampSchema.nullable(), + evidenceRefs: DeploymentEvidenceArraySchema, + }).strict().superRefine((value, ctx) => { + if (value.finishedAt && !value.startedAt) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Finished action steps require a start timestamp", + path: ["startedAt"], + }); + } + if (value.startedAt) { + validateChronology(value.startedAt, value.finishedAt, ctx, ["finishedAt"]); + } + }); + + const DeploymentAttemptSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.deploymentAttempt), + updatedAt: DeploymentTimestampSchema, + revision: z.number().int().positive(), + plan: DeploymentPlanRefSchema, + approvals: z.array(AttemptApprovalRefSchema).min(1), + requester: primitives.actorPointer, + decisionActors: DeploymentActorArraySchema, + executorActors: DeploymentActorArraySchema, + environmentLock: z.object({ + id: DeploymentIdSchema, + fencingToken: z.number().int().positive(), + }).strict(), + attemptNumber: z.number().int().positive(), + retryOf: DeploymentAttemptRefSchema.nullable(), + state: z.enum(["queued", "running", "reconciling", "unknown_outcome", "succeeded", "failed", "cancelled"]), + actionSteps: z.array(AttemptActionStepSchema).min(1), + outboxCorrelationRef: primitives.resourcePointer, + inboxCorrelationRef: primitives.resourcePointer, + failureReason: z.string().trim().min(1).nullable(), + evidenceRefs: DeploymentEvidenceArraySchema, + providerReceipts: z.array(ProviderReceiptRefSchema).default([]), + finalReceipt: DeploymentReceiptRefSchema.nullable(), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + validateChronology(value.createdAt, value.updatedAt, ctx, ["updatedAt"]); + uniqueBy(value.approvals, (approval) => approval.decision.id, ctx, ["approvals"], "Approval decision ids"); + uniqueBy(value.decisionActors, (actor) => `${actor.kind}:${actor.id}`, ctx, ["decisionActors"], "Decision actor identities"); + uniqueBy(value.executorActors, (actor) => `${actor.kind}:${actor.id}`, ctx, ["executorActors"], "Executor actor identities"); + uniqueBy(value.actionSteps, (step) => step.actionId, ctx, ["actionSteps"], "Attempt action ids"); + uniqueBy(value.actionSteps, (step) => String(step.sequence), ctx, ["actionSteps"], "Attempt action sequences"); + if (!isSorted(value.actionSteps.map((step) => String(step.sequence).padStart(10, "0")))) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Attempt action steps must be in ascending sequence order", + path: ["actionSteps"], + }); + } + if ((value.state === "failed" || value.state === "cancelled" || value.state === "unknown_outcome") && !value.failureReason) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Failed, cancelled, and unknown-outcome attempts require a reason", + path: ["failureReason"], + }); + } + if (value.state !== "succeeded" && value.finalReceipt) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Only succeeded attempts may bind a final deployment receipt", + path: ["finalReceipt"], + }); + } + }); + + const ProviderReceiptSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.providerReceipt), + attempt: DeploymentAttemptRefSchema, + provider: DeploymentNameSchema, + adapter: DeploymentNameSchema, + connectionRef: primitives.resourcePointer, + capabilityDigest: DeploymentDigestSchema, + operationId: DeploymentOperationIdSchema, + operationVersion: z.number().int().positive(), + providerIdentity: z.object({ + projectId: DeploymentIdSchema.nullable(), + operationId: DeploymentIdSchema, + deploymentId: DeploymentIdSchema.nullable(), + resourceIds: z.array(DeploymentIdSchema).default([]), + eventId: DeploymentIdSchema.nullable(), + }).strict(), + requestFingerprint: DeploymentDigestSchema, + providerStatus: DeploymentNameSchema, + normalizedResult: z.enum(["accepted", "succeeded", "failed", "cancelled", "unknown"]), + observedProviderRevision: DeploymentIdSchema.nullable(), + observedAt: DeploymentTimestampSchema, + retryClass: z.enum(["none", "safe", "reconcile_first"]), + reconciliationState: z.enum(["not_required", "pending", "confirmed", "diverged"]), + unknownOutcome: z.boolean(), + redaction: z.enum(["none", "partial", "full"]), + responseEvidenceRefs: z.array(primitives.evidencePointer).min(1), + observationEvidenceRefs: DeploymentEvidenceArraySchema, + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + const providerIds = [ + value.providerIdentity.projectId, + value.providerIdentity.operationId, + value.providerIdentity.deploymentId, + value.providerIdentity.eventId, + ...value.providerIdentity.resourceIds, + ].filter((identity): identity is string => Boolean(identity)); + providerIds.forEach((identity, index) => { + if (UUID.test(identity)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Provider receipts require provider-issued identities, not mutable local UUIDs", + path: ["providerIdentity", index], + }); + } + }); + uniqueBy(value.providerIdentity.resourceIds, String, ctx, ["providerIdentity", "resourceIds"], "Provider resource ids"); + if (value.normalizedResult === "succeeded" && value.observationEvidenceRefs.length === 0) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Provider success requires later observation evidence", + path: ["observationEvidenceRefs"], + }); + } + if (value.unknownOutcome !== (value.normalizedResult === "unknown")) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "unknownOutcome must agree with normalizedResult", + path: ["unknownOutcome"], + }); + } + }); + + const VerificationCheckSchema = z.object({ + id: DeploymentNameSchema, + kind: z.enum(["health", "readiness", "version", "migration", "alarm", "access", "restore", "rollback", "security", "contract"]), + status: z.enum(["passed", "failed", "missing", "expired", "blocked"]), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict(); + + const DeploymentReceiptSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.deploymentReceipt), + request: DeploymentRequestRefSchema, + plan: DeploymentPlanRefSchema, + approvals: z.array(DeploymentApprovalDecisionRefSchema).min(1), + attempt: DeploymentAttemptRefSchema, + product: ProductProjectionRefSchema, + intent: IntentSnapshotRefSchema, + artifact: BuildArtifactRefSchema, + attestations: z.array(ArtifactAttestationRefSchema).min(1), + environment: EnvironmentBindingRefSchema, + providerReceipts: z.array(ProviderReceiptRefSchema).min(1), + desiredStateDigest: DeploymentDigestSchema, + observedStateDigest: DeploymentDigestSchema, + verification: z.array(VerificationCheckSchema).min(1), + infrastructurePlanRef: primitives.evidencePointer.optional(), + infrastructureStateLineageRef: primitives.resourcePointer.optional(), + rollbackTarget: DeploymentReceiptRefSchema.optional(), + verifiers: DeploymentActorArraySchema, + evidenceRefs: z.array(primitives.evidencePointer).min(1), + outcome: z.enum(["succeeded", "failed", "cancelled", "unknown_outcome"]), + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.approvals, (approval) => approval.id, ctx, ["approvals"], "Receipt approval ids"); + uniqueBy(value.attestations, (attestation) => attestation.id, ctx, ["attestations"], "Receipt attestation ids"); + uniqueBy(value.providerReceipts, (receipt) => receipt.id, ctx, ["providerReceipts"], "Provider receipt ids"); + uniqueBy(value.verification, (check) => check.id, ctx, ["verification"], "Verification check ids"); + uniqueBy(value.verifiers, (actor) => `${actor.kind}:${actor.id}`, ctx, ["verifiers"], "Receipt verifier identities"); + if ( + value.outcome === "succeeded" + && value.verification.some((check) => check.status !== "passed") + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Succeeded deployment receipts require every verification check to pass", + path: ["verification"], + }); + } + }); + + const LaunchFindingSchema = z.object({ + id: DeploymentNameSchema, + severity: z.enum(["p0", "p1", "p2", "p3"]), + status: z.enum(["open", "resolved", "accepted"]), + evidenceRefs: z.array(primitives.evidencePointer).min(1), + }).strict(); + + const LaunchEvidenceSchema = z.object({ + ...recordBase(DEPLOYMENT_SCHEMA_IDS.launchEvidence), + product: ProductProjectionRefSchema, + environment: EnvironmentBindingRefSchema, + deploymentReceipt: DeploymentReceiptRefSchema, + requiredChecks: z.array(VerificationCheckSchema).min(1), + proofBundleRefs: z.array(primitives.resourcePointer).min(1), + findings: z.array(LaunchFindingSchema).default([]), + verifiers: DeploymentActorArraySchema, + independentReview: z.boolean(), + status: z.enum(["candidate", "blocked", "ready", "launched", "rolled_back"]), + compiledAt: DeploymentTimestampSchema, + expiresAt: DeploymentTimestampSchema, + }).strict().superRefine((value, ctx) => { + validateDeploymentRecord(value, ctx); + uniqueBy(value.requiredChecks, (check) => check.id, ctx, ["requiredChecks"], "Launch check ids"); + uniqueBy(value.findings, (finding) => finding.id, ctx, ["findings"], "Launch finding ids"); + uniqueBy(value.verifiers, (actor) => `${actor.kind}:${actor.id}`, ctx, ["verifiers"], "Launch verifier identities"); + validateChronology(value.compiledAt, value.expiresAt, ctx, ["expiresAt"]); + if ( + (value.status === "ready" || value.status === "launched") + && ( + value.requiredChecks.some((check) => check.status !== "passed") + || value.findings.some((finding) => + (finding.severity === "p0" || finding.severity === "p1") + && finding.status === "open") + || !value.independentReview + ) + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Ready and launched evidence requires passing checks, no open P0/P1 findings, and independent review", + path: ["status"], + }); + } + }); + + const DeploymentSchemaRegistry = Object.freeze({ + [DEPLOYMENT_SCHEMA_IDS.productProjection]: ProductProjectionSchema, + [DEPLOYMENT_SCHEMA_IDS.intentSnapshot]: IntentSnapshotSchema, + [DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate]: VerifiedSourceCandidateSchema, + [DEPLOYMENT_SCHEMA_IDS.buildArtifact]: BuildArtifactSchema, + [DEPLOYMENT_SCHEMA_IDS.artifactAttestation]: ArtifactAttestationSchema, + [DEPLOYMENT_SCHEMA_IDS.environmentBinding]: EnvironmentBindingSchema, + [DEPLOYMENT_SCHEMA_IDS.deploymentRequest]: DeploymentRequestSchema, + [DEPLOYMENT_SCHEMA_IDS.deploymentPlan]: DeploymentPlanSchema, + [DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision]: DeploymentApprovalDecisionSchema, + [DEPLOYMENT_SCHEMA_IDS.deploymentAttempt]: DeploymentAttemptSchema, + [DEPLOYMENT_SCHEMA_IDS.providerReceipt]: ProviderReceiptSchema, + [DEPLOYMENT_SCHEMA_IDS.deploymentReceipt]: DeploymentReceiptSchema, + [DEPLOYMENT_SCHEMA_IDS.launchEvidence]: LaunchEvidenceSchema, + }); + + return { + ProductProjectionRefSchema, + IntentSnapshotRefSchema, + VerifiedSourceCandidateRefSchema, + BuildArtifactRefSchema, + ArtifactAttestationRefSchema, + EnvironmentBindingRefSchema, + DeploymentRequestRefSchema, + DeploymentPlanRefSchema, + DeploymentApprovalDecisionRefSchema, + DeploymentAttemptRefSchema, + ProviderReceiptRefSchema, + DeploymentReceiptRefSchema, + ProductProjectionSchema, + IntentSnapshotSchema, + VerifiedSourceCandidateSchema, + BuildArtifactSchema, + ArtifactAttestationSchema, + EnvironmentBindingSchema, + DeploymentRequestSchema, + DeploymentActionSchema, + DeploymentPlanSchema, + DeploymentApprovalDecisionSchema, + DeploymentAttemptSchema, + ProviderReceiptSchema, + DeploymentReceiptSchema, + LaunchEvidenceSchema, + DeploymentSchemaRegistry, + } as const; +} + +export interface DeploymentContractSet { + productProjections: unknown[]; + intentSnapshots: unknown[]; + verifiedSourceCandidates: unknown[]; + buildArtifacts: unknown[]; + artifactAttestations: unknown[]; + environmentBindings: unknown[]; + deploymentRequests: unknown[]; + deploymentPlans: unknown[]; + deploymentApprovalDecisions: unknown[]; + deploymentAttempts: unknown[]; + providerReceipts: unknown[]; + deploymentReceipts: unknown[]; + launchEvidence: unknown[]; +} + +export interface DeploymentContractSetValidation { + success: boolean; + issues: string[]; +} + +export interface DeploymentContractSchemas { + ProductProjectionSchema: z.ZodTypeAny; + IntentSnapshotSchema: z.ZodTypeAny; + VerifiedSourceCandidateSchema: z.ZodTypeAny; + BuildArtifactSchema: z.ZodTypeAny; + ArtifactAttestationSchema: z.ZodTypeAny; + EnvironmentBindingSchema: z.ZodTypeAny; + DeploymentRequestSchema: z.ZodTypeAny; + DeploymentPlanSchema: z.ZodTypeAny; + DeploymentApprovalDecisionSchema: z.ZodTypeAny; + DeploymentAttemptSchema: z.ZodTypeAny; + ProviderReceiptSchema: z.ZodTypeAny; + DeploymentReceiptSchema: z.ZodTypeAny; + LaunchEvidenceSchema: z.ZodTypeAny; +} + +interface LinkedRecord { + id: string; + digest: string; + revision?: number; +} + +function linkedRecordMap( + records: readonly LinkedRecord[], + label: string, + issues: string[], +): Map { + const result = new Map(); + for (const record of records) { + if (result.has(record.id)) { + issues.push(`${label}: duplicate semantic id ${record.id}`); + continue; + } + result.set(record.id, record); + } + return result; +} + +function requireLinkedRecord( + reference: { id: string; digest: string; revision?: number }, + records: Map, + path: string, + issues: string[], +): void { + const target = records.get(reference.id); + if (!target) { + issues.push(`${path}: missing linked record ${reference.id}`); + return; + } + if (target.digest !== reference.digest) { + issues.push(`${path}: digest mismatch`); + } + if ( + reference.revision !== undefined + && target.revision !== reference.revision + ) { + issues.push(`${path}: revision mismatch`); + } +} + +export function validateDeploymentContractSet( + schemas: DeploymentContractSchemas, + input: DeploymentContractSet, +): DeploymentContractSetValidation { + const issues: string[] = []; + const parseMany = ( + name: keyof DeploymentContractSet, + schema: z.ZodType, + ): T[] => input[name].flatMap((value, index) => { + const parsed = schema.safeParse(value); + if (!parsed.success) { + for (const issue of parsed.error.issues) { + issues.push(`${String(name)}.${index}.${issue.path.join(".")}: ${issue.message}`); + } + return []; + } + return [parsed.data]; + }); + + const products = parseMany( + "productProjections", + schemas.ProductProjectionSchema, + ); + const intents = parseMany("intentSnapshots", schemas.IntentSnapshotSchema); + const candidates = parseMany( + "verifiedSourceCandidates", + schemas.VerifiedSourceCandidateSchema, + ); + const artifacts = parseMany("buildArtifacts", schemas.BuildArtifactSchema); + const attestations = parseMany( + "artifactAttestations", + schemas.ArtifactAttestationSchema, + ); + const environments = parseMany( + "environmentBindings", + schemas.EnvironmentBindingSchema, + ); + const requests = parseMany( + "deploymentRequests", + schemas.DeploymentRequestSchema, + ); + const plans = parseMany("deploymentPlans", schemas.DeploymentPlanSchema); + const approvals = parseMany( + "deploymentApprovalDecisions", + schemas.DeploymentApprovalDecisionSchema, + ); + const attempts = parseMany( + "deploymentAttempts", + schemas.DeploymentAttemptSchema, + ); + const providerReceipts = parseMany( + "providerReceipts", + schemas.ProviderReceiptSchema, + ); + const receipts = parseMany( + "deploymentReceipts", + schemas.DeploymentReceiptSchema, + ); + const launches = parseMany("launchEvidence", schemas.LaunchEvidenceSchema); + + const productMap = linkedRecordMap(products, "productProjections", issues); + const intentMap = linkedRecordMap(intents, "intentSnapshots", issues); + const candidateMap = linkedRecordMap( + candidates, + "verifiedSourceCandidates", + issues, + ); + const artifactMap = linkedRecordMap(artifacts, "buildArtifacts", issues); + const attestationMap = linkedRecordMap( + attestations, + "artifactAttestations", + issues, + ); + const environmentMap = linkedRecordMap( + environments, + "environmentBindings", + issues, + ); + const requestMap = linkedRecordMap(requests, "deploymentRequests", issues); + const planMap = linkedRecordMap(plans, "deploymentPlans", issues); + const approvalMap = linkedRecordMap( + approvals, + "deploymentApprovalDecisions", + issues, + ); + const attemptMap = linkedRecordMap(attempts, "deploymentAttempts", issues); + const providerReceiptMap = linkedRecordMap( + providerReceipts, + "providerReceipts", + issues, + ); + const receiptMap = linkedRecordMap(receipts, "deploymentReceipts", issues); + linkedRecordMap(launches, "launchEvidence", issues); + + intents.forEach((intent) => + requireLinkedRecord(intent.product, productMap, `intentSnapshots.${intent.id}.product`, issues)); + candidates.forEach((candidate) => + requireLinkedRecord(candidate.intent, intentMap, `verifiedSourceCandidates.${candidate.id}.intent`, issues)); + artifacts.forEach((artifact) => + requireLinkedRecord(artifact.sourceCandidate, candidateMap, `buildArtifacts.${artifact.id}.sourceCandidate`, issues)); + attestations.forEach((attestation) => { + requireLinkedRecord(attestation.artifact, artifactMap, `artifactAttestations.${attestation.id}.artifact`, issues); + const artifact = artifactMap.get(attestation.artifact.id) as + | (LinkedRecord & { artifactDigest?: string }) + | undefined; + if (artifact && "artifactDigest" in artifact && artifact.artifactDigest !== attestation.artifactDigest) { + issues.push(`artifactAttestations.${attestation.id}.artifactDigest: digest mismatch`); + } + }); + environments.forEach((environment) => { + requireLinkedRecord(environment.product, productMap, `environmentBindings.${environment.id}.product`, issues); + requireLinkedRecord(environment.intent, intentMap, `environmentBindings.${environment.id}.intent`, issues); + }); + requests.forEach((request) => { + requireLinkedRecord(request.product, productMap, `deploymentRequests.${request.id}.product`, issues); + requireLinkedRecord(request.environment, environmentMap, `deploymentRequests.${request.id}.environment`, issues); + requireLinkedRecord(request.intent, intentMap, `deploymentRequests.${request.id}.intent`, issues); + if (request.artifact) { + requireLinkedRecord(request.artifact, artifactMap, `deploymentRequests.${request.id}.artifact`, issues); + } + request.attestations.forEach((attestation: LinkedRecord, index: number) => + requireLinkedRecord(attestation, attestationMap, `deploymentRequests.${request.id}.attestations.${index}`, issues)); + if (request.priorReceipt) { + requireLinkedRecord(request.priorReceipt, receiptMap, `deploymentRequests.${request.id}.priorReceipt`, issues); + } + }); + plans.forEach((plan) => + requireLinkedRecord(plan.request, requestMap, `deploymentPlans.${plan.id}.request`, issues)); + approvals.forEach((approval) => + requireLinkedRecord(approval.plan, planMap, `deploymentApprovalDecisions.${approval.id}.plan`, issues)); + attempts.forEach((attempt) => { + requireLinkedRecord(attempt.plan, planMap, `deploymentAttempts.${attempt.id}.plan`, issues); + attempt.approvals.forEach(( + approval: { decision: LinkedRecord }, + index: number, + ) => + requireLinkedRecord(approval.decision, approvalMap, `deploymentAttempts.${attempt.id}.approvals.${index}`, issues)); + }); + providerReceipts.forEach((receipt) => + requireLinkedRecord(receipt.attempt, attemptMap, `providerReceipts.${receipt.id}.attempt`, issues)); + receipts.forEach((receipt) => { + requireLinkedRecord(receipt.request, requestMap, `deploymentReceipts.${receipt.id}.request`, issues); + requireLinkedRecord(receipt.plan, planMap, `deploymentReceipts.${receipt.id}.plan`, issues); + requireLinkedRecord(receipt.attempt, attemptMap, `deploymentReceipts.${receipt.id}.attempt`, issues); + receipt.approvals.forEach((approval: LinkedRecord, index: number) => + requireLinkedRecord(approval, approvalMap, `deploymentReceipts.${receipt.id}.approvals.${index}`, issues)); + receipt.providerReceipts.forEach(( + providerReceipt: LinkedRecord, + index: number, + ) => + requireLinkedRecord(providerReceipt, providerReceiptMap, `deploymentReceipts.${receipt.id}.providerReceipts.${index}`, issues)); + }); + launches.forEach((launch) => { + requireLinkedRecord(launch.product, productMap, `launchEvidence.${launch.id}.product`, issues); + requireLinkedRecord(launch.environment, environmentMap, `launchEvidence.${launch.id}.environment`, issues); + requireLinkedRecord(launch.deploymentReceipt, receiptMap, `launchEvidence.${launch.id}.deploymentReceipt`, issues); + }); + + return { + success: issues.length === 0, + issues, + }; +} diff --git a/src/deployment/index.ts b/src/deployment/index.ts new file mode 100644 index 0000000..d1f46cf --- /dev/null +++ b/src/deployment/index.ts @@ -0,0 +1,75 @@ +export { + DEPLOYMENT_CONTRACT_VERSION, + DEPLOYMENT_GENERATED_ARTIFACT_ROOT, + DEPLOYMENT_SCHEMA_IDS, + canonicalizeDeploymentValue, + computeDeploymentRecordDigest, + computeEnvironmentBindingEtag, + sha256DeploymentText, + sha256DeploymentValue, + stableDeploymentJson, + validateDeploymentContractSet, + withDeploymentRecordDigest, + type DeploymentContractSchemas, + type DeploymentContractSet, + type DeploymentContractSetValidation, + type DeploymentSchemaId, +} from "../deployment"; + +export { + ArtifactAttestationRefSchema, + ArtifactAttestationSchema, + BuildArtifactRefSchema, + BuildArtifactSchema, + DeploymentActionSchema, + DeploymentApprovalDecisionRefSchema, + DeploymentApprovalDecisionSchema, + DeploymentAttemptRefSchema, + DeploymentAttemptSchema, + DeploymentPlanRefSchema, + DeploymentPlanSchema, + DeploymentReceiptRefSchema, + DeploymentReceiptSchema, + DeploymentRequestRefSchema, + DeploymentRequestSchema, + DeploymentSchemaRegistry, + EnvironmentBindingRefSchema, + EnvironmentBindingSchema, + IntentSnapshotRefSchema, + IntentSnapshotSchema, + LaunchEvidenceSchema, + ProductProjectionRefSchema, + ProductProjectionSchema, + ProviderReceiptRefSchema, + ProviderReceiptSchema, + VerifiedSourceCandidateRefSchema, + VerifiedSourceCandidateSchema, + type ArtifactAttestation, + type ArtifactAttestationInput, + type BuildArtifact, + type BuildArtifactInput, + type DeploymentAction, + type DeploymentActionInput, + type DeploymentApprovalDecision, + type DeploymentApprovalDecisionInput, + type DeploymentAttempt, + type DeploymentAttemptInput, + type DeploymentPlan, + type DeploymentPlanInput, + type DeploymentReceipt, + type DeploymentReceiptInput, + type DeploymentRequest, + type DeploymentRequestInput, + type EnvironmentBinding, + type EnvironmentBindingInput, + type IntentSnapshot, + type IntentSnapshotInput, + type LaunchEvidence, + type LaunchEvidenceInput, + type ProductProjection, + type ProductProjectionInput, + type ProviderReceipt, + type ProviderReceiptInput, + type VerifiedSourceCandidate, + type VerifiedSourceCandidateInput, +} from "../schemas"; diff --git a/src/hasna.contract.schema.json b/src/hasna.contract.schema.json index e065458..2e4144a 100644 --- a/src/hasna.contract.schema.json +++ b/src/hasna.contract.schema.json @@ -83,7 +83,7 @@ "type": "string", "minLength": 1 }, - "description": "Declared bins. Allowlisted: , -cli, -mcp, -serve, -worker, -runner, -daemon, -migrate, -doctor." + "description": "Declared bins. Allowlisted: , -cli, -mcp, -serve, -worker, -runner, -daemon, -migrate, -doctor. The deployment app additionally supports its registered canonical operator entrypoint hasna-deploy." }, "hosting": { "type": "array", diff --git a/src/index.ts b/src/index.ts index 2a2699c..8258664 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ export * from "./schemas"; export * from "./validators"; +export * from "./deployment"; +export * from "./deployment-artifacts"; export * from "./no-cloud"; export * from "./server-backend"; export * from "./service-contract"; diff --git a/src/no-cloud.ts b/src/no-cloud.ts index add7b9f..4667ea1 100644 --- a/src/no-cloud.ts +++ b/src/no-cloud.ts @@ -1064,7 +1064,24 @@ function collectTarballFiles(target: string): ScanFile[] { // deliberately so — see src/artifact-scan.ts. const kind = shouldReadPath(normalized); if (!kind) continue; - const text = readArchiveMemberText(target, entry); + let text: string; + try { + text = readArchiveMemberText(target, entry); + } catch (error) { + // Directory scans already decline source-shaped files above + // MAX_TEXT_BYTES. Apply the same policy to packed members instead of + // turning an otherwise valid package into a scanner crash. + if ( + error instanceof Error + && ( + (error as NodeJS.ErrnoException).code === "ENOBUFS" + || error.message.includes("maxBuffer") + ) + ) { + continue; + } + throw error; + } const artifactKind = kind === "package_manifest" || kind === "lockfile" ? kind : "packed_artifact"; files.push({ path: normalized, text, kind: artifactKind }); } diff --git a/src/schemas.ts b/src/schemas.ts index 9098963..3f9581c 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -1,8 +1,12 @@ import { createHash } from "node:crypto"; +import { + createDeploymentSchemas, + DEPLOYMENT_SCHEMA_IDS, +} from "./deployment"; import { z } from "zod"; export const CONTRACTS_PACKAGE_NAME = "@hasna/contracts"; -export const CONTRACTS_PACKAGE_VERSION = "0.10.2"; +export const CONTRACTS_PACKAGE_VERSION = "0.10.3"; export const SCHEMA_IDS = { actorRef: "hasna.actor_ref.v1", @@ -5661,9 +5665,21 @@ export const ALLOWED_BIN_SUFFIXES = [ "-doctor" ] as const; +/** + * Canonical Hasna operator entrypoints whose public name intentionally differs + * from the package/app name. Keep this registry exact: it is not permission + * for arbitrary `hasna-*` binaries. + */ +const CANONICAL_HASNA_BIN_ALIASES: Readonly> = Object.freeze({ + deployment: Object.freeze(["hasna-deploy"]) +}); + /** All bin names an app named `name` may declare by default. */ export function allowedBinsForName(name: string): string[] { - return ALLOWED_BIN_SUFFIXES.map((suffix) => `${name}${suffix}`); + return [ + ...ALLOWED_BIN_SUFFIXES.map((suffix) => `${name}${suffix}`), + ...(CANONICAL_HASNA_BIN_ALIASES[name] ?? []) + ]; } /** @@ -6639,7 +6655,69 @@ export function validateCommsTaggedMessage(input: { return { success: true, tag, metadata: parsed.data }; } -export const ContractSchemaRegistry = { +const DEPLOYMENT_SCHEMAS = createDeploymentSchemas({ + actorPointer: ActorPointerSchema, + costEstimate: CostEstimateSchema, + decisionEnvelope: DecisionEnvelopeSchema, + evidencePointer: EvidencePointerSchema, + providerCapabilityCard: ProviderCapabilityCardSchema, + resourcePointer: ResourcePointerSchema, + validationPlan: ValidationPlanSchema, + workRun: WorkRunSchema, + schemaId: SchemaIdSchema, + timestamp: TimestampSchema, + uri: UriSchema, + sha256Digest: Sha256DigestSchema, + relativeProjectPath: RelativeProjectPathSchema, + providerSideEffectClass: ProviderSideEffectClassSchema, +}); + +export const { + ProductProjectionRefSchema, + IntentSnapshotRefSchema, + VerifiedSourceCandidateRefSchema, + BuildArtifactRefSchema, + ArtifactAttestationRefSchema, + EnvironmentBindingRefSchema, + DeploymentRequestRefSchema, + DeploymentPlanRefSchema, + DeploymentApprovalDecisionRefSchema, + DeploymentAttemptRefSchema, + ProviderReceiptRefSchema, + DeploymentReceiptRefSchema, + ProductProjectionSchema, + IntentSnapshotSchema, + VerifiedSourceCandidateSchema, + BuildArtifactSchema, + ArtifactAttestationSchema, + EnvironmentBindingSchema, + DeploymentRequestSchema, + DeploymentActionSchema, + DeploymentPlanSchema, + DeploymentApprovalDecisionSchema, + DeploymentAttemptSchema, + ProviderReceiptSchema, + DeploymentReceiptSchema, + LaunchEvidenceSchema, + DeploymentSchemaRegistry, +} = DEPLOYMENT_SCHEMAS; + +export type ProductProjection = z.output; +export type IntentSnapshot = z.output; +export type VerifiedSourceCandidate = z.output; +export type BuildArtifact = z.output; +export type ArtifactAttestation = z.output; +export type EnvironmentBinding = z.output; +export type DeploymentRequest = z.output; +export type DeploymentAction = z.output; +export type DeploymentPlan = z.output; +export type DeploymentApprovalDecision = z.output; +export type DeploymentAttempt = z.output; +export type ProviderReceipt = z.output; +export type DeploymentReceipt = z.output; +export type LaunchEvidence = z.output; + +const CoreContractSchemaRegistry = { [SCHEMA_IDS.actorRef]: ActorRefSchema, [SCHEMA_IDS.resourceRef]: ResourceRefSchema, [SCHEMA_IDS.evidenceRef]: EvidenceRefSchema, @@ -6676,9 +6754,15 @@ export const ContractSchemaRegistry = { [SCHEMA_IDS.release]: ReleaseSchema, [SCHEMA_IDS.rolloutRecord]: RolloutRecordSchema, [SCHEMA_IDS.announcement]: AnnouncementSchema, - [SCHEMA_IDS.audience]: AudienceSchema + [SCHEMA_IDS.audience]: AudienceSchema, } as const; +export const ContractSchemaRegistry: + typeof CoreContractSchemaRegistry & typeof DeploymentSchemaRegistry = { + ...CoreContractSchemaRegistry, + ...DeploymentSchemaRegistry, +}; + export type KnownSchemaId = keyof typeof ContractSchemaRegistry; export type ContractBySchemaId = { @@ -6715,6 +6799,19 @@ export type ContractBySchemaId = { [SCHEMA_IDS.rolloutRecord]: RolloutRecord; [SCHEMA_IDS.announcement]: Announcement; [SCHEMA_IDS.audience]: Audience; + [DEPLOYMENT_SCHEMA_IDS.productProjection]: ProductProjection; + [DEPLOYMENT_SCHEMA_IDS.intentSnapshot]: IntentSnapshot; + [DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate]: VerifiedSourceCandidate; + [DEPLOYMENT_SCHEMA_IDS.buildArtifact]: BuildArtifact; + [DEPLOYMENT_SCHEMA_IDS.artifactAttestation]: ArtifactAttestation; + [DEPLOYMENT_SCHEMA_IDS.environmentBinding]: EnvironmentBinding; + [DEPLOYMENT_SCHEMA_IDS.deploymentRequest]: DeploymentRequest; + [DEPLOYMENT_SCHEMA_IDS.deploymentPlan]: DeploymentPlan; + [DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision]: DeploymentApprovalDecision; + [DEPLOYMENT_SCHEMA_IDS.deploymentAttempt]: DeploymentAttempt; + [DEPLOYMENT_SCHEMA_IDS.providerReceipt]: ProviderReceipt; + [DEPLOYMENT_SCHEMA_IDS.deploymentReceipt]: DeploymentReceipt; + [DEPLOYMENT_SCHEMA_IDS.launchEvidence]: LaunchEvidence; }; export type ActorRefInput = z.input; @@ -6753,6 +6850,20 @@ export type AudienceInput = z.input; export type ActorPointerInput = z.input; export type ResourcePointerInput = z.input; export type EvidencePointerInput = z.input; +export type ProductProjectionInput = z.input; +export type IntentSnapshotInput = z.input; +export type VerifiedSourceCandidateInput = z.input; +export type BuildArtifactInput = z.input; +export type ArtifactAttestationInput = z.input; +export type EnvironmentBindingInput = z.input; +export type DeploymentRequestInput = z.input; +export type DeploymentActionInput = z.input; +export type DeploymentPlanInput = z.input; +export type DeploymentApprovalDecisionInput = z.input; +export type DeploymentAttemptInput = z.input; +export type ProviderReceiptInput = z.input; +export type DeploymentReceiptInput = z.input; +export type LaunchEvidenceInput = z.input; export type ContractInputBySchemaId = { [SCHEMA_IDS.actorRef]: ActorRefInput; @@ -6788,4 +6899,17 @@ export type ContractInputBySchemaId = { [SCHEMA_IDS.rolloutRecord]: RolloutRecordInput; [SCHEMA_IDS.announcement]: AnnouncementInput; [SCHEMA_IDS.audience]: AudienceInput; + [DEPLOYMENT_SCHEMA_IDS.productProjection]: ProductProjectionInput; + [DEPLOYMENT_SCHEMA_IDS.intentSnapshot]: IntentSnapshotInput; + [DEPLOYMENT_SCHEMA_IDS.verifiedSourceCandidate]: VerifiedSourceCandidateInput; + [DEPLOYMENT_SCHEMA_IDS.buildArtifact]: BuildArtifactInput; + [DEPLOYMENT_SCHEMA_IDS.artifactAttestation]: ArtifactAttestationInput; + [DEPLOYMENT_SCHEMA_IDS.environmentBinding]: EnvironmentBindingInput; + [DEPLOYMENT_SCHEMA_IDS.deploymentRequest]: DeploymentRequestInput; + [DEPLOYMENT_SCHEMA_IDS.deploymentPlan]: DeploymentPlanInput; + [DEPLOYMENT_SCHEMA_IDS.deploymentApprovalDecision]: DeploymentApprovalDecisionInput; + [DEPLOYMENT_SCHEMA_IDS.deploymentAttempt]: DeploymentAttemptInput; + [DEPLOYMENT_SCHEMA_IDS.providerReceipt]: ProviderReceiptInput; + [DEPLOYMENT_SCHEMA_IDS.deploymentReceipt]: DeploymentReceiptInput; + [DEPLOYMENT_SCHEMA_IDS.launchEvidence]: LaunchEvidenceInput; }; diff --git a/src/service-contract.ts b/src/service-contract.ts index 1c74dd0..7437fa0 100644 --- a/src/service-contract.ts +++ b/src/service-contract.ts @@ -85,7 +85,7 @@ export const SERVICE_CONTRACT_JSON_SCHEMA = { type: "array", items: { type: "string", minLength: 1 }, description: - "Declared bins. Allowlisted: , -cli, -mcp, -serve, -worker, -runner, -daemon, -migrate, -doctor." + "Declared bins. Allowlisted: , -cli, -mcp, -serve, -worker, -runner, -daemon, -migrate, -doctor. The deployment app additionally supports its registered canonical operator entrypoint hasna-deploy." }, hosting: { type: "array", diff --git a/tests/deployment-artifacts.test.ts b/tests/deployment-artifacts.test.ts new file mode 100644 index 0000000..f3a6fa3 --- /dev/null +++ b/tests/deployment-artifacts.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync, readdirSync } from "node:fs"; +import { join, relative } from "node:path"; +import { + buildDeploymentFixtureBundle, + buildDeploymentJsonSchemas, + buildDeploymentSchemaBundle, + renderDeploymentArtifacts, +} from "../src/deployment-artifacts"; +import { + DEPLOYMENT_GENERATED_ARTIFACT_ROOT, + DEPLOYMENT_SCHEMA_IDS, + sha256DeploymentText, + sha256DeploymentValue, +} from "../src/deployment"; + +const repositoryRoot = join(import.meta.dir, ".."); +const generatedRoot = join( + repositoryRoot, + DEPLOYMENT_GENERATED_ARTIFACT_ROOT, +); + +function listFiles(root: string): string[] { + const files: string[] = []; + const walk = (directory: string) => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const path = join(directory, entry.name); + if (entry.isDirectory()) { + walk(path); + } else if (entry.isFile()) { + files.push(relative(root, path)); + } + } + }; + walk(root); + return files.sort((left, right) => left.localeCompare(right)); +} + +describe("deployment generated artifacts", () => { + test("schema and fixture bundles are deterministic", () => { + expect(buildDeploymentSchemaBundle()).toEqual( + buildDeploymentSchemaBundle(), + ); + expect(buildDeploymentFixtureBundle()).toEqual( + buildDeploymentFixtureBundle(), + ); + expect(renderDeploymentArtifacts()).toEqual(renderDeploymentArtifacts()); + }); + + test("the schema bundle registers every exact deployment schema id", () => { + const schemas = buildDeploymentJsonSchemas(); + expect(Object.keys(schemas).sort()).toEqual( + Object.values(DEPLOYMENT_SCHEMA_IDS).sort(), + ); + for (const [schemaId, schema] of Object.entries(schemas)) { + expect(schema.$id).toBe(schemaId); + expect(schema.type).toBe("object"); + expect(schema.additionalProperties).toBe(false); + expect(schema["x-hasna-runtime-validation-required"]).toBe(true); + expect(schema["x-hasna-cross-record-validation-required"]).toBe(true); + } + + const bundle = buildDeploymentSchemaBundle(); + expect(bundle.schemaDigest).toBe(sha256DeploymentValue(bundle.schemas)); + }); + + test("checked-in artifacts match the renderer byte for byte", () => { + const rendered = renderDeploymentArtifacts(); + expect(listFiles(generatedRoot)).toEqual(Object.keys(rendered)); + for (const [path, expected] of Object.entries(rendered)) { + expect(readFileSync(join(generatedRoot, path), "utf8")).toBe(expected); + } + }); + + test("the checksum manifest authenticates every other generated artifact", () => { + const rendered = renderDeploymentArtifacts(); + const manifest = JSON.parse(rendered["checksums.json"]!) as { + files: Record; + manifestDigest: string; + }; + const expectedPaths = Object.keys(rendered) + .filter((path) => path !== "checksums.json") + .sort((left, right) => left.localeCompare(right)); + expect(Object.keys(manifest.files)).toEqual(expectedPaths); + for (const path of expectedPaths) { + expect(manifest.files[path]).toBe(sha256DeploymentText(rendered[path]!)); + } + expect(manifest.manifestDigest).toBe( + sha256DeploymentValue(manifest.files), + ); + }); +}); diff --git a/tests/deployment.test.ts b/tests/deployment.test.ts new file mode 100644 index 0000000..66dd02e --- /dev/null +++ b/tests/deployment.test.ts @@ -0,0 +1,221 @@ +import { describe, expect, test } from "bun:test"; +import { + ArtifactAttestationSchema, + BuildArtifactSchema, + ContractSchemaRegistry, + DeploymentApprovalDecisionSchema, + DeploymentAttemptSchema, + DeploymentPlanSchema, + DeploymentReceiptSchema, + DeploymentRequestSchema, + EnvironmentBindingSchema, + IntentSnapshotSchema, + LaunchEvidenceSchema, + ProductProjectionSchema, + ProviderReceiptSchema, + VerifiedSourceCandidateSchema, +} from "../src/schemas"; +import { + DEPLOYMENT_SCHEMA_IDS, + canonicalizeDeploymentValue, + computeDeploymentRecordDigest, + sha256DeploymentText, + stableDeploymentJson, + validateDeploymentContractSet, + withDeploymentRecordDigest, +} from "../src/deployment"; +import { + createDeploymentFixtureSet, + deploymentFixtureSetToContractSet, + deploymentFixturesBySchemaId, +} from "../src/deployment-fixtures"; + +const runtimeSchemas = { + ProductProjectionSchema, + IntentSnapshotSchema, + VerifiedSourceCandidateSchema, + BuildArtifactSchema, + ArtifactAttestationSchema, + EnvironmentBindingSchema, + DeploymentRequestSchema, + DeploymentPlanSchema, + DeploymentApprovalDecisionSchema, + DeploymentAttemptSchema, + ProviderReceiptSchema, + DeploymentReceiptSchema, + LaunchEvidenceSchema, +}; + +function clone(value: T): T { + return structuredClone(value); +} + +function redigest>(value: T): T { + return withDeploymentRecordDigest(value) as T; +} + +describe("deployment contract records", () => { + test("all thirteen registered fixtures parse and retain canonical digests", () => { + const fixtures = createDeploymentFixtureSet(); + const fixturesBySchemaId = deploymentFixturesBySchemaId(fixtures); + const schemaIds = Object.values(DEPLOYMENT_SCHEMA_IDS); + + expect(schemaIds).toHaveLength(13); + for (const schemaId of schemaIds) { + const schema = ContractSchemaRegistry[schemaId]; + const fixture = fixturesBySchemaId[schemaId] as Record; + const parsed = schema.parse(fixture) as Record; + expect(parsed.digest).toBe(computeDeploymentRecordDigest(parsed)); + } + }); + + test("canonicalization is deterministic across object key order", () => { + const left = { + zeta: [3, { beta: true, alpha: "value" }], + alpha: { second: 2, first: 1 }, + }; + const right = { + alpha: { first: 1, second: 2 }, + zeta: [3, { alpha: "value", beta: true }], + }; + + expect(canonicalizeDeploymentValue(left)).toEqual( + canonicalizeDeploymentValue(right), + ); + expect(stableDeploymentJson(left)).toBe(stableDeploymentJson(right)); + }); + + test("the complete linked fixture set passes cross-record validation", () => { + const fixtures = createDeploymentFixtureSet(); + const result = validateDeploymentContractSet( + runtimeSchemas, + deploymentFixtureSetToContractSet(fixtures), + ); + expect(result).toEqual({ success: true, issues: [] }); + }); + + test("missing fields, unknown fields, and wrong schema versions are rejected", () => { + const fixtures = createDeploymentFixtureSet(); + const missing = clone(fixtures.productProjection) as Record; + delete missing.id; + expect(ProductProjectionSchema.safeParse(missing).success).toBe(false); + + const unknown = redigest({ + ...clone(fixtures.productProjection), + unexpectedField: "not-registered", + }); + expect(ProductProjectionSchema.safeParse(unknown).success).toBe(false); + + const wrongSchema = redigest({ + ...clone(fixtures.productProjection), + schema: "hasna.product_projection.v2", + }); + expect(ProductProjectionSchema.safeParse(wrongSchema).success).toBe(false); + }); + + test("duplicate semantic ids and non-finite numbers are rejected", () => { + const fixtures = createDeploymentFixtureSet(); + const duplicateProcess = clone(fixtures.intentSnapshot); + duplicateProcess.processes.push(clone(duplicateProcess.processes[0]!)); + expect( + IntentSnapshotSchema.safeParse(redigest(duplicateProcess)).success, + ).toBe(false); + + const nonFinite = clone(fixtures.intentSnapshot); + nonFinite.processes[0]!.resources.cpuMillicores = Number.POSITIVE_INFINITY; + expect(IntentSnapshotSchema.safeParse(nonFinite).success).toBe(false); + expect(() => stableDeploymentJson(nonFinite)).toThrow( + "rejects non-finite numbers", + ); + }); + + test("ambiguous timestamps are rejected", () => { + const fixtures = createDeploymentFixtureSet(); + const ambiguous = clone(fixtures.productProjection); + ambiguous.projectedAt = "2026-08-09T09:00:00"; + expect( + ProductProjectionSchema.safeParse(redigest(ambiguous)).success, + ).toBe(false); + }); + + test("secret-bearing values and executable strings are rejected recursively", () => { + const fixtures = createDeploymentFixtureSet(); + const secretBearing = clone(fixtures.deploymentApprovalDecision); + secretBearing.decision.reason = + "api_key=abcdefghijklmnopqrstuvwxyz012345"; + expect( + DeploymentApprovalDecisionSchema.safeParse( + redigest(secretBearing), + ).success, + ).toBe(false); + + const executable = clone(fixtures.deploymentApprovalDecision); + executable.decision.reason = "bash -c whoami"; + expect( + DeploymentApprovalDecisionSchema.safeParse(redigest(executable)).success, + ).toBe(false); + }); + + test("provider identity rejects mutable local UUIDs", () => { + const fixtures = createDeploymentFixtureSet(); + const environment = clone(fixtures.environmentBinding); + environment.providerIdentity.accountId = + "123e4567-e89b-42d3-a456-426614174000"; + expect( + EnvironmentBindingSchema.safeParse(redigest(environment)).success, + ).toBe(false); + + const receipt = clone(fixtures.providerReceipt); + receipt.providerIdentity.operationId = + "123e4567-e89b-42d3-a456-426614174000"; + expect(ProviderReceiptSchema.safeParse(redigest(receipt)).success).toBe( + false, + ); + }); + + test("duplicate cross-record semantic ids are rejected", () => { + const fixtures = createDeploymentFixtureSet(); + const contractSet = deploymentFixtureSetToContractSet(fixtures); + contractSet.productProjections.push(clone(fixtures.productProjection)); + const result = validateDeploymentContractSet(runtimeSchemas, contractSet); + expect(result.success).toBe(false); + expect(result.issues).toContain( + `productProjections: duplicate semantic id ${fixtures.productProjection.id}`, + ); + }); + + test.each([ + "intent", + "plan", + "approval", + "receipt", + ] as const)("mismatched %s digests fail the linked-set gate", (kind) => { + const fixtures = createDeploymentFixtureSet(); + const contractSet = deploymentFixtureSetToContractSet(fixtures); + const wrongDigest = sha256DeploymentText(`wrong-${kind}-digest`); + + if (kind === "intent") { + const request = clone(fixtures.deploymentRequest); + request.intent.digest = wrongDigest; + contractSet.deploymentRequests = [redigest(request)]; + } else if (kind === "plan") { + const approval = clone(fixtures.deploymentApprovalDecision); + approval.plan.digest = wrongDigest; + contractSet.deploymentApprovalDecisions = [redigest(approval)]; + } else if (kind === "approval") { + const attempt = clone(fixtures.deploymentAttempt); + attempt.approvals[0]!.decision.digest = wrongDigest; + contractSet.deploymentAttempts = [redigest(attempt)]; + } else { + const launch = clone(fixtures.launchEvidence); + launch.deploymentReceipt.digest = wrongDigest; + contractSet.launchEvidence = [redigest(launch)]; + } + + const result = validateDeploymentContractSet(runtimeSchemas, contractSet); + expect(result.success).toBe(false); + expect(result.issues.some((issue) => issue.endsWith("digest mismatch"))).toBe( + true, + ); + }); +}); diff --git a/tests/no-cloud-edge.test.ts b/tests/no-cloud-edge.test.ts index 2e53fbe..c836e25 100644 --- a/tests/no-cloud-edge.test.ts +++ b/tests/no-cloud-edge.test.ts @@ -1456,6 +1456,22 @@ describe("no-cloud gate: this package's inlined declaration is attributed, not e ); }); + test("packed scans skip an oversized source member and still inspect bounded members", () => { + const oversizedSource = `export const padding = ${JSON.stringify("x".repeat(5 * 1024 * 1024))};\n`; + withTarball( + { + "package.json": JSON.stringify({ name: "iapp-large", version: "1.0.0", files: ["dist"] }), + "dist/oversized.js": oversizedSource, + "dist/bounded.js": `export const runtime = "${RETIRED}";\n`, + }, + (report) => { + expect(report.scanMode).toBe("packed_artifact"); + expect(patterns(report)).toEqual([`dist/bounded.js:${RETIRED}`]); + expect(report.verdict).toBe("failed"); + }, + ); + }); + test("PROOF: a credential sitting NEXT TO the inlined declaration is still reported", () => { // Per-occurrence, not per-file. Both previous attempts returned early for // the whole file, which is what took the credential detectors with them. diff --git a/tests/published-package-security.test.ts b/tests/published-package-security.test.ts index 727cab7..986c7e7 100644 --- a/tests/published-package-security.test.ts +++ b/tests/published-package-security.test.ts @@ -20,7 +20,7 @@ import { CONTRACTS_PACKAGE_VERSION } from "../src/schemas.js"; import { scanNoCloudTarget } from "../src/no-cloud.js"; const root = join(import.meta.dir, ".."); -const expectedUnreleasedVersion = "0.10.2"; +const expectedUnreleasedVersion = "0.10.3"; const forbiddenInternalDomains = [["hasna", "xyz"].join(".")]; function commandText(bytes: Uint8Array): string { diff --git a/tests/service-contract.test.ts b/tests/service-contract.test.ts index 1a20199..f3d81b3 100644 --- a/tests/service-contract.test.ts +++ b/tests/service-contract.test.ts @@ -39,6 +39,9 @@ describe("service contract helpers", () => { expect(allowedBinsForName("todos")).toContain("todos"); expect(allowedBinsForName("todos")).toContain("todos-serve"); expect(allowedBinsForName("todos")).not.toContain("todos-sync"); + expect(allowedBinsForName("deployment")).toContain("hasna-deploy"); + expect(allowedBinsForName("deployment")).not.toContain("hasna-deployment"); + expect(allowedBinsForName("todos")).not.toContain("hasna-deploy"); expect(databaseUrlSecretRefFor("todos")).toBe("hasna/oss/todos/database-url"); expect(defaultSqlitePathFor("todos")).toBe("~/.hasna/todos/todos.db"); }); @@ -72,6 +75,36 @@ describe("service contract manifest validation", () => { expect(r.success).toBe(false); }); + test("accepts only the registered hasna-deploy alias for the deployment app", () => { + const deployment = { + ...baseCliWithStore, + name: "deployment", + bins: ["deployment", "hasna-deploy"], + storage: { + backend: "sqlite", + sqlitePath: "~/.hasna/deployment/deployment.db" + } + } as const; + expect(validateServiceContractManifest(deployment).success).toBe(true); + + const wrongApp = validateServiceContractManifest({ + ...baseCliWithStore, + bins: ["todos", "hasna-deploy"] + }); + expect(wrongApp.success).toBe(false); + if (!wrongApp.success) { + expect(wrongApp.error.issues).toContainEqual(expect.objectContaining({ + path: ["bins", 1], + message: expect.stringContaining('Bin "hasna-deploy" is not allowlisted for app "todos"') + })); + } + + expect(validateServiceContractManifest({ + ...deployment, + bins: ["deployment", "hasna-deployment"] + }).success).toBe(false); + }); + test("rejects deprecated backend aliases in the manifest (strict enum)", () => { const bad = { ...baseCliWithStore, storage: { backend: "hybrid", sqlitePath: "x" } }; expect(validateServiceContractManifest(bad).success).toBe(false); From 525c908f33696bdd6102e41f454c75f6449484cf Mon Sep 17 00:00:00 2001 From: Andrei Hasna Date: Sun, 9 Aug 2026 21:02:23 +0300 Subject: [PATCH 2/2] fix: seal deployment linked-set lineage Agent: codewith-iapp-news --- .github/workflows/ci.yml | 41 +++++++++ src/deployment.ts | 142 ++++++++++++++++++++++++++++- tests/deployment.test.ts | 190 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 44eb9aa..af60d8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,47 @@ on: branches: [main] jobs: + secret-scan: + name: Secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Install pinned gitleaks + env: + GITLEAKS_VERSION: "8.24.3" + GITLEAKS_SHA256: "9991e0b2903da4c8f6122b5c3186448b927a5da4deef1fe45271c3793f4ee29c" + run: | + set -euo pipefail + archive="$RUNNER_TEMP/gitleaks.tar.gz" + checksum_file="$RUNNER_TEMP/gitleaks.sha256" + curl --fail --silent --show-error --location \ + "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + --output "$archive" + printf '%s %s\n' "$GITLEAKS_SHA256" "$archive" > "$checksum_file" + sha256sum --check "$checksum_file" + tar -xzf "$archive" -C "$RUNNER_TEMP" gitleaks + - name: Scan repository with redacted output + env: + BASE_SHA: ${{ github.event.before || github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.after || github.event.pull_request.head.sha || github.sha }} + run: | + set -euo pipefail + if [[ "$BASE_SHA" =~ ^0+$ ]]; then + log_opts="$HEAD_SHA" + else + log_opts="$BASE_SHA..$HEAD_SHA" + fi + "$RUNNER_TEMP/gitleaks" detect \ + --source . \ + --log-opts "$log_opts" \ + --redact \ + --no-banner + verify: runs-on: ubuntu-latest steps: diff --git a/src/deployment.ts b/src/deployment.ts index d6d4825..c9ad545 100644 --- a/src/deployment.ts +++ b/src/deployment.ts @@ -1193,11 +1193,45 @@ export interface DeploymentContractSchemas { } interface LinkedRecord { + schema?: string; id: string; digest: string; revision?: number; } +interface DeploymentRecordReference extends LinkedRecord { + schema: string; +} + +function sameDeploymentReference( + left: DeploymentRecordReference, + right: DeploymentRecordReference, +): boolean { + return left.schema === right.schema + && left.id === right.id + && left.digest === right.digest + && left.revision === right.revision; +} + +function sameDeploymentReferenceSet( + left: readonly DeploymentRecordReference[], + right: readonly DeploymentRecordReference[], +): boolean { + if (left.length !== right.length) { + return false; + } + const referenceKey = (reference: DeploymentRecordReference) => + [ + reference.schema, + reference.id, + reference.revision ?? "", + reference.digest, + ].join("\u0000"); + const leftKeys = left.map(referenceKey).sort(); + const rightKeys = right.map(referenceKey).sort(); + return leftKeys.every((key, index) => key === rightKeys[index]); +} + function linkedRecordMap( records: readonly LinkedRecord[], label: string, @@ -1362,10 +1396,98 @@ export function validateDeploymentContractSet( requireLinkedRecord(request.priorReceipt, receiptMap, `deploymentRequests.${request.id}.priorReceipt`, issues); } }); - plans.forEach((plan) => - requireLinkedRecord(plan.request, requestMap, `deploymentPlans.${plan.id}.request`, issues)); - approvals.forEach((approval) => - requireLinkedRecord(approval.plan, planMap, `deploymentApprovalDecisions.${approval.id}.plan`, issues)); + plans.forEach((plan) => { + requireLinkedRecord(plan.request, requestMap, `deploymentPlans.${plan.id}.request`, issues); + const request = requestMap.get(plan.request.id) as + | (LinkedRecord & { + product: DeploymentRecordReference; + environment: DeploymentRecordReference; + intent: DeploymentRecordReference; + artifact?: DeploymentRecordReference; + attestations: DeploymentRecordReference[]; + priorReceipt?: DeploymentRecordReference; + }) + | undefined; + if (!request) { + return; + } + const pinnedRequestInputs = [ + request.product, + request.environment, + request.intent, + ...(request.artifact ? [request.artifact] : []), + ...(request.priorReceipt ? [request.priorReceipt] : []), + ]; + if (!sameDeploymentReferenceSet(plan.inputs, pinnedRequestInputs)) { + issues.push( + `deploymentPlans.${plan.id}.inputs: input set does not exactly match linked request ${request.id}`, + ); + } + }); + approvals.forEach((approval) => { + requireLinkedRecord(approval.plan, planMap, `deploymentApprovalDecisions.${approval.id}.plan`, issues); + const plan = planMap.get(approval.plan.id) as + | (LinkedRecord & { + request: DeploymentRecordReference; + inputs: DeploymentRecordReference[]; + rollbackInputs: DeploymentRecordReference[]; + providerCapabilityDigests: string[]; + }) + | undefined; + if (!plan) { + return; + } + const request = requestMap.get(plan.request.id) as + | (LinkedRecord & { + product: DeploymentRecordReference; + environment: DeploymentRecordReference; + intent: DeploymentRecordReference; + artifact?: DeploymentRecordReference; + attestations: DeploymentRecordReference[]; + priorReceipt?: DeploymentRecordReference; + }) + | undefined; + const planBoundDigests = new Set([ + plan.digest, + plan.request.digest, + ...plan.inputs.map((input) => input.digest), + ...plan.rollbackInputs.map((input) => input.digest), + ...plan.providerCapabilityDigests, + ...(request?.attestations.map((attestation) => attestation.digest) ?? []), + ]); + const expectedDigestByKind = new Map([ + ["plan", plan.digest], + ["request", plan.request.digest], + ...(request + ? [ + ["product", request.product.digest], + ["environment", request.environment.digest], + ["intent", request.intent.digest], + ...(request.artifact + ? [["artifact", request.artifact.digest]] + : []), + ...(request.priorReceipt + ? [["prior-receipt", request.priorReceipt.digest]] + : []), + ] as Array<[string, string]> + : []), + ]); + approval.boundInputDigests.forEach(( + binding: { kind: string; digest: string }, + index: number, + ) => { + const expectedDigest = expectedDigestByKind.get(binding.kind); + if (expectedDigest && binding.digest !== expectedDigest) { + issues.push( + `deploymentApprovalDecisions.${approval.id}.boundInputDigests.${index}: ${binding.kind} digest does not match linked plan lineage`, + ); + } else if (!expectedDigest && !planBoundDigests.has(binding.digest)) { + issues.push( + `deploymentApprovalDecisions.${approval.id}.boundInputDigests.${index}: digest is not bound by linked plan ${plan.id}`, + ); + } + }); + }); attempts.forEach((attempt) => { requireLinkedRecord(attempt.plan, planMap, `deploymentAttempts.${attempt.id}.plan`, issues); attempt.approvals.forEach(( @@ -1380,6 +1502,18 @@ export function validateDeploymentContractSet( requireLinkedRecord(receipt.request, requestMap, `deploymentReceipts.${receipt.id}.request`, issues); requireLinkedRecord(receipt.plan, planMap, `deploymentReceipts.${receipt.id}.plan`, issues); requireLinkedRecord(receipt.attempt, attemptMap, `deploymentReceipts.${receipt.id}.attempt`, issues); + requireLinkedRecord(receipt.intent, intentMap, `deploymentReceipts.${receipt.id}.intent`, issues); + const request = requestMap.get(receipt.request.id) as + | (LinkedRecord & { intent: DeploymentRecordReference }) + | undefined; + if ( + request + && !sameDeploymentReference(receipt.intent, request.intent) + ) { + issues.push( + `deploymentReceipts.${receipt.id}.intent: reference does not match linked request intent`, + ); + } receipt.approvals.forEach((approval: LinkedRecord, index: number) => requireLinkedRecord(approval, approvalMap, `deploymentReceipts.${receipt.id}.approvals.${index}`, issues)); receipt.providerReceipts.forEach(( diff --git a/tests/deployment.test.ts b/tests/deployment.test.ts index 66dd02e..360a94c 100644 --- a/tests/deployment.test.ts +++ b/tests/deployment.test.ts @@ -54,6 +54,98 @@ function redigest>(value: T): T { return withDeploymentRecordDigest(value) as T; } +type DeploymentFixtures = ReturnType; + +function recomputePlanDownstream( + fixtures: DeploymentFixtures, + deploymentPlan: DeploymentFixtures["deploymentPlan"], + approvalDraft = clone(fixtures.deploymentApprovalDecision), +) { + approvalDraft.plan = { + schema: deploymentPlan.schema, + id: deploymentPlan.id, + digest: deploymentPlan.digest, + }; + const planBinding = approvalDraft.boundInputDigests.find( + (binding) => binding.kind === "plan", + ); + if (!planBinding) { + throw new Error("fixture approval is missing the plan digest binding"); + } + planBinding.digest = deploymentPlan.digest; + const deploymentApprovalDecision = DeploymentApprovalDecisionSchema.parse( + redigest(approvalDraft), + ); + + const attemptDraft = clone(fixtures.deploymentAttempt); + attemptDraft.plan = { + schema: deploymentPlan.schema, + id: deploymentPlan.id, + digest: deploymentPlan.digest, + }; + attemptDraft.approvals[0]!.decision = { + schema: deploymentApprovalDecision.schema, + id: deploymentApprovalDecision.id, + digest: deploymentApprovalDecision.digest, + }; + const deploymentAttempt = DeploymentAttemptSchema.parse( + redigest(attemptDraft), + ); + + const providerReceiptDraft = clone(fixtures.providerReceipt); + providerReceiptDraft.attempt = { + schema: deploymentAttempt.schema, + id: deploymentAttempt.id, + revision: deploymentAttempt.revision, + digest: deploymentAttempt.digest, + }; + const providerReceipt = ProviderReceiptSchema.parse( + redigest(providerReceiptDraft), + ); + + const receiptDraft = clone(fixtures.deploymentReceipt); + receiptDraft.plan = { + schema: deploymentPlan.schema, + id: deploymentPlan.id, + digest: deploymentPlan.digest, + }; + receiptDraft.approvals = [{ + schema: deploymentApprovalDecision.schema, + id: deploymentApprovalDecision.id, + digest: deploymentApprovalDecision.digest, + }]; + receiptDraft.attempt = { + schema: deploymentAttempt.schema, + id: deploymentAttempt.id, + revision: deploymentAttempt.revision, + digest: deploymentAttempt.digest, + }; + receiptDraft.providerReceipts = [{ + schema: providerReceipt.schema, + id: providerReceipt.id, + digest: providerReceipt.digest, + }]; + const deploymentReceipt = DeploymentReceiptSchema.parse( + redigest(receiptDraft), + ); + + const launchDraft = clone(fixtures.launchEvidence); + launchDraft.deploymentReceipt = { + schema: deploymentReceipt.schema, + id: deploymentReceipt.id, + digest: deploymentReceipt.digest, + }; + const launchEvidence = LaunchEvidenceSchema.parse(redigest(launchDraft)); + + return { + deploymentApprovalDecision, + deploymentAttempt, + providerReceipt, + deploymentReceipt, + launchEvidence, + }; +} + describe("deployment contract records", () => { test("all thirteen registered fixtures parse and retain canonical digests", () => { const fixtures = createDeploymentFixtureSet(); @@ -218,4 +310,102 @@ describe("deployment contract records", () => { true, ); }); + + test("recomputed downstream records cannot swap a required plan input for another request reference", () => { + const fixtures = createDeploymentFixtureSet(); + const contractSet = deploymentFixtureSetToContractSet(fixtures); + + const planDraft = clone(fixtures.deploymentPlan); + const inputIndex = planDraft.inputs.findIndex( + (input) => input.schema === DEPLOYMENT_SCHEMA_IDS.intentSnapshot, + ); + expect(inputIndex).toBeGreaterThanOrEqual(0); + planDraft.inputs[inputIndex] = { + schema: fixtures.artifactAttestation.schema, + id: fixtures.artifactAttestation.id, + digest: fixtures.artifactAttestation.digest, + }; + const deploymentPlan = DeploymentPlanSchema.parse(redigest(planDraft)); + const downstream = recomputePlanDownstream(fixtures, deploymentPlan); + + contractSet.deploymentPlans = [deploymentPlan]; + contractSet.deploymentApprovalDecisions = [ + downstream.deploymentApprovalDecision, + ]; + contractSet.deploymentAttempts = [downstream.deploymentAttempt]; + contractSet.providerReceipts = [downstream.providerReceipt]; + contractSet.deploymentReceipts = [downstream.deploymentReceipt]; + contractSet.launchEvidence = [downstream.launchEvidence]; + + const result = validateDeploymentContractSet(runtimeSchemas, contractSet); + expect(result.issues).toContain( + `deploymentPlans.${deploymentPlan.id}.inputs: input set does not exactly match linked request ${fixtures.deploymentRequest.id}`, + ); + }); + + test("recomputed downstream records cannot bind an approval kind to another lineage digest", () => { + const fixtures = createDeploymentFixtureSet(); + const contractSet = deploymentFixtureSetToContractSet(fixtures); + + const approvalDraft = clone(fixtures.deploymentApprovalDecision); + const bindingIndex = approvalDraft.boundInputDigests.findIndex( + (binding) => binding.kind === "intent", + ); + expect(bindingIndex).toBeGreaterThanOrEqual(0); + approvalDraft.boundInputDigests[bindingIndex]!.digest = + fixtures.deploymentPlan.digest; + const downstream = recomputePlanDownstream( + fixtures, + fixtures.deploymentPlan, + approvalDraft, + ); + + contractSet.deploymentApprovalDecisions = [ + downstream.deploymentApprovalDecision, + ]; + contractSet.deploymentAttempts = [downstream.deploymentAttempt]; + contractSet.providerReceipts = [downstream.providerReceipt]; + contractSet.deploymentReceipts = [downstream.deploymentReceipt]; + contractSet.launchEvidence = [downstream.launchEvidence]; + + const result = validateDeploymentContractSet(runtimeSchemas, contractSet); + expect(result.issues).toContain( + `deploymentApprovalDecisions.${downstream.deploymentApprovalDecision.id}.boundInputDigests.${bindingIndex}: intent digest does not match linked plan lineage`, + ); + }); + + test("recomputed downstream records cannot substitute a receipt intent", () => { + const fixtures = createDeploymentFixtureSet(); + const contractSet = deploymentFixtureSetToContractSet(fixtures); + const alternateIntent = IntentSnapshotSchema.parse(redigest({ + ...clone(fixtures.intentSnapshot), + id: "intent-snapshot-receipt-substitute", + })); + contractSet.intentSnapshots.push(alternateIntent); + + const receiptDraft = clone(fixtures.deploymentReceipt); + receiptDraft.intent = { + schema: alternateIntent.schema, + id: alternateIntent.id, + digest: alternateIntent.digest, + }; + const deploymentReceipt = DeploymentReceiptSchema.parse( + redigest(receiptDraft), + ); + const launchDraft = clone(fixtures.launchEvidence); + launchDraft.deploymentReceipt = { + schema: deploymentReceipt.schema, + id: deploymentReceipt.id, + digest: deploymentReceipt.digest, + }; + const launchEvidence = LaunchEvidenceSchema.parse(redigest(launchDraft)); + + contractSet.deploymentReceipts = [deploymentReceipt]; + contractSet.launchEvidence = [launchEvidence]; + + const result = validateDeploymentContractSet(runtimeSchemas, contractSet); + expect(result.issues).toContain( + `deploymentReceipts.${deploymentReceipt.id}.intent: reference does not match linked request intent`, + ); + }); });