owlrunkit 0.18.1 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +85 -19
- package/docs/architecture/OWLCODA_RUNKIT_018_PROJECT_DRIVER_PRODUCT_DEFINITION.md +16 -5
- package/docs/architecture/OWLCODA_RUNKIT_USAGE_MODE_SELECTION_PRODUCT_DECISION_20260811.md +78 -4
- package/docs/architecture/OWLCODA_RUN_KIT_CONTRACT_V0_2.md +7 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +28 -9
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.1.md +160 -0
- package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.2.md +545 -0
- package/package.json +1 -1
- package/packages/attest/README.md +4 -3
- package/packages/attest/consumer-surface-v1.json +1 -0
- package/packages/attest/distribution-manifest-v1.json +12 -1
- package/packages/attest/schemas/quick-verification-receipt-v2.schema.json +232 -0
- package/packages/attest/src/index.mjs +4 -1
- package/packages/attest/src/quick-receipt-contract.mjs +13 -3
- package/packages/attest/src/quick.mjs +21 -2
- package/registry-release-policy-v1.json +5 -5
- package/sbom.spdx.json +5 -5
- package/scripts/runkit-contract/assurance-router.mjs +3 -1
- package/scripts/runkit-contract/core-contract.mjs +2 -1
- package/scripts/runkit-contract/onboarding-doctor.mjs +46 -18
- package/scripts/runkit-contract/profile-onboarding.mjs +4 -0
- package/scripts/runkit-contract/project-cli-resolver.mjs +3 -0
- package/scripts/runkit-contract/quick-metrics.mjs +3 -3
- package/scripts/runkit-contract/quick-receipt.mjs +110 -5
- package/scripts/runkit-contract/quick-verify.mjs +93 -11
- package/scripts/runkit-contract/runkit-cli.mjs +172 -24
- package/scripts/runkit-contract/schemas/profile-reconcile-plan-v1.schema.json +2 -0
- package/scripts/runkit-contract/schemas/team-project-event-v2.schema.json +128 -0
- package/scripts/runkit-contract/team-project.mjs +310 -45
- package/scripts/runkit-contract/usage-mode.mjs +11 -13
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://owlcoda.dev/schemas/runkit/trust/quick-verification-receipt-v2.schema.json",
|
|
4
|
+
"title": "OwlCoda Quick Verification Receipt V2",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"schemaVersion",
|
|
9
|
+
"receiptId",
|
|
10
|
+
"assurance",
|
|
11
|
+
"authorizationGranted",
|
|
12
|
+
"coreIdentity",
|
|
13
|
+
"workspaceBefore",
|
|
14
|
+
"exactCommand",
|
|
15
|
+
"inputArtifacts",
|
|
16
|
+
"verificationContext",
|
|
17
|
+
"startedAt",
|
|
18
|
+
"finishedAt",
|
|
19
|
+
"exitResult",
|
|
20
|
+
"outputArtifacts",
|
|
21
|
+
"workspaceAfter",
|
|
22
|
+
"mutationDecision",
|
|
23
|
+
"issueCodes"
|
|
24
|
+
],
|
|
25
|
+
"properties": {
|
|
26
|
+
"schemaVersion": {
|
|
27
|
+
"const": "OwlCodaQuickVerificationReceiptV2"
|
|
28
|
+
},
|
|
29
|
+
"receiptId": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1
|
|
32
|
+
},
|
|
33
|
+
"assurance": {
|
|
34
|
+
"const": "captured_verification"
|
|
35
|
+
},
|
|
36
|
+
"authorizationGranted": {
|
|
37
|
+
"const": false
|
|
38
|
+
},
|
|
39
|
+
"coreIdentity": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"required": [
|
|
43
|
+
"contractVersion",
|
|
44
|
+
"coreVersion",
|
|
45
|
+
"coreManifestSha256"
|
|
46
|
+
],
|
|
47
|
+
"properties": {
|
|
48
|
+
"contractVersion": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"minLength": 1
|
|
51
|
+
},
|
|
52
|
+
"coreVersion": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"minLength": 1
|
|
55
|
+
},
|
|
56
|
+
"coreManifestSha256": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"workspaceBefore": {
|
|
63
|
+
"$ref": "workspace-snapshot-v1.schema.json"
|
|
64
|
+
},
|
|
65
|
+
"exactCommand": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": [
|
|
69
|
+
"executable",
|
|
70
|
+
"argv",
|
|
71
|
+
"cwd"
|
|
72
|
+
],
|
|
73
|
+
"properties": {
|
|
74
|
+
"executable": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"minLength": 1
|
|
77
|
+
},
|
|
78
|
+
"argv": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": {
|
|
81
|
+
"type": "string"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"cwd": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"minLength": 1
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"inputArtifacts": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"required": [
|
|
94
|
+
"stdin"
|
|
95
|
+
],
|
|
96
|
+
"properties": {
|
|
97
|
+
"stdin": {
|
|
98
|
+
"$ref": "#/$defs/materialArtifact"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"verificationContext": {
|
|
103
|
+
"type": "object",
|
|
104
|
+
"additionalProperties": false,
|
|
105
|
+
"required": [
|
|
106
|
+
"platform",
|
|
107
|
+
"architecture",
|
|
108
|
+
"runtime"
|
|
109
|
+
],
|
|
110
|
+
"properties": {
|
|
111
|
+
"platform": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"minLength": 1
|
|
114
|
+
},
|
|
115
|
+
"architecture": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"minLength": 1
|
|
118
|
+
},
|
|
119
|
+
"runtime": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"startedAt": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"format": "date-time"
|
|
128
|
+
},
|
|
129
|
+
"finishedAt": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"format": "date-time"
|
|
132
|
+
},
|
|
133
|
+
"exitResult": {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"additionalProperties": false,
|
|
136
|
+
"required": [
|
|
137
|
+
"exitCode",
|
|
138
|
+
"signal"
|
|
139
|
+
],
|
|
140
|
+
"properties": {
|
|
141
|
+
"exitCode": {
|
|
142
|
+
"type": [
|
|
143
|
+
"integer",
|
|
144
|
+
"null"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
"signal": {
|
|
148
|
+
"type": [
|
|
149
|
+
"string",
|
|
150
|
+
"null"
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"outputArtifacts": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"additionalProperties": false,
|
|
158
|
+
"required": [
|
|
159
|
+
"stdout",
|
|
160
|
+
"stderr"
|
|
161
|
+
],
|
|
162
|
+
"properties": {
|
|
163
|
+
"stdout": {
|
|
164
|
+
"$ref": "#/$defs/materialArtifact"
|
|
165
|
+
},
|
|
166
|
+
"stderr": {
|
|
167
|
+
"$ref": "#/$defs/materialArtifact"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"workspaceAfter": {
|
|
172
|
+
"$ref": "workspace-snapshot-v1.schema.json"
|
|
173
|
+
},
|
|
174
|
+
"mutationDecision": {
|
|
175
|
+
"enum": [
|
|
176
|
+
"source_unchanged",
|
|
177
|
+
"invalidated_by_command_source_mutation"
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
"issueCodes": {
|
|
181
|
+
"type": "array",
|
|
182
|
+
"uniqueItems": true,
|
|
183
|
+
"items": {
|
|
184
|
+
"type": "string",
|
|
185
|
+
"minLength": 1
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"signatureRef": {
|
|
189
|
+
"type": "object",
|
|
190
|
+
"additionalProperties": false,
|
|
191
|
+
"required": [
|
|
192
|
+
"path",
|
|
193
|
+
"sha256"
|
|
194
|
+
],
|
|
195
|
+
"properties": {
|
|
196
|
+
"path": {
|
|
197
|
+
"type": "string",
|
|
198
|
+
"minLength": 1
|
|
199
|
+
},
|
|
200
|
+
"sha256": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"$defs": {
|
|
208
|
+
"materialArtifact": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"additionalProperties": false,
|
|
211
|
+
"required": [
|
|
212
|
+
"path",
|
|
213
|
+
"sha256",
|
|
214
|
+
"sizeBytes"
|
|
215
|
+
],
|
|
216
|
+
"properties": {
|
|
217
|
+
"path": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"minLength": 1
|
|
220
|
+
},
|
|
221
|
+
"sha256": {
|
|
222
|
+
"type": "string",
|
|
223
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
224
|
+
},
|
|
225
|
+
"sizeBytes": {
|
|
226
|
+
"type": "integer",
|
|
227
|
+
"minimum": 0
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -41,7 +41,10 @@ function readSubject(subjectPath) {
|
|
|
41
41
|
|
|
42
42
|
export function attestFile({ subjectPath, workspaceRoot }) {
|
|
43
43
|
const subject = readSubject(subjectPath);
|
|
44
|
-
if (
|
|
44
|
+
if (new Set([
|
|
45
|
+
"OwlCodaQuickVerificationReceiptV1",
|
|
46
|
+
"OwlCodaQuickVerificationReceiptV2",
|
|
47
|
+
]).has(subject.value.schemaVersion)) {
|
|
45
48
|
const details = attestQuickReceiptDetailsFromBytes({
|
|
46
49
|
receiptPath: subject.absolutePath,
|
|
47
50
|
receiptBytes: subject.bytes,
|
|
@@ -110,10 +110,14 @@ function validOutputArtifact(value) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export function validQuickReceiptShape(receipt) {
|
|
113
|
-
|
|
113
|
+
const receiptV1 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV1";
|
|
114
|
+
const receiptV2 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV2";
|
|
115
|
+
const requiredKeys = receiptV2
|
|
116
|
+
? [...RECEIPT_REQUIRED_KEYS, "inputArtifacts"]
|
|
117
|
+
: RECEIPT_REQUIRED_KEYS;
|
|
118
|
+
if (!(receiptV1 || receiptV2) || !hasExactKeys(receipt, requiredKeys, ["signatureRef"])) return false;
|
|
114
119
|
if (
|
|
115
|
-
receipt.
|
|
116
|
-
|| typeof receipt.receiptId !== "string"
|
|
120
|
+
typeof receipt.receiptId !== "string"
|
|
117
121
|
|| receipt.receiptId.length === 0
|
|
118
122
|
|| receipt.assurance !== "captured_verification"
|
|
119
123
|
|| receipt.authorizationGranted !== false
|
|
@@ -145,6 +149,12 @@ export function validQuickReceiptShape(receipt) {
|
|
|
145
149
|
) {
|
|
146
150
|
return false;
|
|
147
151
|
}
|
|
152
|
+
if (receiptV2 && (
|
|
153
|
+
!hasExactKeys(receipt.inputArtifacts, ["stdin"])
|
|
154
|
+
|| !validOutputArtifact(receipt.inputArtifacts.stdin)
|
|
155
|
+
)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
148
158
|
if (receipt.signatureRef !== undefined) {
|
|
149
159
|
if (!hasExactKeys(receipt.signatureRef, ["path", "sha256"])
|
|
150
160
|
|| typeof receipt.signatureRef.path !== "string"
|
|
@@ -18,6 +18,16 @@ import { captureWorkspaceSnapshot } from "./workspace-snapshot.mjs";
|
|
|
18
18
|
export { validQuickReceiptShape } from "./quick-receipt-contract.mjs";
|
|
19
19
|
|
|
20
20
|
export const SUPPORTED_QUICK_CORE_IDENTITIES = Object.freeze([
|
|
21
|
+
{
|
|
22
|
+
contractVersion: "0.2",
|
|
23
|
+
coreVersion: "0.18.3",
|
|
24
|
+
coreManifestSha256: "sha256:cc7a923649592084150828f24f0d90f280af92514bafdbc4999f4015b3175d5c",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
contractVersion: "0.2",
|
|
28
|
+
coreVersion: "0.18.2",
|
|
29
|
+
coreManifestSha256: "sha256:abe17ff794b4019d8d476f09eb5d4105bae1070b1df0aab53e6c94c7ec8b65a6",
|
|
30
|
+
},
|
|
21
31
|
{
|
|
22
32
|
contractVersion: "0.2",
|
|
23
33
|
coreVersion: "0.18.1",
|
|
@@ -189,7 +199,11 @@ export function attestQuickReceiptDetailsFromBytes({
|
|
|
189
199
|
throw error;
|
|
190
200
|
}
|
|
191
201
|
|
|
192
|
-
const issues = [
|
|
202
|
+
const issues = [
|
|
203
|
+
...receipt.issueCodes.filter((issue) => issue !== "quick_ignored_artifact_unbound"),
|
|
204
|
+
"signature_absent",
|
|
205
|
+
"anchor_absent",
|
|
206
|
+
];
|
|
193
207
|
const materials = [];
|
|
194
208
|
let materialMissing = false;
|
|
195
209
|
let materialMismatch = false;
|
|
@@ -228,7 +242,12 @@ export function attestQuickReceiptDetailsFromBytes({
|
|
|
228
242
|
const commandWorkspaceMatches = selectedWorkspaceRoot !== undefined
|
|
229
243
|
&& receiptWorkspaceRoot === selectedWorkspaceRoot;
|
|
230
244
|
if (commandWorkspaceMatches) {
|
|
231
|
-
|
|
245
|
+
const boundArtifacts = [
|
|
246
|
+
...(receipt.inputArtifacts === undefined ? [] : [receipt.inputArtifacts.stdin]),
|
|
247
|
+
receipt.outputArtifacts.stdout,
|
|
248
|
+
receipt.outputArtifacts.stderr,
|
|
249
|
+
];
|
|
250
|
+
for (const artifact of boundArtifacts) {
|
|
232
251
|
try {
|
|
233
252
|
const materialPath = resolveBoundMaterial(receiptWorkspaceRoot, artifact.path);
|
|
234
253
|
const { bytes } = readFileBytesBounded(materialPath);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV1",
|
|
3
3
|
"status": "release_candidate_unpublished",
|
|
4
4
|
"packageName": "owlrunkit",
|
|
5
|
-
"candidateVersion": "0.18.
|
|
5
|
+
"candidateVersion": "0.18.3",
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|
|
7
7
|
"registryRequiredBeforeAdoption": true,
|
|
8
8
|
"exactVersionRequired": true,
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
],
|
|
24
24
|
"currentPublishedRelease": {
|
|
25
25
|
"packageName": "owlrunkit",
|
|
26
|
-
"version": "0.18.
|
|
27
|
-
"shasum": "
|
|
28
|
-
"integrity": "sha512-
|
|
29
|
-
"tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.
|
|
26
|
+
"version": "0.18.2",
|
|
27
|
+
"shasum": "4a85e31dad306260e4a6b1fcbccb3807e8647a0a",
|
|
28
|
+
"integrity": "sha512-Clpr8UQdNitzMMmQHUtjs9mesmukUqZrQ5nrda+Ryo8SuvECH8eBiis378NnzV1lI79kmljv49ToRRe867zlBg==",
|
|
29
|
+
"tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.2.tgz"
|
|
30
30
|
},
|
|
31
31
|
"registryRelease": null,
|
|
32
32
|
"registryEvidenceMustBeExternal": true,
|
package/sbom.spdx.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "owlrunkit-0.18.
|
|
6
|
-
"documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.18.
|
|
5
|
+
"name": "owlrunkit-0.18.3",
|
|
6
|
+
"documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.18.3",
|
|
7
7
|
"creationInfo": {
|
|
8
8
|
"created": "2026-07-29T00:00:00Z",
|
|
9
9
|
"creators": [
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
{
|
|
15
15
|
"name": "owlrunkit",
|
|
16
16
|
"SPDXID": "SPDXRef-Package-OwlRunKit",
|
|
17
|
-
"versionInfo": "0.18.
|
|
18
|
-
"downloadLocation": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.
|
|
17
|
+
"versionInfo": "0.18.3",
|
|
18
|
+
"downloadLocation": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.3.tgz",
|
|
19
19
|
"filesAnalyzed": false,
|
|
20
20
|
"licenseConcluded": "GPL-3.0-or-later",
|
|
21
21
|
"licenseDeclared": "GPL-3.0-or-later",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
{
|
|
25
25
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
26
26
|
"referenceType": "purl",
|
|
27
|
-
"referenceLocator": "pkg:npm/owlrunkit@0.18.
|
|
27
|
+
"referenceLocator": "pkg:npm/owlrunkit@0.18.3"
|
|
28
28
|
}
|
|
29
29
|
]
|
|
30
30
|
}
|
|
@@ -14,7 +14,7 @@ const BOOLEAN_FACTS = [
|
|
|
14
14
|
"schemaOrDataMigration",
|
|
15
15
|
];
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
export const RUNKIT_RISK_CATEGORIES = Object.freeze([
|
|
18
18
|
"backtest",
|
|
19
19
|
"deployment",
|
|
20
20
|
"destructive",
|
|
@@ -26,6 +26,8 @@ const RISK_CATEGORIES = new Set([
|
|
|
26
26
|
"release",
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
|
+
const RISK_CATEGORIES = new Set(RUNKIT_RISK_CATEGORIES);
|
|
30
|
+
|
|
29
31
|
const MATERIAL_RISK_CATEGORIES = new Set([
|
|
30
32
|
"destructive",
|
|
31
33
|
"foreign_write",
|
|
@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
import { parseProjectControlState } from "./project-control-parser.mjs";
|
|
15
15
|
|
|
16
16
|
export const CONTRACT_VERSION = "0.2";
|
|
17
|
-
export const CORE_VERSION = "0.18.
|
|
17
|
+
export const CORE_VERSION = "0.18.3";
|
|
18
18
|
export const RUNTIME_ROOT = ".owlcoda/runkit";
|
|
19
19
|
|
|
20
20
|
const CORE_FILES = [
|
|
@@ -126,6 +126,7 @@ const CORE_FILES = [
|
|
|
126
126
|
"schemas/verification-context-v1.schema.json",
|
|
127
127
|
"schemas/team-project-definition-v1.schema.json",
|
|
128
128
|
"schemas/team-project-event-v1.schema.json",
|
|
129
|
+
"schemas/team-project-event-v2.schema.json",
|
|
129
130
|
"schemas/team-project-successor-receipt-v1.schema.json",
|
|
130
131
|
"schemas/team-project-status-v1.schema.json",
|
|
131
132
|
"schemas/usage-mode-recommendation-v1.schema.json",
|
|
@@ -190,11 +190,16 @@ function parseJsonStrict(text) {
|
|
|
190
190
|
export function resolveBoundedWorkspaceRoot(workspaceRoot) {
|
|
191
191
|
const requested = path.resolve(workspaceRoot);
|
|
192
192
|
const stat = lstatSync(requested);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
const resolved = realpathSync(requested);
|
|
194
|
+
if ((stat.isSymbolicLink() || resolved !== requested)
|
|
195
|
+
&& lstatSync(resolved).isDirectory()) {
|
|
196
|
+
const quoted = `'${resolved.replaceAll("'", `'"'"'`)}'`;
|
|
197
|
+
throw new Error(
|
|
198
|
+
"workspace root must be a real directory without symlink ancestors. "
|
|
199
|
+
+ `Retry with --workspace ${quoted}.`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
if (!stat.isDirectory()) {
|
|
198
203
|
throw new Error("workspace root must be a real directory without symlink ancestors");
|
|
199
204
|
}
|
|
200
205
|
return requested;
|
|
@@ -317,28 +322,51 @@ export function readLocalInstallBinding({ workspaceRoot } = {}) {
|
|
|
317
322
|
};
|
|
318
323
|
}
|
|
319
324
|
|
|
325
|
+
function registryTransportFailure(error) {
|
|
326
|
+
const code = error?.cause?.code ?? error?.code ?? null;
|
|
327
|
+
if (error?.name === "TimeoutError"
|
|
328
|
+
|| error?.name === "AbortError"
|
|
329
|
+
|| code === "ETIMEDOUT") {
|
|
330
|
+
return { issueCode: "registry_timeout", retryable: true };
|
|
331
|
+
}
|
|
332
|
+
if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
|
|
333
|
+
return { issueCode: "registry_dns_failed", retryable: true };
|
|
334
|
+
}
|
|
335
|
+
if (code === "ERR_INVALID_URL") {
|
|
336
|
+
return { issueCode: "registry_url_invalid", retryable: false };
|
|
337
|
+
}
|
|
338
|
+
return { issueCode: "registry_connection_failed", retryable: true };
|
|
339
|
+
}
|
|
340
|
+
|
|
320
341
|
export async function readRegistryExact({
|
|
321
342
|
registryUrl,
|
|
322
343
|
packageName = PACKAGE_NAME,
|
|
323
344
|
version = EXPECTED_VERSION,
|
|
324
345
|
timeoutMs = 1_500,
|
|
346
|
+
fetchImpl = fetch,
|
|
325
347
|
} = {}) {
|
|
326
348
|
const base = registryUrl.replace(/\/+$/, "");
|
|
327
349
|
const url = `${base}/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`;
|
|
328
350
|
let response;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
351
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
352
|
+
try {
|
|
353
|
+
response = await fetchImpl(url, {
|
|
354
|
+
headers: {
|
|
355
|
+
accept: "application/json",
|
|
356
|
+
},
|
|
357
|
+
redirect: "manual",
|
|
358
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
359
|
+
});
|
|
360
|
+
break;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
const failure = registryTransportFailure(error);
|
|
363
|
+
if (!failure.retryable || attempt === 1) {
|
|
364
|
+
return {
|
|
365
|
+
status: "unavailable",
|
|
366
|
+
issueCodes: [failure.issueCode],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
}
|
|
342
370
|
}
|
|
343
371
|
if (response.status === 401 || response.status === 403) {
|
|
344
372
|
return {
|
|
@@ -1511,10 +1511,14 @@ export function reconcileProfilesV2({
|
|
|
1511
1511
|
}
|
|
1512
1512
|
const proposedProfilesBytes = `${JSON.stringify(merged.proposedProfiles, null, 2)}\n`;
|
|
1513
1513
|
const proposedProfilesSha256 = sha256(proposedProfilesBytes);
|
|
1514
|
+
const normalizationOnly = proposedProfilesSha256 !== currentProfilesSha256
|
|
1515
|
+
&& merged.addedProfileIds.length === 0
|
|
1516
|
+
&& merged.updatedProfiles.length === 0;
|
|
1514
1517
|
const planBody = {
|
|
1515
1518
|
detectionSha256: detection.detectionSha256,
|
|
1516
1519
|
currentProfilesSha256,
|
|
1517
1520
|
proposedProfilesSha256,
|
|
1521
|
+
normalizationOnly,
|
|
1518
1522
|
addedProfileIds: merged.addedProfileIds,
|
|
1519
1523
|
updatedProfiles: merged.updatedProfiles,
|
|
1520
1524
|
};
|
|
@@ -18,6 +18,9 @@ const OFFICIAL_CLI_ENTRYPOINT =
|
|
|
18
18
|
const EXACT_VERSION = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
|
19
19
|
const SHA256_REF = /^sha256:[a-f0-9]{64}$/;
|
|
20
20
|
const TRUSTED_PRIOR_CORE_IDENTITIES = new Map([
|
|
21
|
+
["0.18.1", new Set([
|
|
22
|
+
"sha256:349b4157d3d089462b172de1619ccd169b5c1669b9322e2580ac6ec4f8616b07",
|
|
23
|
+
])],
|
|
21
24
|
["0.18.0", new Set([
|
|
22
25
|
"sha256:72c481dbafe06a9c56cd940d74a3fe109a82b73a3c43d0bb54923ea6c584c04e",
|
|
23
26
|
])],
|
|
@@ -59,7 +59,7 @@ function trustedReceiptRoot(workspaceRoot) {
|
|
|
59
59
|
return { status: "valid", root };
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
export function readLocalQuickMetrics(workspaceRoot) {
|
|
62
|
+
export function readLocalQuickMetrics(workspaceRoot, { verbose = false } = {}) {
|
|
63
63
|
const selected = trustedReceiptRoot(workspaceRoot);
|
|
64
64
|
if (selected.status === "invalid") {
|
|
65
65
|
return {
|
|
@@ -68,7 +68,7 @@ export function readLocalQuickMetrics(workspaceRoot) {
|
|
|
68
68
|
schemaVersion: "OwlCodaRunKitLocalMetricsV1",
|
|
69
69
|
telemetry: false,
|
|
70
70
|
networkRequests: 0,
|
|
71
|
-
inputs: [],
|
|
71
|
+
...(verbose ? { inputs: [] } : {}),
|
|
72
72
|
quick: {
|
|
73
73
|
total: 0,
|
|
74
74
|
passed: 0,
|
|
@@ -117,7 +117,7 @@ export function readLocalQuickMetrics(workspaceRoot) {
|
|
|
117
117
|
schemaVersion: "OwlCodaRunKitLocalMetricsV1",
|
|
118
118
|
telemetry: false,
|
|
119
119
|
networkRequests: 0,
|
|
120
|
-
inputs: receiptPaths,
|
|
120
|
+
...(verbose ? { inputs: receiptPaths } : {}),
|
|
121
121
|
quick: totals,
|
|
122
122
|
authorizationGranted: false,
|
|
123
123
|
};
|