owlrunkit 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +274 -66
  3. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +223 -117
  4. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  5. package/integrations/codex/skills/owlcoda-runkit/assets/templates/ready-for-commit-request.json +2 -2
  6. package/package.json +2 -2
  7. package/packages/attest/distribution-manifest-v1.json +10 -0
  8. package/packages/attest/src/quick.mjs +10 -0
  9. package/registry-release-policy-v1.json +8 -2
  10. package/sbom.spdx.json +5 -5
  11. package/scripts/runkit-contract/assurance-router.mjs +119 -0
  12. package/scripts/runkit-contract/core-contract.mjs +250 -115
  13. package/scripts/runkit-contract/core-successor.mjs +2043 -0
  14. package/scripts/runkit-contract/deployment-workflow.mjs +2040 -0
  15. package/scripts/runkit-contract/finalize.mjs +242 -21
  16. package/scripts/runkit-contract/fleet-discovery.mjs +456 -0
  17. package/scripts/runkit-contract/formal-workflow.mjs +850 -0
  18. package/scripts/runkit-contract/human-status.mjs +553 -0
  19. package/scripts/runkit-contract/inspect-presentation.mjs +25 -8
  20. package/scripts/runkit-contract/install-codex-skill.mjs +73 -30
  21. package/scripts/runkit-contract/lease-lifecycle.mjs +8 -2
  22. package/scripts/runkit-contract/lifecycle-orchestration.mjs +135 -12
  23. package/scripts/runkit-contract/onboarding-doctor.mjs +43 -90
  24. package/scripts/runkit-contract/owner-authority-trust.mjs +230 -0
  25. package/scripts/runkit-contract/owner-deployment-decision.mjs +385 -0
  26. package/scripts/runkit-contract/profile-onboarding.mjs +841 -13
  27. package/scripts/runkit-contract/project-cli-resolver.mjs +701 -0
  28. package/scripts/runkit-contract/project-control-parser.mjs +830 -0
  29. package/scripts/runkit-contract/project-control-state.mjs +28 -0
  30. package/scripts/runkit-contract/provenance-common.mjs +19 -2
  31. package/scripts/runkit-contract/ready-for-commit.mjs +330 -18
  32. package/scripts/runkit-contract/remote-deployment.mjs +1596 -0
  33. package/scripts/runkit-contract/remote-process-adapter.mjs +177 -0
  34. package/scripts/runkit-contract/runkit-bootstrap.mjs +131 -0
  35. package/scripts/runkit-contract/runkit-cli.mjs +1097 -21
  36. package/scripts/runkit-contract/schemas/assurance-route-v1.schema.json +26 -0
  37. package/scripts/runkit-contract/schemas/core-successor-batch-receipt-v1.schema.json +126 -0
  38. package/scripts/runkit-contract/schemas/core-successor-plan-v1.schema.json +155 -0
  39. package/scripts/runkit-contract/schemas/core-successor-project-success-receipt-v1.schema.json +72 -0
  40. package/scripts/runkit-contract/schemas/deployment-execute-request-v1.schema.json +63 -0
  41. package/scripts/runkit-contract/schemas/deployment-lineage-v1.schema.json +292 -0
  42. package/scripts/runkit-contract/schemas/deployment-prepare-receipt-v1.schema.json +140 -0
  43. package/scripts/runkit-contract/schemas/fleet-discovery-v1.schema.json +31 -0
  44. package/scripts/runkit-contract/schemas/fleet-manifest-v1.schema.json +20 -0
  45. package/scripts/runkit-contract/schemas/fleet-root-registry-v1.schema.json +34 -0
  46. package/scripts/runkit-contract/schemas/human-status-v1.schema.json +102 -0
  47. package/scripts/runkit-contract/schemas/owner-authority-trust-v1.schema.json +66 -0
  48. package/scripts/runkit-contract/schemas/owner-deployment-authority-v1.schema.json +46 -0
  49. package/scripts/runkit-contract/schemas/owner-deployment-authority-v2.schema.json +94 -0
  50. package/scripts/runkit-contract/schemas/owner-deployment-decision-v1.schema.json +102 -0
  51. package/scripts/runkit-contract/schemas/owner-migration-authority-v1.schema.json +33 -0
  52. package/scripts/runkit-contract/schemas/owner-migration-authority-v2.schema.json +67 -0
  53. package/scripts/runkit-contract/schemas/profile-apply-receipt-v1.schema.json +32 -0
  54. package/scripts/runkit-contract/schemas/profile-detection-v2.schema.json +145 -0
  55. package/scripts/runkit-contract/schemas/ready-for-commit-v2.schema.json +37 -0
  56. package/scripts/runkit-contract/schemas/remote-deployment-manifest-v1.schema.json +379 -0
  57. package/scripts/runkit-contract/schemas/remote-deployment-result-v1.schema.json +153 -0
  58. package/scripts/runkit-contract/schemas/remote-deployment-stage-journal-v1.schema.json +183 -0
  59. package/scripts/runkit-contract/schemas/remote-target-v1.schema.json +32 -0
  60. package/scripts/runkit-contract/schemas/source-candidate-v2.schema.json +152 -0
  61. package/scripts/runkit-contract/schemas/verification-receipt-v2.schema.json +13 -0
  62. package/scripts/runkit-contract/snapshot.mjs +1 -1
  63. package/scripts/runkit-contract/source-candidate.mjs +1382 -0
  64. package/scripts/runkit-contract/ssh-remote-adapter.mjs +1184 -0
  65. package/scripts/runkit-contract/sync-core016-release-identity.mjs +161 -0
  66. package/scripts/runkit-contract/templates/assurance-request.json +13 -0
  67. package/scripts/runkit-contract/templates/core-successor-owner-authority.json +15 -0
  68. package/scripts/runkit-contract/templates/deployment-execute-request.json +39 -0
  69. package/scripts/runkit-contract/templates/deployment-owner-authority.json +23 -0
  70. package/scripts/runkit-contract/templates/deployment-owner-decision.json +26 -0
  71. package/scripts/runkit-contract/templates/fleet-manifest.json +8 -0
  72. package/scripts/runkit-contract/templates/fleet-root-registry.json +8 -0
  73. package/scripts/runkit-contract/templates/owner-authority-trust.json +16 -0
  74. package/scripts/runkit-contract/templates/ready-for-commit-request.json +2 -2
  75. package/scripts/runkit-contract/templates/remote-deployment-manifest.json +108 -0
  76. package/scripts/runkit-contract/verification-receipt-gate.mjs +28 -0
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ readFileSync,
5
+ renameSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ import { currentCoreIdentity } from "./core-contract.mjs";
12
+
13
+ const RELEASE_FILES = Object.freeze({
14
+ packageManifest: "packages/runkit/package.json",
15
+ attestManifest: "packages/attest/distribution-manifest-v1.json",
16
+ attestRuntime: "packages/attest/src/quick.mjs",
17
+ skillMarkdown: "integrations/codex/skills/owlcoda-runkit/SKILL.md",
18
+ skillConfig:
19
+ "integrations/codex/skills/owlcoda-runkit/assets/templates/config.json",
20
+ });
21
+
22
+ const ATTEST_RUNTIME_CORE016 =
23
+ /(coreVersion:\s*"0\.16\.0",\s*coreManifestSha256:\s*")sha256:[a-f0-9]{64}("\s*,?)/gu;
24
+
25
+ function readJson(ref) {
26
+ return JSON.parse(readFileSync(ref, "utf8"));
27
+ }
28
+
29
+ function bytes(value) {
30
+ return `${JSON.stringify(value, null, 2)}\n`;
31
+ }
32
+
33
+ function writeAtomic(ref, value) {
34
+ const temporary = `${ref}.sync-${process.pid}`;
35
+ writeFileSync(temporary, value, { flag: "wx" });
36
+ renameSync(temporary, ref);
37
+ }
38
+
39
+ function exactCore(actual, expected, includeSourceRef) {
40
+ return actual?.contractVersion === expected.contractVersion
41
+ && actual?.coreVersion === expected.coreVersion
42
+ && actual?.coreManifestSha256 === expected.coreManifestSha256
43
+ && (
44
+ !includeSourceRef
45
+ || actual?.coreSourceRef === expected.coreSourceRef
46
+ );
47
+ }
48
+
49
+ export function synchronizeCore016ReleaseIdentityV1({
50
+ repositoryRoot,
51
+ core,
52
+ write = false,
53
+ }) {
54
+ const root = path.resolve(repositoryRoot);
55
+ if (
56
+ core?.contractVersion !== "0.2"
57
+ || core?.coreVersion !== "0.16.0"
58
+ || !/^sha256:[a-f0-9]{64}$/u.test(
59
+ core?.coreManifestSha256 ?? "",
60
+ )
61
+ || core?.coreSourceRef !== `artifact:${core.coreManifestSha256}`
62
+ ) throw new Error("core016_release_identity_invalid");
63
+ const refs = Object.fromEntries(Object.entries(RELEASE_FILES).map(
64
+ ([key, relative]) => [key, path.join(root, relative)],
65
+ ));
66
+ const packageManifest = readJson(refs.packageManifest);
67
+ if (
68
+ packageManifest.name !== "owlrunkit"
69
+ || packageManifest.version !== "0.16.0"
70
+ ) throw new Error("core016_release_package_invalid");
71
+ const attestManifest = readJson(refs.attestManifest);
72
+ const candidateIndexes = attestManifest.supportedProducerCoreIdentities
73
+ ?.map((identity, index) => ({ identity, index }))
74
+ .filter(({ identity }) => identity?.coreVersion === "0.16.0") ?? [];
75
+ if (candidateIndexes.length !== 1) {
76
+ throw new Error("core016_release_attest_candidate_ambiguous");
77
+ }
78
+ const attestRuntime = readFileSync(refs.attestRuntime, "utf8");
79
+ const runtimeMatches = [...attestRuntime.matchAll(ATTEST_RUNTIME_CORE016)];
80
+ if (runtimeMatches.length !== 1) {
81
+ throw new Error("core016_release_attest_runtime_candidate_ambiguous");
82
+ }
83
+ const skillMarkdown = readFileSync(refs.skillMarkdown, "utf8");
84
+ const skillHashes = skillMarkdown.match(/sha256:[a-f0-9]{64}/gu) ?? [];
85
+ if (skillHashes.length !== 1) {
86
+ throw new Error("core016_release_skill_identity_ambiguous");
87
+ }
88
+ const skillConfig = readJson(refs.skillConfig);
89
+ const mismatches = [];
90
+ if (!exactCore(candidateIndexes[0].identity, core, false)) {
91
+ mismatches.push("attest");
92
+ }
93
+ if (!runtimeMatches[0][0].includes(core.coreManifestSha256)) {
94
+ mismatches.push("attest_runtime");
95
+ }
96
+ if (skillHashes[0] !== core.coreManifestSha256) {
97
+ mismatches.push("skill_markdown");
98
+ }
99
+ if (!exactCore(skillConfig.core, core, true)) {
100
+ mismatches.push("skill_config");
101
+ }
102
+ if (write && mismatches.length > 0) {
103
+ attestManifest.supportedProducerCoreIdentities[
104
+ candidateIndexes[0].index
105
+ ] = {
106
+ contractVersion: core.contractVersion,
107
+ coreVersion: core.coreVersion,
108
+ coreManifestSha256: core.coreManifestSha256,
109
+ };
110
+ writeAtomic(refs.attestManifest, bytes(attestManifest));
111
+ writeAtomic(
112
+ refs.attestRuntime,
113
+ attestRuntime.replace(
114
+ ATTEST_RUNTIME_CORE016,
115
+ `$1${core.coreManifestSha256}$2`,
116
+ ),
117
+ );
118
+ writeAtomic(
119
+ refs.skillMarkdown,
120
+ skillMarkdown.replace(skillHashes[0], core.coreManifestSha256),
121
+ );
122
+ writeAtomic(refs.skillConfig, bytes({
123
+ ...skillConfig,
124
+ core: structuredClone(core),
125
+ }));
126
+ }
127
+ return {
128
+ status: mismatches.length === 0 ? "exact" : write ? "synchronized" : "drifted",
129
+ core: structuredClone(core),
130
+ mismatches,
131
+ changed: write ? mismatches : [],
132
+ };
133
+ }
134
+
135
+ function main(argv) {
136
+ const write = argv.includes("--write");
137
+ const rootIndex = argv.indexOf("--repository-root");
138
+ const repositoryRoot = rootIndex === -1
139
+ ? path.resolve(fileURLToPath(new URL("../..", import.meta.url)))
140
+ : argv[rootIndex + 1];
141
+ if (!repositoryRoot) throw new Error("repository_root_required");
142
+ const result = synchronizeCore016ReleaseIdentityV1({
143
+ repositoryRoot,
144
+ core: currentCoreIdentity(),
145
+ write,
146
+ });
147
+ process.stdout.write(`${JSON.stringify(result)}\n`);
148
+ if (!write && result.status !== "exact") process.exitCode = 2;
149
+ }
150
+
151
+ if (process.argv[1]
152
+ && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
153
+ try {
154
+ main(process.argv.slice(2));
155
+ } catch (error) {
156
+ process.stderr.write(
157
+ `${error instanceof Error ? error.stack : String(error)}\n`,
158
+ );
159
+ process.exitCode = 1;
160
+ }
161
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "needsDurableEvidence": true,
3
+ "needsFormalAcceptance": false,
4
+ "mayMutateProject": false,
5
+ "externalSideEffects": false,
6
+ "longRunning": false,
7
+ "interruptionRecovery": false,
8
+ "dirtyParallelWorkspace": false,
9
+ "exactCommandCount": 1,
10
+ "writerCount": 0,
11
+ "riskCategories": [],
12
+ "authorizationGranted": false
13
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitOwnerMigrationAuthorityV2",
3
+ "authorityId": "replace-with-owner-authority-id",
4
+ "decision": "approved",
5
+ "scope": "migrate_declared_core_successor_fleet",
6
+ "planSha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
7
+ "fromCoreSetSha256": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
8
+ "toCoreManifestSha256": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
9
+ "fleetManifestSha256": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
10
+ "signerKeyId": "replace-with-owner-key-id",
11
+ "signatureAlgorithm": "ed25519",
12
+ "authorizationGranted": false,
13
+ "authoritySha256": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
14
+ "signature": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
15
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitDeploymentExecuteRequestV1",
3
+ "executeRunId": "replace-with-execute-run-id",
4
+ "executeGoal": {
5
+ "path": ".owlcoda/runkit/executions/replace-with-execute-run-id/goal-contract.json",
6
+ "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
7
+ },
8
+ "prepareReceiptSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
9
+ "target": {
10
+ "schemaVersion": "OwlCodaRunKitRemoteTargetV1",
11
+ "targetId": "replace-with-target-id",
12
+ "environment": "production",
13
+ "host": "replace.example.invalid",
14
+ "port": 22,
15
+ "user": "deploy",
16
+ "hostKeySha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
17
+ "machineIdentitySha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
18
+ },
19
+ "ownerAuthority": {
20
+ "path": "authorities/replace-with-execute-run-id.json",
21
+ "sha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
22
+ },
23
+ "ownerDecision": {
24
+ "path": "authorities/replace-with-owner-decision-id.json",
25
+ "sha256": "1111111111111111111111111111111111111111111111111111111111111111"
26
+ },
27
+ "ownerDecisionSnapshot": {
28
+ "path": ".owlcoda/runkit/deployments/replace-with-execute-run-id/owner-decision-snapshot.json",
29
+ "sha256": "2222222222222222222222222222222222222222222222222222222222222222"
30
+ },
31
+ "workItemId": "deployment-execute",
32
+ "profileId": "deployment",
33
+ "resourcePreflight": {
34
+ "path": ".owlcoda/runkit/executions/replace-with-execute-run-id/resource-preflights/replace-with-preflight-id.json",
35
+ "sha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
36
+ },
37
+ "deploy": true,
38
+ "destructive": false
39
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitOwnerDeploymentAuthorityV2",
3
+ "authorityId": "replace-with-owner-authority-id",
4
+ "decision": "approved",
5
+ "scope": "execute_exact_remote_deployment",
6
+ "executeRunId": "replace-with-execute-run-id",
7
+ "prepareReceiptSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
8
+ "targetSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
9
+ "artifactSha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
10
+ "remoteManifestFileSha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
11
+ "remoteDeploymentIntentSha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
12
+ "ownerDecisionId": "replace-with-owner-decision-id",
13
+ "ownerDecisionSha256": "1111111111111111111111111111111111111111111111111111111111111111",
14
+ "signerKeyId": "replace-with-owner-key-id",
15
+ "signatureAlgorithm": "ed25519",
16
+ "permissions": {
17
+ "deploy": true,
18
+ "destructive": false
19
+ },
20
+ "authorizationGranted": false,
21
+ "authoritySha256": "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
22
+ "signature": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
23
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitOwnerDeploymentDecisionV1",
3
+ "decisionId": "replace-with-owner-decision-id",
4
+ "decisionVersion": 1,
5
+ "provenance": {
6
+ "kind": "owner_explicit",
7
+ "sourceRef": "replace-with-owner-controlled-source-ref",
8
+ "recordedAt": "2026-08-01T00:00:00.000Z"
9
+ },
10
+ "project": {
11
+ "projectId": "replace-with-project-id",
12
+ "scope": "replace-with-deployment-scope"
13
+ },
14
+ "supersedesDecisionSha256": null,
15
+ "deploymentMode": "clean_install",
16
+ "existingProjectAssets": "replace",
17
+ "legacyRollbackAllowed": false,
18
+ "dataAuthority": {
19
+ "mode": "initialize_new",
20
+ "sourceRef": "replace-with-owner-controlled-data-authority-ref"
21
+ },
22
+ "serviceActivationAuthorized": false,
23
+ "baselineCutAuthorized": false,
24
+ "destructiveScope": [],
25
+ "decisionSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
26
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitFleetManifestV1",
3
+ "skillName": "owlcoda-runkit",
4
+ "workspaceRoots": [
5
+ "/replace/with/absolute/project/root"
6
+ ],
7
+ "authorizationGranted": false
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitFleetRootRegistryV1",
3
+ "coverageRoots": [
4
+ "/absolute/path/to/fleet"
5
+ ],
6
+ "authorizationGranted": false,
7
+ "registrySha256": "sha256:270e2fb1accb0e5a891f697c5a483b52881289849cfb75b4cd54a0443bcac8ec"
8
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitOwnerAuthorityTrustV1",
3
+ "keys": [
4
+ {
5
+ "keyId": "replace-with-owner-key-id",
6
+ "algorithm": "ed25519",
7
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nreplace-with-ed25519-public-key\n-----END PUBLIC KEY-----\n",
8
+ "publicKeySha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
9
+ "purposes": [
10
+ "core_successor",
11
+ "remote_deployment"
12
+ ],
13
+ "status": "active"
14
+ }
15
+ ]
16
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
- "schemaVersion": "OwlCodaRunKitReadyForCommitRequestV1",
3
- "deliveryPacketPath": ".owlcoda/runkit/executions/replace-with-run-id/delivery-packets/replace-with-packet.json",
2
+ "schemaVersion": "OwlCodaRunKitReadyForCommitRequestV2",
3
+ "sourceCandidatePath": ".owlcoda/runkit/executions/replace-with-run-id/source-candidates/replace-with-candidate.json",
4
4
  "verificationGateInputPath": ".owlcoda/runkit/executions/replace-with-run-id/verification-receipts/replace-with-receipt/verification-gate-input.json",
5
5
  "roots": [
6
6
  {
@@ -0,0 +1,108 @@
1
+ {
2
+ "schemaVersion": "OwlCodaRunKitRemoteDeploymentManifestV1",
3
+ "deploymentId": "replace-with-deployment-id",
4
+ "deploymentLineageSha256": null,
5
+ "mode": "first",
6
+ "ownerDecision": {
7
+ "decisionId": "replace-with-owner-decision-id",
8
+ "decisionVersion": 1,
9
+ "decisionSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
10
+ "deploymentMode": "clean_install",
11
+ "existingProjectAssets": "replace",
12
+ "legacyRollbackAllowed": false,
13
+ "dataAuthority": {
14
+ "mode": "initialize_new",
15
+ "sourceRef": "replace-with-owner-controlled-data-authority-ref"
16
+ },
17
+ "serviceActivationAuthorized": false,
18
+ "baselineCutAuthorized": false,
19
+ "destructiveScope": []
20
+ },
21
+ "serviceActivation": false,
22
+ "baselineCut": false,
23
+ "target": {
24
+ "schemaVersion": "OwlCodaRunKitRemoteTargetV1",
25
+ "targetId": "replace-with-target-id",
26
+ "environment": "production",
27
+ "host": "replace.example.invalid",
28
+ "port": 22,
29
+ "user": "deploy",
30
+ "hostKeySha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
31
+ "machineIdentitySha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
32
+ },
33
+ "adapter": {
34
+ "kind": "builtin_ssh",
35
+ "adapterId": "builtin-ssh-v1",
36
+ "version": "1.0.0",
37
+ "executable": "/replace/with/exact/owlrunkit/scripts/runkit-contract/ssh-remote-adapter.mjs",
38
+ "sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
39
+ "knownHostsPath": "/replace/with/exact/project/known_hosts",
40
+ "sshExecutable": "/usr/bin/ssh",
41
+ "sshExecutableSha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
42
+ "remoteHelper": {
43
+ "path": "/usr/local/libexec/owlrunkit-remote-helper",
44
+ "protocol": "OwlCodaRunKitSshRemoteHelperV1",
45
+ "version": "1.0.0",
46
+ "capabilities": [
47
+ "execute",
48
+ "reconcile"
49
+ ]
50
+ },
51
+ "authentication": {
52
+ "mode": "agent",
53
+ "identityFile": null
54
+ },
55
+ "stageContracts": {
56
+ "install": {
57
+ "archiveFormat": "tar_gzip",
58
+ "releaseRoot": "/opt/owlapp/releases",
59
+ "currentSymlink": "/opt/owlapp/current"
60
+ },
61
+ "systemd": {
62
+ "unitName": "owlapp.service",
63
+ "unitFile": {
64
+ "sourcePath": "deploy/owlapp.service",
65
+ "destinationPath": "/etc/systemd/system/owlapp.service",
66
+ "sha256": "1111111111111111111111111111111111111111111111111111111111111111"
67
+ },
68
+ "daemonReload": true,
69
+ "enable": true,
70
+ "restart": true
71
+ },
72
+ "nginx": {
73
+ "siteName": "owlapp",
74
+ "configFile": {
75
+ "sourcePath": "deploy/owlapp.nginx.conf",
76
+ "destinationPath": "/etc/nginx/sites-available/owlapp.conf",
77
+ "sha256": "2222222222222222222222222222222222222222222222222222222222222222"
78
+ },
79
+ "enabledLinkPath": "/etc/nginx/sites-enabled/owlapp.conf",
80
+ "configTest": true,
81
+ "reload": true
82
+ },
83
+ "smoke": {
84
+ "checks": [
85
+ {
86
+ "checkId": "service-active",
87
+ "kind": "systemd_active",
88
+ "unitName": "owlapp.service"
89
+ }
90
+ ]
91
+ }
92
+ }
93
+ },
94
+ "credentialRef": "agent:replace/with/credential-reference",
95
+ "artifact": {
96
+ "path": "dist/replace-with-artifact.tgz",
97
+ "sha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
98
+ "size": 0,
99
+ "mediaType": "application/gzip"
100
+ },
101
+ "upload": {
102
+ "remotePath": "/srv/releases/replace-with-artifact.tgz",
103
+ "createOnly": true
104
+ },
105
+ "priorDeployment": null,
106
+ "expectedRemoteFiles": [],
107
+ "deletionAllowlist": []
108
+ }
@@ -51,6 +51,33 @@ function isRisk(value) {
51
51
  ]).has(category));
52
52
  }
53
53
 
54
+ function validateSourceArtifactShape(receipt, sourceGate) {
55
+ if (receipt.sourceArtifact === undefined) return [];
56
+ const artifact = receipt.sourceArtifact;
57
+ if (
58
+ !isRecord(artifact)
59
+ || !new Set(["delivery_packet_v1", "source_candidate_v2"])
60
+ .has(artifact.kind)
61
+ || artifact.runId !== receipt.runId
62
+ || typeof artifact.path !== "string"
63
+ || artifact.path.length === 0
64
+ || artifact.path.startsWith("/")
65
+ || artifact.path.split("/").some(segment => (
66
+ segment.length === 0 || segment === "." || segment === ".."
67
+ ))
68
+ || !isSha256(artifact.sha256)
69
+ || !isSha256(artifact.sourceFingerprint)
70
+ || artifact.sourceFingerprint !== receipt.sourceFingerprint
71
+ || artifact.sourceFingerprint !== sourceGate?.recomputedFingerprint
72
+ ) {
73
+ return [issue(
74
+ "source_artifact_binding_malformed",
75
+ "sourceArtifact must exactly bind the active run, source bytes, path, and fingerprint.",
76
+ )];
77
+ }
78
+ return [];
79
+ }
80
+
54
81
  function sameRisk(left, right) {
55
82
  return left?.riskMode === right?.riskMode
56
83
  && JSON.stringify(left?.riskCategories) === JSON.stringify(right?.riskCategories);
@@ -425,6 +452,7 @@ export function validateVerificationReceiptGate({
425
452
  if (commandReceiptShapeIssues.length > 0) {
426
453
  return malformedResult(commandReceiptShapeIssues, lineage);
427
454
  }
455
+ issues.push(...validateSourceArtifactShape(activeReceipt, sourceGate));
428
456
 
429
457
  if (
430
458
  activeReceipt.sourceFingerprint.toLowerCase()