@rightkit/release 0.6.31 → 0.6.32
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/bin/rightkit-gate.mjs +42 -10
- package/deterministic-scans.mjs +5 -3
- package/package.json +1 -1
- package/rightkit-versions.json +3 -3
package/bin/rightkit-gate.mjs
CHANGED
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
//
|
|
26
26
|
// Content checks run on an export of HEAD (exactly what is pushed), never on uncommitted work in the checkout.
|
|
27
27
|
//
|
|
28
|
-
// rightkit-gate [--base <ref>] [--plan]
|
|
29
|
-
// run the gate (default base origin/main); --plan prints the scans and runs none
|
|
30
|
-
//
|
|
28
|
+
// rightkit-gate [--base <ref>] [--plan]
|
|
29
|
+
// run the gate (default base origin/main); --plan prints the scans and runs none.
|
|
30
|
+
// There is no cache bypass (GC-T14; Adrian: no no-cache option): a result is reused only under a key
|
|
31
|
+
// naming every input it read, so a changed input always reruns.
|
|
31
32
|
// rightkit-gate --to check|compile|package|qualify|dev|test --route [--platform p] [--commit <rev>]
|
|
32
33
|
// prints one JSON line (schema rightkit-gate.route/1) naming the route this host takes for the
|
|
33
34
|
// stage and the refusal it would meet, and runs nothing: no ownership, snapshot, check, run record
|
|
@@ -79,7 +80,7 @@ import path from "node:path";
|
|
|
79
80
|
import { hostTarget } from "../cross-targets.mjs";
|
|
80
81
|
import { FOREIGN_PRE_COMMIT, retireHooksIn } from "../hook-retirement.mjs";
|
|
81
82
|
import { fileURLToPath } from "node:url";
|
|
82
|
-
import { BIOME_CONFIG_FILES, ESLINT_CONFIG_FILES, LOCAL_CLASS_B_JOBS, WORKSPACE_RUST_FILE, ancestorConfigChanged, ancestorDirsOf, canonicalJson, defaultSpawn, defaultSpawnAsync, digestScanSet, fileScanCache, findRustfmt, metadataArgs, planScans, runScans, scanToolPolicyFromPipeline, scanDeferrals, scanFailures } from "../deterministic-scans.mjs";
|
|
83
|
+
import { BIOME_CONFIG_FILES, CHECKER_IDENTITY, ESLINT_CONFIG_FILES, LOCAL_CLASS_B_JOBS, WORKSPACE_RUST_FILE, ancestorConfigChanged, ancestorDirsOf, canonicalJson, defaultSpawn, defaultSpawnAsync, digestScanSet, fileScanCache, findRustfmt, metadataArgs, planScans, runScans, scanToolPolicyFromPipeline, scanDeferrals, scanFailures } from "../deterministic-scans.mjs";
|
|
83
84
|
import { changedLockNames, parseLock, reach } from "../lock-graph.mjs";
|
|
84
85
|
import { resolveExecutor } from "../gate-executor.mjs";
|
|
85
86
|
// The gate's own executor: an outer gate's cargo wrapper on PATH is never this gate's cargo (gate-executor.mjs `gateWrappers`).
|
|
@@ -111,7 +112,23 @@ export const PARTIAL_EXIT = 3;
|
|
|
111
112
|
/** The platforms a door run can package: desktop (signed, sealed, installed QA, publisher upload) and mobile (signed, sealed, store test track). */
|
|
112
113
|
export const PLATFORMS = Object.freeze(["mac", "win", "ios", "android"]);
|
|
113
114
|
export const MOBILE_PLATFORMS = Object.freeze(new Set(["ios", "android"]));
|
|
114
|
-
|
|
115
|
+
// The gate's code identity for result keys: the checker (deterministic-scans and scan-digest, CHECKER_IDENTITY) and this file, where
|
|
116
|
+
// the keys are built. An unidentifiable checker gets a per-process value, so nothing is reused across runs.
|
|
117
|
+
let gateCodeIdentityMemo = null;
|
|
118
|
+
function gateCodeIdentity() {
|
|
119
|
+
if (gateCodeIdentityMemo === null) {
|
|
120
|
+
const h = createHash("sha256");
|
|
121
|
+
h.update(CHECKER_IDENTITY ?? `unidentified-${process.pid}-${Date.now()}`);
|
|
122
|
+
h.update("\0");
|
|
123
|
+
h.update(fs.readFileSync(fileURLToPath(import.meta.url)));
|
|
124
|
+
// The runtime cargo wrapper and the broker carrier it runs: their code decides what a carried compile did.
|
|
125
|
+
for (const f of ["cargo-target-shim.mjs", "snapshot-broker.mjs", "snapshot-request.mjs", "snapshot-metadata.mjs", "provenance-verify.mjs", "cargo-ledger.mjs"]) { h.update(`\0${f}\0`); h.update(fs.readFileSync(new URL(`../${f}`, import.meta.url))); }
|
|
126
|
+
gateCodeIdentityMemo = h.digest("hex").slice(0, 24);
|
|
127
|
+
}
|
|
128
|
+
return gateCodeIdentityMemo;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const USAGE = `usage: rightkit-gate --to check|compile|package|qualify|release [--platform mac|win|ios|android] [--tier patch|update] [--receipt-in <file>] [--receipt-out <file>] | rightkit-gate --to check|compile|package|qualify|release --unit npm:@rightkit/<name>|cargo:rightkit-<name> [--receipt-out <file>] | rightkit-gate --to tool --unit cargo:rightkit-qa|cargo:rightkit-credentials [--no-broker <exception-id>] [--receipt-out <file>] [--commit <rev>] (builds the unit's release binary from the commit and enrols it: cargo:rightkit-qa as the managed rightkit-qa runner, cargo:rightkit-credentials as the managed OS credential provider updater signing runs; Mac and Windows) | rightkit-gate --to check|compile|package|qualify --units-file <json {"units":[<selector>,...]} written for this run> | rightkit-gate --to check|compile|package|qualify --all-units-exception <id> (RightKit only: its unit is named on every run, or every unit by Adrian's entry in ci/all-units-exceptions.json of the commit) | rightkit-gate --to check|compile|package|qualify [--unit <selector>] --no-broker <exception-id> (Mac and Dell only; Adrian's recorded exception in .rightkit/broker-exceptions.json of the commit) | rightkit-gate --to dev|test [--commit <rev>] [-- <right-release args>] | rightkit-gate --to check|compile|package|qualify|dev|test --route [--platform mac|win|ios|android] [--commit <rev>] | rightkit-gate stage --platform mac|win [--tier patch|update] | rightkit-gate [--base <ref>] [--plan] | rightkit-gate install-hook | rightkit-gate env-digest | rightkit-gate snapshot [--commit <rev>] [--verify [--env <sha256>]] [--json] | rightkit-gate live-scans --repo <root> | rightkit-gate clippy [<cargo clippy args>] | rightkit-gate env-digest [--snapshot <dir> --commit <sha>] | rightkit-gate check [--repo <dir>] [--commit <rev> | --worktree] [--rule-tier compile|release] [--only <rule,...>] [--list] [--print-baseline] [--baseline <file>] | rightkit-gate check --commit <sha> --full-a --snapshot <dir> | --version`;
|
|
115
132
|
/** The host platform (process.platform) that constructs each platform's artifact; a platform missing here (android) builds on any host. */
|
|
116
133
|
const STAGE_NATIVE_HOST = Object.freeze({ mac: "darwin", ios: "darwin", win: "win32" });
|
|
117
134
|
|
|
@@ -3039,6 +3056,11 @@ export async function main(argv, io = {}) {
|
|
|
3039
3056
|
gateFile: fileURLToPath(import.meta.url), ...io,
|
|
3040
3057
|
};
|
|
3041
3058
|
const args = [...argv];
|
|
3059
|
+
// The cache bypass is retired (GC-T14; workspace rule: never write or run a no-cache option). Refused by name so an old caller learns why.
|
|
3060
|
+
if (args.includes("--no-cache") || (io.env ?? process.env).RK_GATE_CACHE === "0") {
|
|
3061
|
+
(io.err ?? console.error)("rightkit-gate: --no-cache and RK_GATE_CACHE=0 are retired: results are reused only under a key naming every input they read, so a changed input always reruns (GC-T14)");
|
|
3062
|
+
return 2;
|
|
3063
|
+
}
|
|
3042
3064
|
const option = (name) => { const i = args.indexOf(name); return i < 0 ? undefined : args[i + 1]; };
|
|
3043
3065
|
// `clippy`: the Clippy route (../clippy-route.mjs; docs/GATE-CONTRACT.md §1 "Clippy route & batching"). Dispatched before the global
|
|
3044
3066
|
// flags below because everything after `clippy` is cargo's own argv, verbatim (`-v`, `-h` and `--version` are cargo's).
|
|
@@ -3969,7 +3991,7 @@ export async function main(argv, io = {}) {
|
|
|
3969
3991
|
try { envAtStart = classAEnvironmentDigest({ root: liveBase, gatePackage: o.gatePackage, files: live.files, spawn: o.spawn, includeCaches: false }); envStartWithCaches = classAEnvironmentDigest({ root: liveBase, gatePackage: o.gatePackage, files: live.files, spawn: o.spawn }); cachesAtStart = toolCacheManifest({ root: liveBase, files: live.files }); }
|
|
3970
3992
|
catch (error) { o.err(`${tag} BLOCKED: ${error.message}`); return 1; }
|
|
3971
3993
|
}
|
|
3972
|
-
if (boundFullA
|
|
3994
|
+
if (boundFullA) {
|
|
3973
3995
|
try {
|
|
3974
3996
|
const common = git("rev-parse", "--git-common-dir");
|
|
3975
3997
|
if (failed(common)) throw new Error("no git directory");
|
|
@@ -3981,12 +4003,19 @@ export async function main(argv, io = {}) {
|
|
|
3981
4003
|
const readBlob = (p) => fs.readFileSync(path.join(liveBase, p), "utf8");
|
|
3982
4004
|
// The verdict also depends on what is not in the tree: the gate's own code and advisory data, the node and pnpm that run
|
|
3983
4005
|
// the checks, the installed dependencies (pnpm's install state) and the platform. Any change there is a cache miss.
|
|
3984
|
-
|
|
4006
|
+
// Tool caches (vitest, tsc build info, ...) are left out: the scans write them themselves, so keying on them made every rerun miss.
|
|
4007
|
+
const environment = classAEnvironmentDigest({ root: liveBase, gatePackage: o.gatePackage, files, spawn: o.spawn, includeCaches: false });
|
|
3985
4008
|
const digest = buildCacheDigest({ objectId, headTree: digestOf(files), rustUnits: rust.units, npmUnits: npm, cargoDir: ".", rustLocks, crateFeatures, listFiles, readBlob });
|
|
3986
|
-
|
|
4009
|
+
// A row's key is its own inputs plus the environment; the run's scope and scan set are not inputs of one row, and keying on them
|
|
4010
|
+
// missed every row whenever one file joined or left the plan. build-helpers is never reused: it reads the host's trace list,
|
|
4011
|
+
// which is outside every key (and takes seconds).
|
|
4012
|
+
// A row field that shapes what the scan checks without changing its id or command is part of its key: a tsc row's tscWorkspace
|
|
4013
|
+
// (the sibling packages its check project maps; scopeScans narrows it per scope) changes the verdict on the same tree.
|
|
4014
|
+
const rowShape = (scan) => (scan.tscWorkspace ? `:tscws=${createHash("sha256").update(canonicalJson([...scan.tscWorkspace].sort())).digest("hex")}` : "");
|
|
4015
|
+
cache = { ...store, digest: (scan) => { if (/^build-helpers(:|$)/.test(scan.id)) return null; const key = digest(scan); return key === null ? null : `${key}:${environment}${rowShape(scan)}`; } };
|
|
3987
4016
|
} catch { cache = null; }
|
|
3988
4017
|
}
|
|
3989
|
-
if (!classAOnly
|
|
4018
|
+
if (!classAOnly) {
|
|
3990
4019
|
try {
|
|
3991
4020
|
const headSha = snapshotBCommit?.commit ?? text(git("rev-parse", "HEAD")).trim();
|
|
3992
4021
|
const treeId = text(git("rev-parse", `${headSha}^{tree}`)).trim();
|
|
@@ -4009,7 +4038,10 @@ export async function main(argv, io = {}) {
|
|
|
4009
4038
|
if (failed(r)) throw new Error(`git show failed: ${why(r)}`);
|
|
4010
4039
|
return text(r);
|
|
4011
4040
|
};
|
|
4012
|
-
|
|
4041
|
+
// The gate's identity is part of every class B key: a changed check or key logic never reuses an older verdict.
|
|
4042
|
+
const rowDigest = buildCacheDigest({ objectId, headTree: treeId, rustUnits: rust.units, npmUnits: npm, cargoDir: ".", rustLocks, crateFeatures, listFiles, readBlob });
|
|
4043
|
+
const gateIdentity = gateCodeIdentity();
|
|
4044
|
+
cache = { ...store, digest: (scan) => { const key = rowDigest(scan); return key === null ? null : `${key}:${gateIdentity}`; } };
|
|
4013
4045
|
}
|
|
4014
4046
|
} catch { cache = null; }
|
|
4015
4047
|
}
|
package/deterministic-scans.mjs
CHANGED
|
@@ -160,9 +160,11 @@ const BUILD_ENV_PREFIXES = ["CARGO_", "RUST", "SCCACHE_", "RK_", "RIGHTKIT_", "R
|
|
|
160
160
|
// 3,809 entries and hit none across identical runs): the run's ownership handle, the attest nonce, the request-id file, the carried call's
|
|
161
161
|
// snapshot request and cargo map, the direct receipt path.
|
|
162
162
|
const BUILD_ENV_EXCLUDED = /^(RK_GATE_|RUSTRIGHT_QUIET_LEASE$|RIGHTKIT_BUILD_OWNERSHIP$|RIGHTKIT_CARRIED_CARGO_MAP$|RUSTRIGHT_ATTEST_NONCE$|RUSTRIGHT_REQUEST_ID_FILE$|RUSTRIGHT_SNAPSHOT_REQUEST$|RK_DIRECT_RECEIPT$)/;
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
|
|
163
|
+
// Per-run parts of a value are normalised: the runtime cargo wrapper's fresh parent (`rk-gate-shim-XXXXXX`) and its folder name
|
|
164
|
+
// (`rk-cargo-shim-<identity>`), whose identity hashes the run's broker section and so differs on every run (measured 2026-11-03: two identical
|
|
165
|
+
// Class A runs of rightkit-asr shared no key, only CARGO differed). The wrapper's CODE keys the result through the gate identity instead
|
|
166
|
+
// (the gate package files in the Class A environment digest; gateCodeIdentity for class B), so a changed wrapper still misses.
|
|
167
|
+
const normalizeRunTemp = (value) => String(value).replace(/rk-gate-shim-[A-Za-z0-9]+/g, "rk-gate-shim-*").replace(/rk-cargo-shim-[0-9a-f]+/g, "rk-cargo-shim-*");
|
|
166
168
|
export const buildEnvName = (name) => {
|
|
167
169
|
const upper = String(name).toUpperCase();
|
|
168
170
|
if (BUILD_ENV_EXCLUDED.test(upper)) return false;
|
package/package.json
CHANGED
package/rightkit-versions.json
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@rightkit/qa": "0.6.2",
|
|
50
50
|
"@rightkit/qa-chrome": "0.1.12",
|
|
51
51
|
"@rightkit/react-shell": "0.7.2",
|
|
52
|
-
"@rightkit/release": "0.6.
|
|
52
|
+
"@rightkit/release": "0.6.32",
|
|
53
53
|
"@rightkit/settings-ui": "0.7.0",
|
|
54
54
|
"@rightkit/social-ui": "0.1.0",
|
|
55
55
|
"@rightkit/system-ui": "0.1.0",
|
|
@@ -557,7 +557,7 @@
|
|
|
557
557
|
"rightkit-disk-cleanup": "0.1.0",
|
|
558
558
|
"rightkit-docs": "0.1.3",
|
|
559
559
|
"rightkit-doctor": "0.1.0",
|
|
560
|
-
"rightkit-document-workspace": "0.1.
|
|
560
|
+
"rightkit-document-workspace": "0.1.2",
|
|
561
561
|
"rightkit-embed": "0.6.2",
|
|
562
562
|
"rightkit-engine-host": "0.1.1",
|
|
563
563
|
"rightkit-evidence": "0.1.0",
|
|
@@ -630,7 +630,7 @@
|
|
|
630
630
|
"rightkit-spend": "0.2.0",
|
|
631
631
|
"rightkit-sync": "0.2.2",
|
|
632
632
|
"rightkit-system-monitor": "0.1.0",
|
|
633
|
-
"rightkit-tauri-shell": "0.7.
|
|
633
|
+
"rightkit-tauri-shell": "0.7.1",
|
|
634
634
|
"rightkit-terminal-ui": "0.1.0",
|
|
635
635
|
"rightkit-text-polish": "0.1.0",
|
|
636
636
|
"rightkit-time": "0.1.1",
|