@rightkit/release 0.2.61 → 0.2.63
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 +86 -22
- package/build-release.test.mjs +31 -2
- package/cargo-contract.mjs +3 -2
- package/cargo-guard.test.mjs +1 -0
- package/cli/right-release.mjs +2 -2
- package/github-release.mjs +25 -10
- package/heavy-command.mjs +27 -11
- package/heavy-command.test.mjs +49 -0
- package/package.json +4 -3
- package/process-liveness.mjs +39 -0
- package/release-cli-contract.test.mjs +17 -6
- package/release-state.mjs +27 -3
- package/release-state.test.mjs +48 -6
- package/release.mjs +15 -15
- package/release.test.mjs +24 -2
- package/right-suite-contract.test.mjs +22 -6
- package/rightkit-versions.json +5 -2
- package/standalone-clone-evidence.json +32 -0
- package/target-bridge.mjs +2 -2
- package/target-bridge.test.mjs +17 -0
- package/upload-release.mjs +36 -170
package/release-state.mjs
CHANGED
|
@@ -46,14 +46,16 @@ export function commandOutputPortable(cmd, args, { cwd, env = process.env } = {}
|
|
|
46
46
|
return result.stdout.trim();
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export function watchProgress(paths, onProgress) {
|
|
49
|
+
export function watchProgress(paths, onProgress, { maxFallbackWatchers = 128, watchFactory = watch, readDirectory = readdirSync } = {}) {
|
|
50
|
+
if (!Number.isInteger(maxFallbackWatchers) || maxFallbackWatchers < 1) throw new TypeError("maxFallbackWatchers must be a positive integer");
|
|
50
51
|
const watchers = [];
|
|
52
|
+
const fallback = { remaining: maxFallbackWatchers };
|
|
51
53
|
for (const candidate of paths) {
|
|
52
54
|
if (!candidate || !existsSync(candidate)) continue;
|
|
53
55
|
try {
|
|
54
|
-
watchers.push(
|
|
56
|
+
watchers.push(watchFactory(candidate, { recursive: true }, onProgress));
|
|
55
57
|
} catch {
|
|
56
|
-
|
|
58
|
+
watchDirectoryTree(candidate, onProgress, watchers, fallback, { watchFactory, readDirectory });
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
return () => {
|
|
@@ -61,6 +63,23 @@ export function watchProgress(paths, onProgress) {
|
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
function watchDirectoryTree(root, onProgress, watchers, fallback, { watchFactory = watch, readDirectory = readdirSync } = {}) {
|
|
67
|
+
const pending = [root];
|
|
68
|
+
const visited = new Set();
|
|
69
|
+
while (pending.length) {
|
|
70
|
+
const directory = pending.pop();
|
|
71
|
+
if (visited.has(directory)) continue;
|
|
72
|
+
visited.add(directory);
|
|
73
|
+
if (fallback.remaining <= 0) return;
|
|
74
|
+
try { watchers.push(watchFactory(directory, onProgress)); fallback.remaining -= 1; } catch { /* output still counts as progress */ }
|
|
75
|
+
let entries;
|
|
76
|
+
try { entries = readDirectory(directory, { withFileTypes: true }); } catch { continue; }
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
if (entry.isDirectory()) pending.push(path.join(directory, entry.name));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
64
83
|
export function releaseEnvironment({ root, cacheRoot, platform, architecture, app, cacheKey, kind = "release", appRoot, mode = "legacy", env = process.env }) {
|
|
65
84
|
if (kind !== "release" && kind !== "test") throw new Error(`invalid target kind: ${kind}`);
|
|
66
85
|
if (mode !== "legacy" && mode !== "shared") throw new Error(`invalid cache mode: ${mode}`);
|
|
@@ -75,6 +94,11 @@ export function releaseEnvironment({ root, cacheRoot, platform, architecture, ap
|
|
|
75
94
|
SCCACHE_CACHE_SIZE: `${policy.sccacheMaxBytes / 1024 ** 3}G`,
|
|
76
95
|
SCCACHE_BASEDIRS: [path.resolve(root), path.resolve(appRoot)].join(path.delimiter),
|
|
77
96
|
RUSTC_WRAPPER: "sccache",
|
|
97
|
+
// Doc-mandated (architecture section 5): a dropped sccache connection must
|
|
98
|
+
// fall through to plain rustc, not fail the build. Without this, a single
|
|
99
|
+
// transient server disconnect (seen on Windows as error 10054) kills a
|
|
100
|
+
// build that would otherwise have compiled fine uncached.
|
|
101
|
+
SCCACHE_IGNORE_SERVER_IO_ERROR: "1",
|
|
78
102
|
RIGHT_RELEASE_CACHE_OWNER: "rightkit-v2",
|
|
79
103
|
};
|
|
80
104
|
}
|
package/release-state.test.mjs
CHANGED
|
@@ -23,20 +23,59 @@ test("progress watcher observes writes in nested Cargo target directories", asyn
|
|
|
23
23
|
const root = mkdtempSync(path.join(os.tmpdir(), "right-release-watch-"));
|
|
24
24
|
const nested = path.join(root, "release", "build", "openssl");
|
|
25
25
|
mkdirSync(nested, { recursive: true });
|
|
26
|
+
const readyFile = path.join(root, "watch-ready");
|
|
27
|
+
const nestedFile = path.join(nested, "object.lib");
|
|
28
|
+
let resolveReady;
|
|
26
29
|
let resolveProgress;
|
|
30
|
+
const ready = new Promise((resolve) => { resolveReady = resolve; });
|
|
27
31
|
const progress = new Promise((resolve) => { resolveProgress = resolve; });
|
|
28
|
-
const close = watchProgress([root],
|
|
32
|
+
const close = watchProgress([root], (_eventType, filename) => {
|
|
33
|
+
const eventName = String(filename ?? "");
|
|
34
|
+
if (eventName === path.basename(readyFile)) resolveReady();
|
|
35
|
+
if (eventName.endsWith(path.basename(nestedFile))) resolveProgress();
|
|
36
|
+
});
|
|
29
37
|
try {
|
|
30
|
-
await
|
|
31
|
-
await
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
39
|
+
await writeFile(readyFile, "ready");
|
|
40
|
+
await waitForEvent(ready, "watcher readiness event missing");
|
|
41
|
+
await writeFile(nestedFile, "progress");
|
|
42
|
+
await waitForEvent(progress, "nested progress event missing");
|
|
43
|
+
} finally {
|
|
44
|
+
close();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("fallback progress watchers cap open handles when recursive watching is unavailable", () => {
|
|
49
|
+
const root = mkdtempSync(path.join(os.tmpdir(), "right-release-watch-cap-"));
|
|
50
|
+
for (let index = 0; index < 10; index += 1) mkdirSync(path.join(root, `dir-${index}`));
|
|
51
|
+
const opened = [];
|
|
52
|
+
const close = watchProgress([root], () => {}, {
|
|
53
|
+
maxFallbackWatchers: 3,
|
|
54
|
+
watchFactory: (directory, options) => {
|
|
55
|
+
if (options?.recursive) throw new Error("recursive watch unsupported");
|
|
56
|
+
opened.push(directory);
|
|
57
|
+
return { close: () => {} };
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
assert.equal(opened.length, 3);
|
|
35
62
|
} finally {
|
|
36
63
|
close();
|
|
37
64
|
}
|
|
38
65
|
});
|
|
39
66
|
|
|
67
|
+
async function waitForEvent(event, message) {
|
|
68
|
+
let timer;
|
|
69
|
+
try {
|
|
70
|
+
await Promise.race([
|
|
71
|
+
event,
|
|
72
|
+
new Promise((_, reject) => { timer = setTimeout(() => reject(new Error(message)), 5_000); }),
|
|
73
|
+
]);
|
|
74
|
+
} finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
40
79
|
test("portable command capture resolves Windows command shims", { skip: process.platform !== "win32" }, () => {
|
|
41
80
|
assert.equal(commandOutputPortable("pnpm", ["--version"]), expectedPnpmVersion);
|
|
42
81
|
});
|
|
@@ -66,6 +105,9 @@ test("shared release environment is isolated from the app vault", () => {
|
|
|
66
105
|
assert.match(env.CARGO_HOME, /RightSuite[\\/]release[\\/]cargo-home$/);
|
|
67
106
|
assert.equal(env.RIGHT_RELEASE_CACHE_OWNER, "rightkit-v2");
|
|
68
107
|
assert.equal(env.SCCACHE_CACHE_SIZE, "32G");
|
|
108
|
+
// A dropped sccache server connection must fall through to plain rustc
|
|
109
|
+
// instead of failing the build; seen on Windows as a bare error 10054.
|
|
110
|
+
assert.equal(env.SCCACHE_IGNORE_SERVER_IO_ERROR, "1");
|
|
69
111
|
});
|
|
70
112
|
|
|
71
113
|
test("shared release environment honors the cache policy override", () => {
|
package/release.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import { assertPrimaryReleaseCheckout, dirtyBuildInputs, resolveReleaseBuildInpu
|
|
|
12
12
|
import { collectPreflight, formatPreflight, preflightFailures } from "./preflight.mjs";
|
|
13
13
|
import { patchTauriBundleType } from "./tauri-bundle-marker.mjs";
|
|
14
14
|
import { verifyNsisEmbeddedBinary } from "./nsis-payload.mjs";
|
|
15
|
+
import { terminateProcessTree } from "./heavy-command.mjs";
|
|
15
16
|
|
|
16
17
|
const TOOL_ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const HARDENING_SCAN = path.resolve(TOOL_ROOT, "hardeningscan.mjs");
|
|
@@ -29,6 +30,7 @@ const RIGHTKIT_ALLOWED = buildAllowedVersions(
|
|
|
29
30
|
const RIGHTKIT_CARGO_ALLOWED = buildAllowedVersions(RIGHTKIT_VERSIONS.cargo, RIGHTKIT_VERSIONS.stagedCargo);
|
|
30
31
|
const FORBIDDEN_RIGHTKIT_SPEC = /^(?:git|file|link|workspace):|github|github\.com/i;
|
|
31
32
|
const WINDOWS_SIGNING_CONTRACT = "windows-raw-exe-authenticode-before-nsis-v1";
|
|
33
|
+
const DEFAULT_NOTARIZATION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
32
34
|
|
|
33
35
|
const args = process.argv.slice(2);
|
|
34
36
|
const opts = {
|
|
@@ -344,7 +346,18 @@ async function runPackageScript(pm, script, cwd) {
|
|
|
344
346
|
|
|
345
347
|
async function runCommand(command, root) {
|
|
346
348
|
const cwd = path.resolve(root, command.cwd ?? ".");
|
|
347
|
-
await run(command.cmd, command.args ?? [], cwd, await commandEnv(command, root),
|
|
349
|
+
await run(command.cmd, command.args ?? [], cwd, await commandEnv(command, root), {
|
|
350
|
+
...command,
|
|
351
|
+
timeoutMs: commandTimeoutMs(command),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function commandTimeoutMs(command) {
|
|
356
|
+
if (Object.hasOwn(command, "timeoutMs")) return command.timeoutMs;
|
|
357
|
+
const tokens = [command.cmd, ...(command.args ?? [])].map((value) => String(value));
|
|
358
|
+
return command.notarize === true || command.notarization === true || tokens.some((value) => /notari[sz]/i.test(value))
|
|
359
|
+
? DEFAULT_NOTARIZATION_TIMEOUT_MS
|
|
360
|
+
: undefined;
|
|
348
361
|
}
|
|
349
362
|
|
|
350
363
|
async function validateRightKitPackageContract(root, appName) {
|
|
@@ -624,18 +637,5 @@ function processCommandLine(pid) {
|
|
|
624
637
|
}
|
|
625
638
|
|
|
626
639
|
function killProcessTree(pid) {
|
|
627
|
-
|
|
628
|
-
if (process.platform === "win32") {
|
|
629
|
-
spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
const children = spawnSync("pgrep", ["-P", String(pid)], { encoding: "utf8" });
|
|
633
|
-
for (const child of (children.stdout ?? "").split(/\s+/).filter(Boolean)) {
|
|
634
|
-
killProcessTree(Number(child));
|
|
635
|
-
}
|
|
636
|
-
try {
|
|
637
|
-
process.kill(pid, "SIGKILL");
|
|
638
|
-
} catch {
|
|
639
|
-
// already gone
|
|
640
|
-
}
|
|
640
|
+
terminateProcessTree(pid);
|
|
641
641
|
}
|
package/release.test.mjs
CHANGED
|
@@ -16,7 +16,7 @@ function git(cwd, ...args) {
|
|
|
16
16
|
return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function fixture({ signed = true, publish = false, signingContract = "windows-raw-exe-authenticode-before-nsis-v1", prePackageFiles = ["raw.exe"], packageJson, cargoManifest, cargoConfig, repoCargoConfig, siblingCargoManifest, buildInputs = defaultBuildInputs, platform = "win" } = {}) {
|
|
19
|
+
function fixture({ signed = true, publish = false, signingContract = "windows-raw-exe-authenticode-before-nsis-v1", prePackageFiles = ["raw.exe"], packageJson, packageCommand, cargoManifest, cargoConfig, repoCargoConfig, siblingCargoManifest, buildInputs = defaultBuildInputs, platform = "win" } = {}) {
|
|
20
20
|
const fixtureRoot = mkdtempSync(path.join(os.tmpdir(), "right-release-test-"));
|
|
21
21
|
const dir = repoCargoConfig ? path.join(fixtureRoot, "apps", "fixture") : fixtureRoot;
|
|
22
22
|
mkdirSync(dir, { recursive: true });
|
|
@@ -49,7 +49,7 @@ function fixture({ signed = true, publish = false, signingContract = "windows-ra
|
|
|
49
49
|
[platform]: {
|
|
50
50
|
...(buildInputs ? { buildInputs } : {}),
|
|
51
51
|
signed,
|
|
52
|
-
package: { cmd: "node", args: ["-e", "process.exit(0)"] },
|
|
52
|
+
package: packageCommand ?? { cmd: "node", args: ["-e", "process.exit(0)"] },
|
|
53
53
|
...(publish ? { publish: { cmd: "node", args: ["publish-update.mjs"] } } : {}),
|
|
54
54
|
artifacts: [],
|
|
55
55
|
...(platform === "win" ? { signingContract, prePackage: { cmd: "node", args: ["-e", "process.exit(0)"] }, sign: { prePackageFiles, files: ["fixture.exe"] } } : {}),
|
|
@@ -159,6 +159,28 @@ test("accepts a tier-neutral internal build", () => {
|
|
|
159
159
|
assert.doesNotMatch(result.stdout, /RIGHT_RELEASE_TIER=/);
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
+
test("notarization commands default to a bounded 30-minute timeout without changing explicit overrides", () => {
|
|
163
|
+
const defaultResult = runRaw(fixture({
|
|
164
|
+
platform: "mac",
|
|
165
|
+
packageCommand: { cmd: "node", args: ["-e", "process.exit(0)", "--notarize"] },
|
|
166
|
+
}), "--platform", "mac", "--dry-run");
|
|
167
|
+
assert.equal(defaultResult.status, 0, defaultResult.stderr);
|
|
168
|
+
assert.match(defaultResult.stdout, /timeout=1800000ms/);
|
|
169
|
+
|
|
170
|
+
const explicitResult = runRaw(fixture({
|
|
171
|
+
platform: "mac",
|
|
172
|
+
packageCommand: { cmd: "node", args: ["-e", "process.exit(0)", "--notarize"], timeoutMs: 1234 },
|
|
173
|
+
}), "--platform", "mac", "--dry-run");
|
|
174
|
+
assert.equal(explicitResult.status, 0, explicitResult.stderr);
|
|
175
|
+
assert.match(explicitResult.stdout, /timeout=1234ms/);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("release worker reuses owned process-tree termination for Windows and remote command descendants", () => {
|
|
179
|
+
const source = readFileSync(release, "utf8");
|
|
180
|
+
assert.match(source, /import \{ terminateProcessTree \} from "\.\/heavy-command\.mjs"/);
|
|
181
|
+
assert.match(source, /function killProcessTree\(pid\) \{\s*terminateProcessTree\(pid\);\s*\}/s);
|
|
182
|
+
});
|
|
183
|
+
|
|
162
184
|
test("accepts patch and exposes it to the signed package command", () => {
|
|
163
185
|
const result = run(fixture(), "--tier=patch");
|
|
164
186
|
assert.equal(result.status, 0, result.stderr);
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
assertPublishedRightKitCargoDependencies,
|
|
11
11
|
cargoArguments,
|
|
12
12
|
cargoExecutable,
|
|
13
|
+
isolatedCargoMetadataEnv,
|
|
13
14
|
validateRightKitCargoContract,
|
|
14
15
|
} from "./cargo-contract.mjs";
|
|
15
16
|
import { assertAsrAdapterPair } from "./asr-artifact-adoption.mjs";
|
|
@@ -126,7 +127,7 @@ function readCargoManifestContract(manifestPath, label) {
|
|
|
126
127
|
{
|
|
127
128
|
cwd: path.dirname(manifestPath),
|
|
128
129
|
encoding: "utf8",
|
|
129
|
-
env:
|
|
130
|
+
env: isolatedCargoMetadataEnv(isolatedCargoHome),
|
|
130
131
|
windowsHide: true,
|
|
131
132
|
},
|
|
132
133
|
);
|
|
@@ -462,15 +463,16 @@ test("RightKit exposes one current version manifest", () => {
|
|
|
462
463
|
assert.deepEqual(versions.stagedNpm, {
|
|
463
464
|
"@rightkit/ax": "0.2.0",
|
|
464
465
|
"@rightkit/git": "0.2.0",
|
|
466
|
+
"@rightkit/hooks": "0.1.0",
|
|
465
467
|
"@rightkit/legal": "0.3.0",
|
|
466
468
|
"@rightkit/legal-ui": "0.1.1",
|
|
467
469
|
"@rightkit/license": "0.1.6",
|
|
468
|
-
"@rightkit/release": "0.2.
|
|
470
|
+
"@rightkit/release": "0.2.63",
|
|
469
471
|
"@rightkit/qa": "0.2.0",
|
|
470
472
|
});
|
|
471
473
|
assert.deepEqual(versions.legacyNpm, {
|
|
472
474
|
"@rightkit/legal-ui": ["0.1.0"],
|
|
473
|
-
"@rightkit/release": ["0.2.22", "0.2.29", "0.2.30", "0.2.31", "0.2.41", "0.2.42", "0.2.43", "0.2.44", "0.2.45", "0.2.46", "0.2.49", "0.2.50", "0.2.51", "0.2.53", "0.2.54", "0.2.55", "0.2.56"],
|
|
475
|
+
"@rightkit/release": ["0.2.22", "0.2.29", "0.2.30", "0.2.31", "0.2.41", "0.2.42", "0.2.43", "0.2.44", "0.2.45", "0.2.46", "0.2.49", "0.2.50", "0.2.51", "0.2.53", "0.2.54", "0.2.55", "0.2.56", "0.2.61", "0.2.62"],
|
|
474
476
|
"@rightkit/qa": ["0.1.0"],
|
|
475
477
|
});
|
|
476
478
|
assert.ok(
|
|
@@ -496,12 +498,26 @@ test("RightKit exposes one current version manifest", () => {
|
|
|
496
498
|
getCurrentCargoVersionContract();
|
|
497
499
|
});
|
|
498
500
|
|
|
499
|
-
test("Cargo metadata uses
|
|
500
|
-
assert.equal(cargoExecutable("win32"), "
|
|
501
|
-
assert.deepEqual(cargoArguments(["metadata"], "win32"), ["
|
|
501
|
+
test("Cargo metadata uses managed Cargo directly on Windows", () => {
|
|
502
|
+
assert.equal(cargoExecutable("win32"), "cargo");
|
|
503
|
+
assert.deepEqual(cargoArguments(["metadata"], "win32"), ["metadata"]);
|
|
502
504
|
assert.equal(cargoExecutable("darwin"), "cargo");
|
|
503
505
|
});
|
|
504
506
|
|
|
507
|
+
test("Cargo metadata delegates controlled storage to managed RightKit", () => {
|
|
508
|
+
const ambient = {
|
|
509
|
+
CARGO_HOME: "/ambient/cargo",
|
|
510
|
+
CARGO_TARGET_DIR: "/ambient/target",
|
|
511
|
+
RIGHTKIT_BUILD_BROKER_SOCKET: "/managed/broker.sock",
|
|
512
|
+
};
|
|
513
|
+
assert.deepEqual(isolatedCargoMetadataEnv("/isolated/cargo", ambient), {
|
|
514
|
+
RIGHTKIT_BUILD_BROKER_SOCKET: "/managed/broker.sock",
|
|
515
|
+
});
|
|
516
|
+
assert.deepEqual(isolatedCargoMetadataEnv("/isolated/cargo", { CARGO_HOME: "/ambient/cargo" }), {
|
|
517
|
+
CARGO_HOME: "/isolated/cargo",
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
|
|
505
521
|
test("license v2 public vector is identical at every portable consumer boundary", () => {
|
|
506
522
|
const canonical = readFileSync(
|
|
507
523
|
path.join(workspace, "tools/rightkit/crates/rightkit-license/test-vectors/license-v2.json"),
|
package/rightkit-versions.json
CHANGED
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
"stagedNpm": {
|
|
16
16
|
"@rightkit/ax": "0.2.0",
|
|
17
17
|
"@rightkit/git": "0.2.0",
|
|
18
|
+
"@rightkit/hooks": "0.1.0",
|
|
18
19
|
"@rightkit/legal": "0.3.0",
|
|
19
20
|
"@rightkit/legal-ui": "0.1.1",
|
|
20
21
|
"@rightkit/license": "0.1.6",
|
|
21
|
-
"@rightkit/release": "0.2.
|
|
22
|
+
"@rightkit/release": "0.2.63",
|
|
22
23
|
"@rightkit/qa": "0.2.0"
|
|
23
24
|
},
|
|
24
25
|
"legacyNpm": {
|
|
@@ -42,7 +43,9 @@
|
|
|
42
43
|
"0.2.53",
|
|
43
44
|
"0.2.54",
|
|
44
45
|
"0.2.55",
|
|
45
|
-
"0.2.56"
|
|
46
|
+
"0.2.56",
|
|
47
|
+
"0.2.61",
|
|
48
|
+
"0.2.62"
|
|
46
49
|
],
|
|
47
50
|
"@rightkit/qa": [
|
|
48
51
|
"0.1.0"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"generatedAt": "2026-08-10T04:42:36.444Z",
|
|
4
|
+
"workRoot": "C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR",
|
|
5
|
+
"apps": [
|
|
6
|
+
{
|
|
7
|
+
"key": "viewright",
|
|
8
|
+
"remote": "https://github.com/bogusyogi/viewright.git",
|
|
9
|
+
"appDir": ".",
|
|
10
|
+
"revision": "21a4171fa8add2d8114bc5f07498b60d7e8eafe5",
|
|
11
|
+
"packageManager": "pnpm@11.18.0",
|
|
12
|
+
"clone": {
|
|
13
|
+
"command": "git clone --depth 1 --single-branch https://github.com/bogusyogi/viewright.git C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright",
|
|
14
|
+
"status": 0,
|
|
15
|
+
"stdout": "",
|
|
16
|
+
"stderr": "Cloning into 'C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright'...\nUpdating files: 91% (1902/2080)\rUpdating files: 92% (1914/2080)\rUpdating files: 93% (1935/2080)\rUpdating files: 94% (1956/2080)\rUpdating files: 95% (1976/2080)\rUpdating files: 96% (1997/2080)\rUpdating files: 97% (2018/2080)\rUpdating files: 98% (2039/2080)\rUpdating files: 99% (2060/2080)\rUpdating files: 100% (2080/2080)\rUpdating files: 100% (2080/2080), done."
|
|
17
|
+
},
|
|
18
|
+
"install": {
|
|
19
|
+
"command": "C:\\nvm4w\\nodejs\\node.exe C:\\nvm4w\\nodejs\\node_modules\\pnpm\\bin\\pnpm.mjs install --frozen-lockfile",
|
|
20
|
+
"status": 0,
|
|
21
|
+
"stdout": "✓ Lockfile passes supply-chain policies (verified 8h ago)\nLockfile is up to date, resolution step is skipped\nProgress: resolved 1, reused 0, downloaded 0, added 0\nPackages: +619\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\nProgress: resolved 619, reused 0, downloaded 0, added 0\nProgress: resolved 619, reused 60, downloaded 0, added 0\nPackages are hard linked from the content-addressable store to the virtual store.\n Content-addressable store is at: C:\\Users\\adrds\\AppData\\Local\\pnpm\\store\\v11\n Virtual store is at: node_modules/.pnpm\nProgress: resolved 619, reused 573, downloaded 7, added 7\nProgress: resolved 619, reused 574, downloaded 9, added 10\nProgress: resolved 619, reused 574, downloaded 22, added 11\nProgress: resolved 619, reused 574, downloaded 23, added 11\nProgress: resolved 619, reused 574, downloaded 26, added 14\nProgress: resolved 619, reused 574, downloaded 30, added 24\nProgress: resolved 619, reused 574, downloaded 31, added 57\nProgress: resolved 619, reused 574, downloaded 34, added 128\nProgress: resolved 619, reused 574, downloaded 38, added 135\nProgress: resolved 619, reused 574, downloaded 38, added 136\nProgress: resolved 619, reused 574, downloaded 39, added 141\nProgress: resolved 619, reused 574, downloaded 39, added 148\nProgress: resolved 619, reused 574, downloaded 39, added 182\nProgress: resolved 619, reused 574, downloaded 40, added 201\nProgress: resolved 619, reused 574, downloaded 41, added 218\nProgress: resolved 619, reused 574, downloaded 41, added 242\nProgress: resolved 619, reused 574, downloaded 42, added 312\nProgress: resolved 619, reused 574, downloaded 42, added 371\nProgress: resolved 619, reused 574, downloaded 42, added 430\nProgress: resolved 619, reused 574, downloaded 42, added 486\nProgress: resolved 619, reused 574, downloaded 43, added 543\nProgress: resolved 619, reused 574, downloaded 43, added 578\nProgress: resolved 619, reused 574, downloaded 44, added 596\nProgress: resolved 619, reused 574, downloaded 44, added 611\nProgress: resolved 619, reused 574, downloaded 44, added 612\nProgress: resolved 619, reused 574, downloaded 44, added 613\nProgress: resolved 619, reused 574, downloaded 44, added 615\nProgress: resolved 619, reused 574, downloaded 44, added 616\nProgress: resolved 619, reused 574, downloaded 44, added 617\nProgress: resolved 619, reused 574, downloaded 44, added 618\nProgress: resolved 619, reused 574, downloaded 45, added 618\nProgress: resolved 619, reused 574, downloaded 45, added 619\nProgress: resolved 619, reused 574, downloaded 45, added 619, done\n\ndependencies:\n+ @codemirror/autocomplete 6.20.3\n+ @codemirror/commands 6.10.4\n+ @codemirror/lang-html 6.4.11\n+ @codemirror/lang-javascript 6.2.5\n+ @codemirror/lang-markdown 6.5.0\n+ @codemirror/language 6.12.4\n+ @codemirror/lint 6.9.7\n+ @codemirror/search 6.7.1\n+ @codemirror/state 6.7.1\n+ @codemirror/view 6.43.6\n+ @eigenpal/docx-editor-agents @eigenpal/docx-editor-agents@file:vendor/docx-editor/packages/agents(react@19.2.7)\n+ @eigenpal/docx-editor-core @eigenpal/docx-editor-core@file:vendor/docx-editor/packages/core(prosemirror-commands@1.7.1)(prosemirror-dropcursor@1.8.2)(prosemirror-history@1.5.0)(prosemirror-keymap@1.2.3)(prosemirror-model@1.25.10)(prosemirror-state@1.4.4)(prosemirror-tables@1.8.5)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.0)\n+ @eigenpal/docx-editor-i18n @eigenpal/docx-editor-i18n@file:vendor/docx-editor/packages/i18n\n+ @eigenpal/docx-editor-react @eigenpal/docx-editor-react@file:vendor/docx-editor/packages/react(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(prosemirror-commands@1.7.1)(prosemirror-dropcursor@1.8.2)(prosemirror-history@1.5.0)(prosemirror-keymap@1.2.3)(prosemirror-model@1.25.10)(prosemirror-state@1.4.4)(prosemirror-tables@1.8.5)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)\n+ @lezer/highlight 1.2.3\n+ @mdx-js/mdx 3.1.1\n+ @phosphor-icons/react 2.1.10\n+ @radix-ui/react-select 2.3.2\n+ @rightkit/legal-ui 0.1.0\n+ @rightkit/license 0.1.6\n+ @rightkit/logs 0.1.3\n+ @rightkit/tauri 0.1.0\n+ @rightkit/updates 0.2.3\n+ @tauri-apps/api 2.11.1\n+ @tauri-apps/plugin-http 2.5.9\n+ @tauri-apps/plugin-process 2.3.1\n+ @tauri-apps/plugin-updater 2.10.1\n+ clsx 2.1.1\n+ docxtemplater 3.69.0\n+ dompurify 3.4.13\n+ fabric 7.4.0\n+ github-slugger 2.0.0\n+ jszip 3.10.1\n+ katex 0.17.0\n+ mermaid 11.16.1\n+ pdfjs-dist 6.2.108\n+ pizzip 3.2.0\n+ prosemirror-commands 1.7.1\n+ prosemirror-dropcursor 1.8.2\n+ prosemirror-history 1.5.0\n+ prosemirror-keymap 1.2.3\n+ prosemirror-model 1.25.10\n+ prosemirror-state 1.4.4\n+ prosemirror-tables 1.8.5\n+ prosemirror-transform 1.12.0\n+ prosemirror-view 1.42.0\n+ react 19.2.7\n+ react-dom 19.2.7\n+ react-image-crop 11.1.2\n+ rehype-stringify 10.0.1\n+ remark-frontmatter 5.0.0\n+ remark-gfm 4.0.1\n+ remark-math 6.0.0\n+ remark-parse 11.0.0\n+ remark-rehype 11.1.2\n+ remark-smartypants 3.0.2\n+ shiki 4.3.1\n+ sonner 2.0.7\n+ sucrase 3.35.1\n+ unified 11.0.5\n+ xml-js 1.6.11\n+ yaml 2.9.0\n\ndevDependencies:\n+ @biomejs/biome 2.5.3\n+ @rightkit/legal 0.3.0\n+ @rightkit/release 0.2.50\n+ @tailwindcss/vite 4.3.2\n+ @tauri-apps/cli 2.11.4\n+ @testing-library/dom 10.4.1\n+ @testing-library/jest-dom 6.9.1\n+ @testing-library/react 16.3.2\n+ @types/mdast 4.0.4\n+ @types/react 19.2.17\n+ @types/react-dom 19.2.3\n+ @types/ws 8.18.1\n+ @vitejs/plugin-react 6.0.3\n+ happy-dom 20.10.6\n+ jscpd 5.0.12\n+ jsdom 29.1.1\n+ knip 6.25.0\n+ tailwindcss 4.3.2\n+ typescript 6.0.3\n+ vite 8.1.4\n+ vitest 4.1.10\n+ ws 8.21.0\n\nDone in 40.8s using pnpm v11.18.0",
|
|
22
|
+
"stderr": ""
|
|
23
|
+
},
|
|
24
|
+
"doctor": {
|
|
25
|
+
"command": "C:\\nvm4w\\nodejs\\node.exe C:\\nvm4w\\nodejs\\node_modules\\pnpm\\bin\\pnpm.mjs release:doctor",
|
|
26
|
+
"status": 0,
|
|
27
|
+
"stdout": "right-release 0.2.50\nconfig: C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright\\right-release.config.mjs\napp: viewright\nplatform: win\ntier: <required for release/publish>\npackageManager: pnpm\nworkdir: C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright\nhardeningscan: C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright\\node_modules\\.pnpm\\@rightkit+release@0.2.50\\node_modules\\@rightkit\\release\\hardeningscan.mjs\nlegal: C:\\Users\\adrds\\AppData\\Local\\Temp\\rightkit-standalone-sBI0iR\\viewright\\legal\\legal-manifest.json\nlegalAcceptance: viewright-2026-07-17-v3\nlegalManifestSha256: 035ea7cbd040ef001dbdc1385f114c8bb126178fea9a9f705016a726f96a7830\nsign: src-tauri/target/release/bundle/nsis/ViewRight_0.1.60_x64-setup.exe\npreflight:\n [ok ] target-bridge: src-tauri/target is ready for the shared cache bridge\n [ok ] version: 0.1.60 is free to build\n [ok ] windows-sdk: makeappx.exe from SDK 10.0.26100.0\n [ok ] signtool: signtool.exe from SDK 10.0.26100.0\n [ok ] sccache: sccache 0.17.0\n [ok ] disk: 628.7GB free",
|
|
28
|
+
"stderr": "$ right-release doctor"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
package/target-bridge.mjs
CHANGED
|
@@ -51,7 +51,7 @@ export function createTargetBridge({
|
|
|
51
51
|
}
|
|
52
52
|
mkdir(target, { recursive: true });
|
|
53
53
|
if (!entry) {
|
|
54
|
-
symlink(target, link,
|
|
54
|
+
symlink(target, link, "dir");
|
|
55
55
|
entry = lstat(link);
|
|
56
56
|
if (!entry.isSymbolicLink()) throw new Error(`RightKit target bridge was not created as a symbolic link: ${link}`);
|
|
57
57
|
if (!sameRealPath(link, target, realpath, platform)) {
|
|
@@ -64,7 +64,7 @@ export function createTargetBridge({
|
|
|
64
64
|
// Stale link from an earlier fingerprint, or one whose cache entry a
|
|
65
65
|
// prune already removed. Both are ours to repoint.
|
|
66
66
|
unlink(link);
|
|
67
|
-
symlink(target, link,
|
|
67
|
+
symlink(target, link, "dir");
|
|
68
68
|
entry = lstat(link);
|
|
69
69
|
if (!sameRealPath(link, target, realpath, platform)) {
|
|
70
70
|
throw new Error(`RightKit target bridge did not repoint to the owned shared cache target: ${link}`);
|
package/target-bridge.test.mjs
CHANGED
|
@@ -27,6 +27,23 @@ test("removes an invocation-created bridge after success without touching the sh
|
|
|
27
27
|
assert.equal(readFileSync(path.join(fx.target, "keep.txt"), "utf8"), "shared-cache\n");
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
test("Windows creates a directory symlink instead of an untrusted junction", () => {
|
|
31
|
+
const fx = fixture();
|
|
32
|
+
let requestedType;
|
|
33
|
+
const bridge = createTargetBridge({
|
|
34
|
+
...fx,
|
|
35
|
+
platform: "win32",
|
|
36
|
+
symlink(target, link, type) {
|
|
37
|
+
requestedType = type;
|
|
38
|
+
symlinkSync(target, link, type);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
bridge.ensure();
|
|
42
|
+
assert.equal(requestedType, "dir");
|
|
43
|
+
assert.equal(realpathSync(fx.link), realpathSync(fx.target));
|
|
44
|
+
bridge.release();
|
|
45
|
+
});
|
|
46
|
+
|
|
30
47
|
test("removes an invocation-created bridge after the build throws", async () => {
|
|
31
48
|
const fx = fixture();
|
|
32
49
|
const bridge = createTargetBridge(fx);
|