@rightkit/release 0.6.7 → 0.6.8
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/README.md +10 -1
- package/bin/darwin/rightkit-swap +0 -0
- package/bin/rightkit-gate.mjs +29 -1
- package/door.mjs +23 -0
- package/package.json +2 -1
- package/rightkit-versions.json +1 -1
package/README.md
CHANGED
|
@@ -419,6 +419,15 @@ macOS and Windows tie privacy grants (mic, screen, Files and Folders, Removable
|
|
|
419
419
|
- `right-release dev` (mac) signs with the same Developer ID Application identity as release (an app that needs a provisioning profile uses a Developer ID profile); Apple Development certificates are refused with `DEV_MAC_SIGNING_DEVELOPER_ID_REQUIRED`.
|
|
420
420
|
- **Cargo target folders are not stable paths.** The broker's target tree is `<managed>/rightkit-build-control/ws/<hash>/g/<generation>/target/...` and the generation changes; `cargo-guard` uses a hashed `dev-targets/<project>-<hash>` folder. They are build output only, so nothing may run from them. Dev and QA binaries run from a fixed staged path: list them in `development.targets.<platform>.stage` (`[{ source } | { manifestPath, bin, targetTriple?, profile?, name? }]`) and `right-release dev` copies each in place to `<app root>/.rightkit-dev-bin/<triple-or-host>/<name>` (no backup of the old copy); `rightkit-qa` launches from its `.rightkit-qa-bin` stash on every path.
|
|
421
421
|
|
|
422
|
+
## The door check for an app's own build steps
|
|
423
|
+
|
|
424
|
+
An app's payload assembler or installer packager is a step its release config declares and `right-release` runs inside a stage. `door.mjs` (0.6.8) gives that step the check `right-release` makes for itself: `requireDoor(command)` exits 2 with the refusal unless a live `rightkit-gate --to <stage>` run for HEAD launched the process, so `node scripts/release/<step>.mjs` by hand is refused instead of becoming a side door around class A. `doorRefusal(options)` returns the message (or `null`) for a step that wants to report rather than exit. Refused: by hand, an ended run, a run for another commit, a forged nonce, outside a git checkout.
|
|
425
|
+
|
|
426
|
+
```js
|
|
427
|
+
import { requireDoor } from "@rightkit/release/door.mjs";
|
|
428
|
+
requireDoor("scripts/release/mac-payload.mjs"); // first statement; everything below runs only inside the door
|
|
429
|
+
```
|
|
430
|
+
|
|
422
431
|
## Runtime budget gate (crates)
|
|
423
432
|
|
|
424
433
|
`publish cargo` runs the `runtime budget` step (`runtime-budgets.mjs`) right after the secret scan. Full contract, schema and refusal table: `docs/RUNTIME-BUDGETS.md`.
|
|
@@ -475,7 +484,7 @@ enforcement. D4 is ratified; pending activation does not mean pending ratificati
|
|
|
475
484
|
|
|
476
485
|
Bins: `right-release` (`cli/right-release.mjs`) and `rightkit-gate` (`bin/rightkit-gate.mjs`). The CLI is the supported surface.
|
|
477
486
|
|
|
478
|
-
`package.json` carries an explicit `exports` map (plan item 2.10, C4-16): one `"./<file>"` entry per public file, no `"."` index, no wildcard. It lists the two bin files, `./package.json`, the modules this README documents as SDK (`./release-dependencies.mjs`, `./engine-locator.mjs`, `./pe-content.mjs`, `./dmg-build.mjs`) and the modules that product repositories and RightKit's own tooling import by deep path today. Every other file is private: `import "@rightkit/release/release.mjs"` fails with `ERR_PACKAGE_PATH_NOT_EXPORTED`, and so does `import "@rightkit/release"`. `docs/RELEASE-EXPORTS.md` in the RightKit repository is the inventory (every consumer import with file:line) and `release-exports.test.mjs` fails when the map, that inventory or a checked-out product repository disagree. A new public subpath needs an inventory row or a README SDK section in the same commit; the signing, notarization and packaging modules in the map are a shrinking baseline, not an invitation. A file read by path (`node_modules/@rightkit/release/<file>`) is outside the map and is listed in the inventory too.
|
|
487
|
+
`package.json` carries an explicit `exports` map (plan item 2.10, C4-16): one `"./<file>"` entry per public file, no `"."` index, no wildcard. It lists the two bin files, `./package.json`, the modules this README documents as SDK (`./release-dependencies.mjs`, `./engine-locator.mjs`, `./pe-content.mjs`, `./dmg-build.mjs`, `./door.mjs`) and the modules that product repositories and RightKit's own tooling import by deep path today. Every other file is private: `import "@rightkit/release/release.mjs"` fails with `ERR_PACKAGE_PATH_NOT_EXPORTED`, and so does `import "@rightkit/release"`. `docs/RELEASE-EXPORTS.md` in the RightKit repository is the inventory (every consumer import with file:line) and `release-exports.test.mjs` fails when the map, that inventory or a checked-out product repository disagree. A new public subpath needs an inventory row or a README SDK section in the same commit; the signing, notarization and packaging modules in the map are a shrinking baseline, not an invitation. A file read by path (`node_modules/@rightkit/release/<file>`) is outside the map and is listed in the inventory too.
|
|
479
488
|
|
|
480
489
|
## Dependencies
|
|
481
490
|
|
package/bin/darwin/rightkit-swap
CHANGED
|
Binary file
|
package/bin/rightkit-gate.mjs
CHANGED
|
@@ -72,6 +72,7 @@ import { changedLockNames, parseLock, reach } from "../lock-graph.mjs";
|
|
|
72
72
|
import { resolveExecutor } from "../gate-executor.mjs";
|
|
73
73
|
import { bindingOf, endRun, readReceipt, RECEIPT_SCHEMA, sameBinding, sameSource, sealedFor, stagesTo, startRun, STAGES, writeReceipt } from "../gate-stages.mjs";
|
|
74
74
|
import { spawnSync as spawnInherit } from "../background-process.mjs";
|
|
75
|
+
import { readDiskPolicy, scratchRoots } from "../disk-policy.mjs";
|
|
75
76
|
|
|
76
77
|
const ZERO = /^0+$/;
|
|
77
78
|
const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -234,6 +235,23 @@ function workspaceMetadata({ root, spawn, cargoCommand, dir, realpath }) {
|
|
|
234
235
|
* here. The gate itself uses discoverRustWorkspaces, which handles every workspace of the repository. Returns
|
|
235
236
|
* { present, units: [{ name, dir, publish }], cargoDir, uncovered }.
|
|
236
237
|
*/
|
|
238
|
+
/**
|
|
239
|
+
* Where the snapshot export lives. The RustRight broker refuses a job whose workspace is on the system volume
|
|
240
|
+
* (RK_INTERNAL_DRIVE_REFUSED: agents never write to the internal drive), and os.tmpdir() is on it on every Mac and Dell, so on a
|
|
241
|
+
* host with a disk-policy scratch root (/Volumes/D/scratch, D:\scratch) the export goes there. RK_GATE_TMPDIR overrides; os.tmpdir()
|
|
242
|
+
* is the fallback where no scratch root exists (CI runners, cloud containers), where plain cargo runs and nothing refuses the system
|
|
243
|
+
* volume. (rightkit#1215)
|
|
244
|
+
*/
|
|
245
|
+
export function exportTmpRoot({ env = process.env, platform = process.platform, exists = fs.existsSync, policy = null } = {}) {
|
|
246
|
+
if (env.RK_GATE_TMPDIR) return env.RK_GATE_TMPDIR;
|
|
247
|
+
try {
|
|
248
|
+
const roots = scratchRoots(policy ?? readDiskPolicy(), { platform, env });
|
|
249
|
+
const found = roots.find((root) => exists(root));
|
|
250
|
+
if (found) return found;
|
|
251
|
+
} catch { /* no readable policy: the system temp dir */ }
|
|
252
|
+
return os.tmpdir();
|
|
253
|
+
}
|
|
254
|
+
|
|
237
255
|
export function discoverRustUnits({ root, spawn, cargoCommand, tracked, readFile, realpath = fs.realpathSync }) {
|
|
238
256
|
const manifests = tracked("Cargo.toml");
|
|
239
257
|
if (!manifests.length) return { present: false, units: [], cargoDir: ".", uncovered: [] };
|
|
@@ -1464,7 +1482,7 @@ export async function main(argv, io = {}) {
|
|
|
1464
1482
|
try {
|
|
1465
1483
|
let repo = root;
|
|
1466
1484
|
if (snapshot) {
|
|
1467
|
-
exportRoot = fs.mkdtempSync(path.join(o.env.
|
|
1485
|
+
exportRoot = fs.mkdtempSync(path.join(exportTmpRoot({ env: o.env, platform: o.platform, exists: o.exists }), "rk-gate-"));
|
|
1468
1486
|
repo = path.join(exportRoot, "repo");
|
|
1469
1487
|
// Every file of the commit or tree: read-tree into a private index, then checkout-index. `git archive` would leave out files
|
|
1470
1488
|
// marked export-ignore in .gitattributes, so they would never be scanned; this export has no such exclusion.
|
|
@@ -1476,6 +1494,16 @@ export async function main(argv, io = {}) {
|
|
|
1476
1494
|
fs.mkdirSync(repo, { recursive: true });
|
|
1477
1495
|
const x = failed(made) ? made : o.spawn("git", ["checkout-index", "--all", "--force", `--prefix=${repo.split(path.sep).join("/")}/`], { cwd: root, env: indexEnv });
|
|
1478
1496
|
if (failed(made) || failed(x)) { o.err(`${tag} cannot export ${snapshot}: ${why(made) || why(x)}`); return 2; }
|
|
1497
|
+
// rustright binds the tracked .rightkit-local-build.json grant to the origin URL in .git/config (rustright-policy local_build.rs),
|
|
1498
|
+
// and the export has no .git, so cargo metadata in it was refused on every broker host and no push passed the hook (rightkit#1215).
|
|
1499
|
+
// A config-only .git carries exactly the source checkout's origin and is not a repository to git (no HEAD, no objects), so nothing
|
|
1500
|
+
// can run git against the export. No origin (a checkout without a remote): nothing is written and rustright decides as before.
|
|
1501
|
+
const origin = o.spawn("git", ["config", "--get", "remote.origin.url"], { cwd: root });
|
|
1502
|
+
const originUrl = failed(origin) ? "" : text(origin).trim();
|
|
1503
|
+
if (originUrl) {
|
|
1504
|
+
o.mkdir(path.join(repo, ".git"), { recursive: true });
|
|
1505
|
+
o.writeFile(path.join(repo, ".git", "config"), `[remote "origin"]\n\turl = ${originUrl}\n`);
|
|
1506
|
+
}
|
|
1479
1507
|
}
|
|
1480
1508
|
// Every file of the snapshot, once: units, manifests, lockfiles and the changed set are all read from what is scanned, never from
|
|
1481
1509
|
// the live checkout (a live edit cannot change what gets planned).
|
package/door.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The door check for an app's own build step: a command its right-release.config.mjs declares (a payload assembler, an installer
|
|
2
|
+
// packager) that right-release runs inside a stage. The step proceeds only when a live `rightkit-gate --to` run for HEAD launched it,
|
|
3
|
+
// the same check right-release makes for itself (gate-stages.mjs requireDoorRun), so `node scripts/release/<step>.mjs` run by hand is
|
|
4
|
+
// refused instead of becoming a side door around class A.
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { spawnSync } from "./background-process.mjs";
|
|
7
|
+
import { requireDoorRun } from "./gate-stages.mjs";
|
|
8
|
+
|
|
9
|
+
/** null when a live door run for HEAD launched this process, else the refusal message. */
|
|
10
|
+
export function doorRefusal({ cwd = process.cwd(), env = process.env, command = "this build step", run = spawnSync, alive } = {}) {
|
|
11
|
+
const git = (args) => { const r = run("git", args, { cwd, encoding: "utf8" }); return r.status === 0 ? String(r.stdout).trim() : ""; };
|
|
12
|
+
const common = git(["rev-parse", "--git-common-dir"]);
|
|
13
|
+
if (!common) return `${command} runs only in a git checkout, through the one door: rightkit-gate --to <stage>`;
|
|
14
|
+
return requireDoorRun({ env, commonDir: path.resolve(cwd, common), commit: git(["rev-parse", "HEAD"]), command, ...(alive ? { alive } : {}) });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Exits 2 with the refusal unless a live door run launched this process. */
|
|
18
|
+
export function requireDoor(command, options = {}) {
|
|
19
|
+
const refusal = doorRefusal({ ...options, command });
|
|
20
|
+
if (!refusal) return;
|
|
21
|
+
process.stderr.write(`${refusal}\n`);
|
|
22
|
+
process.exit(2);
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rightkit/release",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
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",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"./direct-bootstrap.mjs": "./direct-bootstrap.mjs",
|
|
20
20
|
"./disk-policy.mjs": "./disk-policy.mjs",
|
|
21
21
|
"./dmg-build.mjs": "./dmg-build.mjs",
|
|
22
|
+
"./door.mjs": "./door.mjs",
|
|
22
23
|
"./engine-locator.mjs": "./engine-locator.mjs",
|
|
23
24
|
"./github-release.mjs": "./github-release.mjs",
|
|
24
25
|
"./legal-contract.mjs": "./legal-contract.mjs",
|
package/rightkit-versions.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@rightkit/qa": "0.6.1",
|
|
33
33
|
"@rightkit/qa-chrome": "0.1.12",
|
|
34
34
|
"@rightkit/react-shell": "0.7.2",
|
|
35
|
-
"@rightkit/release": "0.6.
|
|
35
|
+
"@rightkit/release": "0.6.8",
|
|
36
36
|
"@rightkit/settings-ui": "0.7.0",
|
|
37
37
|
"@rightkit/tauri": "0.3.0",
|
|
38
38
|
"@rightkit/tauri-shell": "0.1.3",
|