owlrunkit 0.14.0 → 0.15.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.
@@ -21,6 +21,45 @@ const RELEASE_EVIDENCE_FIELDS = Object.freeze([
21
21
  "version",
22
22
  ]);
23
23
 
24
+ const STORED_EVIDENCE_FIELDS = Object.freeze([
25
+ "authorizationGranted",
26
+ "authority",
27
+ "decision",
28
+ "exactSpec",
29
+ "installedBinding",
30
+ "packageName",
31
+ "registryRelease",
32
+ "schemaVersion",
33
+ "status",
34
+ "version",
35
+ ]);
36
+
37
+ const STORED_RELEASE_FIELDS = Object.freeze([
38
+ "integrity",
39
+ "packageName",
40
+ "registry",
41
+ "shasum",
42
+ "tarballUrl",
43
+ "version",
44
+ ]);
45
+
46
+ const STORED_INSTALL_FIELDS = Object.freeze([
47
+ "integrity",
48
+ "packageName",
49
+ "requestedSpec",
50
+ "resolved",
51
+ "version",
52
+ ]);
53
+
54
+ function isRecord(value) {
55
+ return typeof value === "object" && value !== null && !Array.isArray(value);
56
+ }
57
+
58
+ function hasExactFields(value, fields) {
59
+ return isRecord(value)
60
+ && Object.keys(value).sort().join("\n") === [...fields].sort().join("\n");
61
+ }
62
+
24
63
  function decision(policy, issueCodes) {
25
64
  return {
26
65
  schemaVersion: "OwlCodaRunKitRegistryAdoptionDecisionV1",
@@ -45,6 +84,78 @@ export function isCanonicalSha512Integrity(value) {
45
84
  return bytes.length === 64 && bytes.toString("base64") === match[1];
46
85
  }
47
86
 
87
+ export function validateStoredRegistryAdoptionEvidence({
88
+ evidence,
89
+ packageName,
90
+ version,
91
+ localInstall,
92
+ }) {
93
+ const issues = [];
94
+ const exactSpec = `${packageName}@${version}`;
95
+ const expectedTarball = expectedRegistryTarballUrl(packageName, version);
96
+ if (
97
+ !hasExactFields(evidence, STORED_EVIDENCE_FIELDS)
98
+ || evidence.schemaVersion !== "OwlCodaRunKitRegistryAdoptionEvidenceV1"
99
+ || evidence.status !== "adopted"
100
+ || evidence.decision !== "ELIGIBLE"
101
+ || evidence.packageName !== packageName
102
+ || evidence.version !== version
103
+ || evidence.exactSpec !== exactSpec
104
+ || evidence.authorizationGranted !== false
105
+ ) {
106
+ issues.push("adoption_evidence_invalid");
107
+ }
108
+ const release = evidence?.registryRelease;
109
+ if (
110
+ !hasExactFields(release, STORED_RELEASE_FIELDS)
111
+ || release.registry !== OFFICIAL_NPM_REGISTRY
112
+ || release.packageName !== packageName
113
+ || release.version !== version
114
+ || !/^[0-9a-f]{40}$/i.test(release.shasum)
115
+ || !isCanonicalSha512Integrity(release.integrity)
116
+ || release.tarballUrl !== expectedTarball
117
+ ) {
118
+ issues.push("adoption_registry_binding_invalid");
119
+ }
120
+ const installed = evidence?.installedBinding;
121
+ if (
122
+ !hasExactFields(installed, STORED_INSTALL_FIELDS)
123
+ || installed.requestedSpec !== exactSpec
124
+ || installed.packageName !== packageName
125
+ || installed.version !== version
126
+ || installed.integrity !== release?.integrity
127
+ || installed.resolved !== expectedTarball
128
+ ) {
129
+ issues.push("adoption_installed_binding_invalid");
130
+ }
131
+ if (
132
+ !hasExactFields(evidence?.authority, ["foreignProjectWrite", "git", "release"])
133
+ || evidence.authority.git !== false
134
+ || evidence.authority.release !== false
135
+ || evidence.authority.foreignProjectWrite !== false
136
+ ) {
137
+ issues.push("adoption_authority_invalid");
138
+ }
139
+ if (
140
+ localInstall !== undefined
141
+ && (
142
+ localInstall.status !== "bound"
143
+ || localInstall.requestedSpec !== exactSpec
144
+ || localInstall.packageName !== packageName
145
+ || localInstall.version !== version
146
+ || localInstall.integrity !== release?.integrity
147
+ || localInstall.resolved !== expectedTarball
148
+ )
149
+ ) {
150
+ issues.push("adoption_local_install_drift");
151
+ }
152
+ const issueCodes = [...new Set(issues)].sort();
153
+ return {
154
+ valid: issueCodes.length === 0,
155
+ issueCodes,
156
+ };
157
+ }
158
+
48
159
  function validReleaseEvidence(policy, release) {
49
160
  if (
50
161
  policy.registry !== OFFICIAL_NPM_REGISTRY
@@ -10,6 +10,7 @@ import {
10
10
  OFFICIAL_NPM_REGISTRY,
11
11
  evaluateRegistryAdoption,
12
12
  } from "./registry-adoption-gate.mjs";
13
+ import { CORE_VERSION } from "./core-contract.mjs";
13
14
  import {
14
15
  readLocalInstallBinding,
15
16
  readRegistryExact,
@@ -18,7 +19,7 @@ import {
18
19
  import { writeJsonExclusiveAtomically } from "./provenance-common.mjs";
19
20
 
20
21
  const PACKAGE_NAME = "owlrunkit";
21
- const CANDIDATE_VERSION = "0.14.0";
22
+ const CANDIDATE_VERSION = CORE_VERSION;
22
23
  const EXACT_SPEC = `${PACKAGE_NAME}@${CANDIDATE_VERSION}`;
23
24
 
24
25
  const POLICY = Object.freeze({
@@ -15,6 +15,7 @@ import {
15
15
  import path from "node:path";
16
16
 
17
17
  import {
18
+ CORE_VERSION,
18
19
  RUNTIME_ROOT,
19
20
  acceptedCloseoutVerificationIssues,
20
21
  createCoreArtifact,
@@ -73,6 +74,8 @@ import {
73
74
  } from "./profile-onboarding.mjs";
74
75
  import {
75
76
  formatDoctorHuman,
77
+ readAdoptionReadiness,
78
+ readProfileLauncherReadiness,
76
79
  runDoctor,
77
80
  } from "./onboarding-doctor.mjs";
78
81
  import {
@@ -81,7 +84,7 @@ import {
81
84
  } from "./registry-adoption.mjs";
82
85
  import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
83
86
 
84
- const TOP_LEVEL_HELP = `OwlRunKit 0.14.0
87
+ const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
85
88
 
86
89
  Usage:
87
90
  owlrunkit <command> [options]
@@ -89,7 +92,7 @@ Usage:
89
92
  Start here:
90
93
  owlrunkit doctor --workspace .
91
94
  owlrunkit profiles detect --workspace . --dry-run
92
- owlrunkit adopt --workspace . --exact owlrunkit@0.14.0
95
+ owlrunkit adopt --workspace . --exact owlrunkit@${CORE_VERSION}
93
96
 
94
97
  Quick Verification
95
98
  owlrunkit quick-verify --workspace . -- <command> [args...]
@@ -121,23 +124,61 @@ function withHumanOutput(result, humanOutput) {
121
124
  return result;
122
125
  }
123
126
 
124
- function onboardingProjection() {
127
+ function profilesReadiness(root) {
128
+ if (!root) return { valid: false, launcherWarnings: [] };
129
+ try {
130
+ const validation = validateProfiles({ workspaceRoot: root });
131
+ const launchers = readProfileLauncherReadiness({ workspaceRoot: root });
132
+ return {
133
+ valid: validation.valid === true && launchers.ready,
134
+ launcherWarnings: launchers.launcherWarnings,
135
+ };
136
+ } catch {
137
+ return { valid: false, launcherWarnings: [] };
138
+ }
139
+ }
140
+
141
+ function onboardingProjection(root, recovery = null) {
142
+ const profiles = profilesReadiness(root);
143
+ const adoption = root
144
+ ? readAdoptionReadiness({ workspaceRoot: root })
145
+ : { status: "missing" };
146
+ const profilesReady = profiles.valid;
147
+ const adoptionReady = adoption.status === "ok";
148
+ if (profilesReady && adoptionReady) {
149
+ return {
150
+ nextAllowedAction: recovery?.nextAllowedAction ?? "plan_new_execution",
151
+ completed: true,
152
+ steps: [],
153
+ };
154
+ }
155
+ const steps = [
156
+ {
157
+ id: "doctor",
158
+ command: "owlrunkit doctor --workspace .",
159
+ },
160
+ ...(!profilesReady
161
+ ? profiles.launcherWarnings.length > 0
162
+ ? [{
163
+ id: "profile_launchers_review",
164
+ command: "owlrunkit doctor --workspace .",
165
+ }]
166
+ : [{
167
+ id: "profiles_detect",
168
+ command: "owlrunkit profiles detect --workspace . --dry-run",
169
+ }]
170
+ : []),
171
+ ...(!adoptionReady
172
+ ? [{
173
+ id: "adopt_or_start",
174
+ command: `owlrunkit adopt --workspace . --exact owlrunkit@${CORE_VERSION} or owlrunkit start`,
175
+ }]
176
+ : []),
177
+ ];
125
178
  return {
126
179
  nextAllowedAction: "run_onboarding_diagnostics",
127
- steps: [
128
- {
129
- id: "doctor",
130
- command: "owlrunkit doctor --workspace .",
131
- },
132
- {
133
- id: "profiles_detect",
134
- command: "owlrunkit profiles detect --workspace . --dry-run",
135
- },
136
- {
137
- id: "adopt_or_start",
138
- command: "owlrunkit adopt --workspace . --exact owlrunkit@0.14.0 or owlrunkit start",
139
- },
140
- ],
180
+ completed: false,
181
+ steps,
141
182
  };
142
183
  }
143
184
 
@@ -666,10 +707,11 @@ function closeoutGateRejected(runId, decision, issues) {
666
707
  }
667
708
 
668
709
  async function initialize(options) {
669
- const initialized = await initializeProjectRunKit({ workspaceRoot: workspace(options) });
710
+ const root = workspace(options);
711
+ const initialized = await initializeProjectRunKit({ workspaceRoot: root });
670
712
  const result = {
671
713
  ...initialized,
672
- onboarding: onboardingProjection(),
714
+ onboarding: onboardingProjection(root),
673
715
  nextAllowedAction: "run_onboarding_diagnostics",
674
716
  };
675
717
  if (options.json === true) return result;
@@ -681,7 +723,7 @@ async function initialize(options) {
681
723
  "Next:",
682
724
  "1. owlrunkit doctor --workspace .",
683
725
  "2. owlrunkit profiles detect --workspace . --dry-run",
684
- "3. owlrunkit adopt --workspace . --exact owlrunkit@0.14.0 or owlrunkit start",
726
+ `3. owlrunkit adopt --workspace . --exact owlrunkit@${CORE_VERSION} or owlrunkit start`,
685
727
  "",
686
728
  ].join("\n"),
687
729
  );
@@ -936,7 +978,7 @@ function inspect(options) {
936
978
  execution: executions.find(execution => execution.runId === requestedRunId),
937
979
  }
938
980
  : { mode: "summary" };
939
- return { ...result, summary, view, onboarding: onboardingProjection() };
981
+ return { ...result, summary, view, onboarding: onboardingProjection(root, recovery) };
940
982
  }
941
983
 
942
984
  function closeout(options) {
@@ -1128,9 +1170,9 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
1128
1170
  return withHumanOutput({
1129
1171
  status: "version",
1130
1172
  exitCode: 0,
1131
- version: "0.14.0",
1173
+ version: CORE_VERSION,
1132
1174
  authorizationGranted: false,
1133
- }, "owlrunkit 0.14.0\n");
1175
+ }, `owlrunkit ${CORE_VERSION}\n`);
1134
1176
  }
1135
1177
  const separatorIndex = rest.indexOf("--");
1136
1178
  if (separatorIndex >= 0 && command !== "verify" && command !== "quick-verify") {
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://owlcoda.dev/schemas/runkit/verification-finalize-attempt-v1.json",
4
+ "title": "OwlCoda RunKit Verification Finalize Attempt V1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schemaVersion",
9
+ "runId",
10
+ "verificationId",
11
+ "status",
12
+ "gateStatus",
13
+ "finalizeRequestPath",
14
+ "finalizeRequestSha256",
15
+ "result",
16
+ "authorizationGranted"
17
+ ],
18
+ "properties": {
19
+ "schemaVersion": {
20
+ "const": "OwlCodaRunKitVerificationFinalizeAttemptV1"
21
+ },
22
+ "runId": {
23
+ "type": "string",
24
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
25
+ },
26
+ "verificationId": {
27
+ "type": "string",
28
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
29
+ },
30
+ "status": {
31
+ "const": "rejected"
32
+ },
33
+ "gateStatus": {
34
+ "type": "string",
35
+ "minLength": 1
36
+ },
37
+ "finalizeRequestPath": {
38
+ "type": "string",
39
+ "minLength": 1
40
+ },
41
+ "finalizeRequestSha256": {
42
+ "type": "string",
43
+ "pattern": "^[a-f0-9]{64}$"
44
+ },
45
+ "result": {
46
+ "type": "object"
47
+ },
48
+ "authorizationGranted": {
49
+ "const": false
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://owlcoda.dev/schemas/runkit/verification-preflight-v1.json",
4
+ "title": "OwlCoda RunKit Verification Preflight V1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schemaVersion",
9
+ "runId",
10
+ "verificationId",
11
+ "status",
12
+ "issueCode",
13
+ "executable",
14
+ "commandArgvSha256",
15
+ "authorizationGranted"
16
+ ],
17
+ "properties": {
18
+ "schemaVersion": {
19
+ "const": "OwlCodaRunKitVerificationPreflightV1"
20
+ },
21
+ "runId": {
22
+ "type": "string",
23
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
24
+ },
25
+ "verificationId": {
26
+ "type": "string",
27
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
28
+ },
29
+ "status": {
30
+ "const": "rejected"
31
+ },
32
+ "issueCode": {
33
+ "enum": [
34
+ "verify_executable_absolute_path_required",
35
+ "verify_executable_missing",
36
+ "verify_executable_not_regular_file",
37
+ "verify_executable_symlink_rejected"
38
+ ]
39
+ },
40
+ "executable": {
41
+ "type": "string",
42
+ "minLength": 1
43
+ },
44
+ "commandArgvSha256": {
45
+ "type": "string",
46
+ "pattern": "^[a-f0-9]{64}$"
47
+ },
48
+ "authorizationGranted": {
49
+ "const": false
50
+ }
51
+ }
52
+ }