@rightkit/release 0.2.123 → 0.2.125

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/build-release.mjs CHANGED
@@ -241,10 +241,8 @@ try {
241
241
  }
242
242
  const ownershipEvidence = preflight.find((check) => check.name === "ownership")?.evidence;
243
243
  if (!ownershipEvidence) fail("ownership evidence was not produced by release preflight");
244
- // Pending-enrollment advisory evidence asserts no commit (ownership-evidence.mjs); only
245
- // committed-tree evidence must match the release commit.
246
- if (ownershipEvidence.source !== "enrollment-pending-advisory" && ownershipEvidence.commit !== commit) {
247
- fail("ownership scan source differs from release commit");
244
+ if (ownershipEvidence.commit !== commit) {
245
+ fail(`ownership scan commit ${ownershipEvidence.commit ?? "(missing)"} differs from release commit ${commit}; regenerate with right-release ownership at release commit ${commit}`);
248
246
  }
249
247
  for (const check of preflight) {
250
248
  if (check.status !== "ok") console.error(`[right-release] preflight ${check.name}: ${check.detail}`);
@@ -41,7 +41,7 @@ function createEvidence(repoRoot, {
41
41
  let enrollmentPending = trustState.enrolled !== true;
42
42
  if (committed && enrollmentPending && !allowPendingAdvisory && !trustState.trust?.rootFingerprint) throw new Error("protected ownership evidence requires both distinct, unrevoked approval keys to be enrolled");
43
43
  // A valid protected registry with incomplete key enrollment can still drive
44
- // a useful local backlog scan. It cannot produce a source binding or verify
44
+ // a useful local backlog scan. It cannot assert a protected source binding or verify
45
45
  // approval signatures, so this result is deliberately advisory.
46
46
  const useCommittedSource = committed && (!enrollmentPending || Boolean(trustState.trust?.rootFingerprint));
47
47
  if (useCommittedSource && requireCleanCheckout) assertCommittedCheckoutClean(root);
@@ -68,6 +68,7 @@ function createEvidence(repoRoot, {
68
68
  }
69
69
  if (useCommittedSource && requireCleanCheckout) assertCommittedCheckoutClean(root, { expectedCommit: source.commit, expectedTree: source.tree });
70
70
  const commit = useCommittedSource ? source.commit : git(root, ["rev-parse", "HEAD"], gitRunner);
71
+ if (!commit) throw new Error("ownership evidence: scan source did not produce a HEAD commit");
71
72
  const tree = useCommittedSource ? source.tree : git(root, ["rev-parse", `${commit}^{tree}`], gitRunner);
72
73
  const scannerVersion = SCANNER_VERSION;
73
74
  const catalogVersion = manifest.version ?? String(manifest.schema ?? "1");
@@ -154,7 +155,8 @@ function createEvidence(repoRoot, {
154
155
  schema: 1,
155
156
  repositoryIdentity: repositoryIdentity ? canonicalRepositoryIdentity(result.metadata?.repositoryIdentity) : null,
156
157
  source: enrollmentPending ? "enrollment-pending-advisory" : useCommittedSource ? "committed-git-tree" : "mutable-checkout-test-seam",
157
- ...(enrollmentPending ? {} : { commit, tree }),
158
+ commit,
159
+ ...(enrollmentPending ? {} : { tree }),
158
160
  catalogDigest,
159
161
  catalogVersion,
160
162
  scannerVersion,
@@ -37,6 +37,7 @@ function statusFor(row, report) {
37
37
  if (report.enrollmentPending && (row.status === "blocked" || row.status === "blocked-by-findings")) return "enrollment-pending";
38
38
  if (row.status === "blocked" || row.status === "blocked-by-findings") return "blocked";
39
39
  if (row.status === "excepted") return "excepted";
40
+ if (row.status === "qa-only") return "qa-only";
40
41
  if (row.status === "verified-integration") return "verified-integration";
41
42
  if (row.status === "declared-dependency" || row.uses === true) return "declared-dependency";
42
43
  if (report.coverage?.length) return "unscanned";
@@ -59,7 +60,7 @@ function exceptionRequests(root, app, report) {
59
60
 
60
61
  function asRecord(app, root, scope, report, manifest, versions, scannedAt) {
61
62
  const meta = report.metadata ?? {};
62
- const findings = (report.findings ?? []).map((f) => ({ fingerprint: f.fingerprint, capability: f.capability, file: f.file, line: f.line ?? 0, occurrenceHash: f.occurrenceHash ?? sha256(canonicalJson(f)) }));
63
+ const findings = (report.findings ?? []).map((f) => ({ fingerprint: f.fingerprint, capability: f.capability, file: f.file, line: f.line ?? 0, occurrenceHash: f.occurrenceHash ?? sha256(canonicalJson(f)), ...(f.qaOnly ? { qaOnly: true } : {}) }));
63
64
  const files = [...new Set(findings.map((f) => f.file))].sort();
64
65
  const contentDigestSource = meta.contentDigests ? "scanner-inputs" : "finding-occurrences-only";
65
66
  const contentDigests = meta.contentDigests ?? findings.map((f) => ({ path: f.file, digest: f.occurrenceHash, kind: "finding-occurrence" }));
package/ownership.mjs CHANGED
@@ -15,7 +15,7 @@ export const EXCEPTIONS_FILE = path.join(".rightkit", "ownership-exceptions.json
15
15
  const CODE_EXT = new Set([".rs", ".ts", ".tsx", ".js", ".mjs", ".cjs", ".jsx", ".swift", ".m", ".mm", ".c", ".cc", ".cpp", ".h", ".py", ".go", ".kt", ".java", ".cs"]);
16
16
  // Listed installed/build inputs retain explicit coverage diagnostics.
17
17
  const OPAQUE_DIRS = new Set(["target", ".build", "DerivedData", "Pods"]);
18
- export const SCANNER_VERSION = "2.2.0";
18
+ export const SCANNER_VERSION = "2.3.0";
19
19
  export const catalogDigest = (manifest) => sha256(manifest);
20
20
  const byteDigest = (bytes) => createHash("sha256").update(bytes).digest("hex");
21
21
  const inputDigest = (file) => file.digest ?? byteDigest(file.bytes);
@@ -249,7 +249,8 @@ function dependenciesFromInventory(appRoot, inventory) {
249
249
  const alias = spec.match(/^(?:npm:)(@[^/]+\/[^@]+|[^@]+)(?:@|$)/)?.[1];
250
250
  const localPath = spec.match(/^(?:file:|link:)(.+)$/)?.[1];
251
251
  const isGit = /^(git\+|https?:.*\.git)/i.test(spec);
252
- addDependency(deps, "npm", alias ?? name, rel, { alias: alias ? name : undefined, local: !!localPath, source: localPath ? spec.split(":")[0] : isGit ? "git" : spec.startsWith("workspace:") ? "workspace" : undefined });
252
+ const devOnly = field === "devDependencies" && !["dependencies", "optionalDependencies", "peerDependencies"].some((section) => Object.hasOwn(pkg[section] ?? {}, name));
253
+ addDependency(deps, "npm", alias ?? name, rel, { alias: alias ? name : undefined, local: !!localPath, source: localPath ? spec.split(":")[0] : isGit ? "git" : spec.startsWith("workspace:") ? "workspace" : undefined, ...(devOnly ? { devOnly: true } : {}) });
253
254
  if (localPath) {
254
255
  resolveLocalPath(appRoot, rel, localPath, coverage, rel, inventory, "local-npm-dependency", name);
255
256
  } else if (isGit) coverage.push({ path: rel, status: "unscanned", reason: `git-npm-dependency-source:${name}` });
@@ -359,13 +360,29 @@ function trustedProvenance(appRoot, inventory, trust, repositoryIdentity, covera
359
360
  return { excluded, classifications };
360
361
  }
361
362
 
363
+ function npmImportUsage(inventory) {
364
+ const usage = new Map(), qaSegments = new Set(["test", "tests", "__tests__", "e2e", "qa", "fixtures"]);
365
+ for (const { rel, bytes } of inventory.files) {
366
+ if (!CODE_EXT.has(path.posix.extname(rel).toLowerCase()) || !bytes) continue;
367
+ const qaPath = rel.split("/").some((segment) => qaSegments.has(segment)) || /(?:\.(?:test|spec)\.|^qa-.*\.)/.test(path.posix.basename(rel));
368
+ for (const match of bytes.toString("utf8").matchAll(/\bimport\b\s*(?:[\w$*{},\s]+?\bfrom\s*)?["']([^"']+)["']|\b(?:import|require)\s*\(\s*["']([^"']+)["']/g)) {
369
+ const specifier = match[1] ?? match[2];
370
+ const name = specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
371
+ usage.set(name, (usage.get(name) ?? true) && qaPath);
372
+ }
373
+ }
374
+ return usage;
375
+ }
376
+
362
377
  function scanInternal(appRoot, manifest, { inventory = fileInventory(appRoot), trust, repositoryIdentity, repositoryRoot = appRoot, pathPrefix = "" } = {}) {
363
378
  const findings = [], coverage = [...inventory.coverage], deps = dependenciesFromInventory(appRoot, inventory), contentDigests = [...(deps.contentDigests ?? [])];
364
379
  coverage.push(...(deps.coverage ?? []));
365
380
  const provenance = trustedProvenance(appRoot, inventory, trust, repositoryIdentity, coverage, repositoryRoot, pathPrefix);
381
+ const npmUsage = npmImportUsage(inventory);
366
382
  for (const c of manifest.capabilities) for (const f of c.fingerprints.filter((x) => x.type === "dependency")) for (const d of deps) {
367
383
  if (d.ecosystem === f.ecosystem && (d.name === f.name || d.alias === f.name)) {
368
- findings.push({ fingerprint: f.id, capability: c.capability, package: c.package, file: d.file, line: 0, text: `${d.ecosystem} dependency ${d.alias ? `${d.alias} aliases ` : ""}${d.name}`, local: d.local, provenance: d.source });
384
+ const qaOnly = c.capability !== "desktop-qa" && d.ecosystem === "npm" && d.devOnly && npmUsage.get(d.alias ?? d.name) === true;
385
+ findings.push({ fingerprint: f.id, capability: c.capability, package: c.package, file: d.file, line: 0, text: `${d.ecosystem} dependency ${d.alias ? `${d.alias} aliases ` : ""}${d.name}`, local: d.local, provenance: d.source, ...(qaOnly ? { qaOnly: true } : {}) });
369
386
  }
370
387
  }
371
388
  const matchers = sourceMatchers(manifest);
@@ -469,16 +486,18 @@ export function evaluate(findings, exceptions, options = {}) {
469
486
  }
470
487
  const pending = enrollmentPending(options.trust, options.trustEnrollment);
471
488
  if (pending) warnings.push("approval enrollment pending; detected findings remain open backlog requests until distinct Windows & macOS keys are enrolled");
472
- for (const f of findings) if (!covered.some((x) => x.occurrenceHash === occurrenceHash(f))) violations.push({ ...f, occurrenceHash: occurrenceHash(f) });
473
- return { violations, covered, problems, warnings, enrollmentPending: pending };
489
+ const qaOnly = findings.filter((f) => f.qaOnly === true && f.capability !== "desktop-qa");
490
+ for (const f of findings) if (!qaOnly.includes(f) && !covered.some((x) => x.occurrenceHash === occurrenceHash(f))) violations.push({ ...f, occurrenceHash: occurrenceHash(f) });
491
+ return { violations, covered, qaOnly, problems, warnings, enrollmentPending: pending };
474
492
  }
475
493
 
476
494
  export function capabilityTable(manifest, deps, result) {
477
495
  return [...new Map(manifest.capabilities.map((c) => [c.capability, c.package])).entries()].map(([capability, owner]) => {
478
496
  const declared = deps.some((d) => d.name === owner || d.name === owner.replace(/^rightkit-/, "@rightkit/"));
479
497
  const own = result.violations.filter((x) => x.capability === capability), covered = result.covered.filter((x) => x.capability === capability);
480
- const status = own.length ? "blocked" : covered.length ? "excepted" : declared ? "declared-dependency" : result.coverage?.length ? "unscanned" : "not-detected";
481
- return { capability, owner, uses: declared, status, count: own.length + covered.length };
498
+ const qaOnly = (result.qaOnly ?? []).filter((x) => x.capability === capability && !covered.some((item) => item.occurrenceHash === x.occurrenceHash));
499
+ const status = own.length ? "blocked" : covered.length ? "excepted" : qaOnly.length ? "qa-only" : declared ? "declared-dependency" : result.coverage?.length ? "unscanned" : "not-detected";
500
+ return { capability, owner, uses: declared, status, count: own.length + covered.length + qaOnly.length };
482
501
  });
483
502
  }
484
503
  export function formatTable(rows) { return ["capability owner status", ...rows.map((x) => `${x.capability} ${x.owner} ${x.status}`)].join("\n"); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rightkit/release",
3
- "version": "0.2.123",
3
+ "version": "0.2.125",
4
4
  "description": "Portable release CLI/SDK with fail-closed public GitHub Releases and private R2 + RightApps distribution.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "@rightkit/app-shell": "0.2.1",
17
17
  "@rightkit/ax": "0.2.4",
18
18
  "@rightkit/doc-render": "0.1.3",
19
- "@rightkit/git": "0.2.25",
19
+ "@rightkit/git": "0.2.26",
20
20
  "@rightkit/hooks": "0.1.1",
21
21
  "@rightkit/i18n": "0.1.0",
22
22
  "@rightkit/legal": "0.3.1",
@@ -28,8 +28,8 @@
28
28
  "@rightkit/pdf-ui": "0.1.2",
29
29
  "@rightkit/platform-ui": "0.1.2",
30
30
  "@rightkit/qa": "0.3.0",
31
- "@rightkit/qa-chrome": "0.1.2",
32
- "@rightkit/release": "0.2.123",
31
+ "@rightkit/qa-chrome": "0.1.3",
32
+ "@rightkit/release": "0.2.125",
33
33
  "@rightkit/settings-ui": "0.2.7",
34
34
  "@rightkit/shell": "0.1.0",
35
35
  "@rightkit/tauri": "0.1.1",
@@ -66,7 +66,8 @@
66
66
  "0.2.21",
67
67
  "0.2.22",
68
68
  "0.2.23",
69
- "0.2.24"
69
+ "0.2.24",
70
+ "0.2.25"
70
71
  ],
71
72
  "@rightkit/legal-ui": [
72
73
  "0.1.0",
@@ -145,7 +146,9 @@
145
146
  "0.2.119",
146
147
  "0.2.120",
147
148
  "0.2.121",
148
- "0.2.122"
149
+ "0.2.122",
150
+ "0.2.123",
151
+ "0.2.124"
149
152
  ],
150
153
  "@rightkit/qa": [
151
154
  "0.1.0",
@@ -201,7 +204,8 @@
201
204
  ],
202
205
  "@rightkit/qa-chrome": [
203
206
  "0.1.0",
204
- "0.1.1"
207
+ "0.1.1",
208
+ "0.1.2"
205
209
  ]
206
210
  },
207
211
  "cargo": {
@@ -224,7 +228,7 @@
224
228
  "stagedCargo": {
225
229
  "rightkit-audio": "0.1.0",
226
230
  "rightkit-automation": "0.1.0",
227
- "rightkit-browser": "0.2.0",
231
+ "rightkit-browser": "0.2.1",
228
232
  "rightkit-cache": "0.1.0",
229
233
  "rightkit-control": "0.1.6",
230
234
  "rightkit-crash": "0.1.0",
@@ -238,13 +242,16 @@
238
242
  "rightkit-logs": "0.2.0",
239
243
  "rightkit-mcp": "0.1.1",
240
244
  "rightkit-media": "0.2.2",
241
- "rightkit-models": "0.2.1",
245
+ "rightkit-models": "0.2.2",
242
246
  "rightkit-oauth": "0.2.0",
243
247
  "rightkit-ort": "0.1.4",
244
248
  "rightkit-pdf": "0.1.0",
245
249
  "rightkit-playback": "0.1.0",
246
250
  "rightkit-process": "0.2.1",
247
251
  "rightkit-qa": "0.2.7",
252
+ "rightkit-qts": "0.2.0",
253
+ "rightkit-qts-ggml": "0.1.0",
254
+ "rightkit-qts-ggml-sys": "0.1.0",
248
255
  "rightkit-sandbox": "0.1.0",
249
256
  "rightkit-search": "0.1.0",
250
257
  "rightkit-secrets": "0.1.0",
@@ -271,7 +278,7 @@
271
278
  "registry": {
272
279
  "cargo": {
273
280
  "rightkit-audio": "0.1.0",
274
- "rightkit-browser": "0.2.0",
281
+ "rightkit-browser": "0.2.1",
275
282
  "rightkit-cache": "0.1.0",
276
283
  "rightkit-control": "0.1.6",
277
284
  "rightkit-crash": "0.1.0",
@@ -285,13 +292,16 @@
285
292
  "rightkit-logs": "0.2.0",
286
293
  "rightkit-mcp": "0.1.1",
287
294
  "rightkit-media": "0.2.2",
288
- "rightkit-models": "0.2.1",
295
+ "rightkit-models": "0.2.2",
289
296
  "rightkit-oauth": "0.2.0",
290
297
  "rightkit-ort": "0.1.4",
291
298
  "rightkit-pdf": "0.1.0",
292
299
  "rightkit-playback": "0.1.0",
293
300
  "rightkit-process": "0.2.1",
294
301
  "rightkit-qa": "0.2.7",
302
+ "rightkit-qts": "0.2.0",
303
+ "rightkit-qts-ggml": "0.1.0",
304
+ "rightkit-qts-ggml-sys": "0.1.0",
295
305
  "rightkit-sandbox": "0.1.0",
296
306
  "rightkit-search": "0.1.0",
297
307
  "rightkit-secrets": "0.1.0",
@@ -306,7 +316,7 @@
306
316
  "@rightkit/app-shell": "0.2.1",
307
317
  "@rightkit/ax": "0.2.4",
308
318
  "@rightkit/doc-render": "0.1.3",
309
- "@rightkit/git": "0.2.25",
319
+ "@rightkit/git": "0.2.26",
310
320
  "@rightkit/hooks": "0.1.1",
311
321
  "@rightkit/i18n": "0.1.0",
312
322
  "@rightkit/legal": "0.3.1",
@@ -318,13 +328,21 @@
318
328
  "@rightkit/pdf-ui": "0.1.2",
319
329
  "@rightkit/platform-ui": "0.1.2",
320
330
  "@rightkit/qa": "0.3.0",
321
- "@rightkit/qa-chrome": "0.1.2",
322
- "@rightkit/release": "0.2.122",
331
+ "@rightkit/qa-chrome": "0.1.3",
332
+ "@rightkit/release": "0.2.124",
323
333
  "@rightkit/settings-ui": "0.2.7",
324
334
  "@rightkit/shell": "0.1.0",
325
335
  "@rightkit/tauri": "0.1.1",
326
336
  "@rightkit/theme": "0.2.1",
327
337
  "@rightkit/updates": "0.2.4"
328
338
  }
339
+ },
340
+ "legacyCargo": {
341
+ "rightkit-browser": [
342
+ "0.2.0"
343
+ ],
344
+ "rightkit-models": [
345
+ "0.2.1"
346
+ ]
329
347
  }
330
348
  }