@rightkit/release 0.2.150 → 0.2.151
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 +3 -1
- package/build-release.mjs +9 -0
- package/macos-notarization.mjs +18 -2
- package/notarize-macos.mjs +4 -3
- package/package.json +1 -1
- package/release.mjs +4 -0
- package/rightkit-versions.json +12 -11
package/README.md
CHANGED
|
@@ -75,7 +75,9 @@ Swift (SwiftPM) apps are a first-class project type. `projectType: "swiftpm"` (c
|
|
|
75
75
|
|
|
76
76
|
`updater.kind: "appinstaller"` (default remains the Tauri minisign flow) generates `msix.appInstaller.out` (https `uri`/`msixUri`); trust is the MSIX Authenticode signature, so no `.sig` is produced and `publish-update` records the sealed package digest.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Portable macOS targets (`macos-developer-id-notarized-portable-v1`) whose `notarize.file` is an archive of bare executables set `notarize.staple: false`: the archive is notarized (Accepted) and recorded, nothing is stapled. Portable Windows and macOS targets with no installer or updater block seal their archives from `targets.<platform>.artifacts`.
|
|
79
|
+
|
|
80
|
+
Never cancel an MSIX deployment from app or updater code. Cancelling `AddPackageAsync` while it is in `RegistrationChanged` leaves the package `Modified, NeedsRemediation` (0x80073CF8, AppX event 751); the app then cannot activate, so the OnLaunch feed check never runs and cannot self-heal. Measured recovery (SwiftRight SliceApp R5 W08 tuple 08, 2026-10-10, one run per method, user data intact in every recovering case): Settings › Apps › Advanced options › Repair recovers a feed install (with or without a newer version on the feed) and a path install with no feed; `Add-AppxPackage -Path <same-version .msix>` recovers; `Add-AppxPackage -AppInstallerFile <feed uri>` recovers with or without a newer version on the feed. `Reset-AppxPackage`, `-RegisterByFamilyName`, the platform's own `RegisterByPackageFullName` (runs on every launch attempt, reports success, package stays NeedsRemediation) and relaunching do not. Not measured: Repair with the install source gone.
|
|
79
81
|
|
|
80
82
|
macOS Swift apps use `right-release swift-package mac-app` (Info.plist from config, resources, frameworks, entitlements on the bundle only; nested code signed inside-out before the app).
|
|
81
83
|
|
package/build-release.mjs
CHANGED
|
@@ -477,6 +477,15 @@ function sealRelease({ configRoot, managedCargoTarget, nativeLayout, sealedDir,
|
|
|
477
477
|
addSource(resolveArtifactPath(artifact.file), "updater");
|
|
478
478
|
if (target.updater?.kind !== "appinstaller") addSource(resolveArtifactPath(artifact.signature), "updater-signature");
|
|
479
479
|
}
|
|
480
|
+
// Portable contracts ship bare archives (zip / tar.gz) with no installer or
|
|
481
|
+
// updater block: `target.artifacts` entries (paths or { file }) seal with the
|
|
482
|
+
// "portable" role.
|
|
483
|
+
for (const artifact of target.artifacts ?? []) {
|
|
484
|
+
const file = typeof artifact === "string" ? artifact : artifact?.file;
|
|
485
|
+
if (typeof file !== "string" || !file) fail("target.artifacts entries must be paths or { file }");
|
|
486
|
+
addSource(resolveArtifactPath(file), "portable");
|
|
487
|
+
}
|
|
488
|
+
if (sources.size === 0) fail(`nothing to seal: declare installer.artifacts, updater.artifacts or artifacts for the ${platform} target`);
|
|
480
489
|
for (const file of sources.keys()) if (!existsSync(file)) fail(`cannot seal missing artifact: ${file}`);
|
|
481
490
|
const temp = `${sealedDir}.tmp-${process.pid}`;
|
|
482
491
|
if (existsSync(temp)) rmSync(temp, { recursive: true, force: true });
|
package/macos-notarization.mjs
CHANGED
|
@@ -33,7 +33,12 @@ function fileEvidence(file) {
|
|
|
33
33
|
|
|
34
34
|
// DMG/PKG receive their own ticket. For a separately submitted app ZIP,
|
|
35
35
|
// target.notarize.app (CLI --app) identifies the bundle to staple before packaging.
|
|
36
|
-
|
|
36
|
+
// `staple: false` is for archives of bare Mach-O executables (portable CLIs):
|
|
37
|
+
// the notary ticket is recorded online and nothing can carry a staple, so the
|
|
38
|
+
// receipt records `staplingSkipped` instead of stapling evidence.
|
|
39
|
+
export const STAPLING_SKIPPED_PORTABLE = "portable-executables";
|
|
40
|
+
|
|
41
|
+
export function notarizeMacosArtifact({ archive, receiptPath, authArgs, profile, app, staple = true, run = spawnSync, env = process.env, ...agentOptions }) {
|
|
37
42
|
archive = path.resolve(archive);
|
|
38
43
|
const stapleTargets = /\.(dmg|pkg)$/i.test(archive) ? [archive] : [];
|
|
39
44
|
if (app) {
|
|
@@ -41,7 +46,11 @@ export function notarizeMacosArtifact({ archive, receiptPath, authArgs, profile,
|
|
|
41
46
|
if (!/\.app$/i.test(bundle)) throw new Error(`notarize.app must name an app bundle: ${bundle}`);
|
|
42
47
|
stapleTargets.push(bundle);
|
|
43
48
|
}
|
|
44
|
-
if (
|
|
49
|
+
if (staple === false) {
|
|
50
|
+
if (stapleTargets.length) throw new Error("notarize.staple: false applies only to archives of bare executables (no .dmg/.pkg archive and no notarize.app)");
|
|
51
|
+
} else if (!stapleTargets.length) {
|
|
52
|
+
throw new Error("notarization archives require notarize.app (or --app) for stapling their app bundle, or notarize.staple: false for bare executables");
|
|
53
|
+
}
|
|
45
54
|
let result, stapling;
|
|
46
55
|
if (detectMacSigningSession({ env, run }).guiRunner) {
|
|
47
56
|
// SSH ignores API credential environment/argv entirely. Only profile name
|
|
@@ -64,6 +73,7 @@ export function notarizeMacosArtifact({ archive, receiptPath, authArgs, profile,
|
|
|
64
73
|
archive: { file: archive, ...fileEvidence(archive) },
|
|
65
74
|
notarization: { status: result.status, id: result.id ?? result.submissionId ?? null },
|
|
66
75
|
stapling,
|
|
76
|
+
...(staple === false ? { staplingSkipped: STAPLING_SKIPPED_PORTABLE } : {}),
|
|
67
77
|
};
|
|
68
78
|
mkdirSync(path.dirname(path.resolve(receiptPath)), { recursive: true });
|
|
69
79
|
writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`);
|
|
@@ -99,6 +109,12 @@ export function validateNotarizationReceipt({ receiptPath, archive, run = spawnS
|
|
|
99
109
|
|| path.resolve(receipt.archive?.file ?? "") !== archive || receipt.archive.sha256 !== fileEvidence(archive).sha256
|
|
100
110
|
|| receipt.notarization?.status !== "Accepted") throw new Error(`invalid macOS notarization receipt evidence: ${receiptPath}`);
|
|
101
111
|
const stapling = receipt.stapling;
|
|
112
|
+
if (receipt.staplingSkipped === STAPLING_SKIPPED_PORTABLE) {
|
|
113
|
+
if (/\.(dmg|pkg|app)$/i.test(archive) || !Array.isArray(stapling) || stapling.length) {
|
|
114
|
+
throw new Error(`invalid macOS notarization receipt: stapling may be skipped only for archives of bare executables: ${receiptPath}`);
|
|
115
|
+
}
|
|
116
|
+
return receipt;
|
|
117
|
+
}
|
|
102
118
|
if (!Array.isArray(stapling) || !stapling.length || stapling.some((item) => item.validated !== true || !/\.(dmg|pkg|app)$/i.test(item.file ?? ""))
|
|
103
119
|
|| (/\.(dmg|pkg|app)$/i.test(archive) && !stapling.some((item) => path.resolve(item.file) === archive))) {
|
|
104
120
|
throw new Error(`missing macOS stapling evidence: ${receiptPath}; rerun notarization before sealing`);
|
package/notarize-macos.mjs
CHANGED
|
@@ -5,14 +5,15 @@ import { notarizeMacosArtifact } from "./macos-notarization.mjs";
|
|
|
5
5
|
|
|
6
6
|
const args = process.argv.slice(2);
|
|
7
7
|
const dryRun = args.includes("--dry-run");
|
|
8
|
+
const noStaple = args.includes("--no-staple");
|
|
8
9
|
const receiptIndex = args.indexOf("--receipt");
|
|
9
10
|
const profileIndex = args.indexOf("--profile");
|
|
10
11
|
const appIndex = args.indexOf("--app");
|
|
11
12
|
const app = appIndex >= 0 ? args[appIndex + 1] : undefined;
|
|
12
13
|
const receiptPath = receiptIndex >= 0 ? args[receiptIndex + 1] : null;
|
|
13
14
|
const profile = profileIndex >= 0 ? args[profileIndex + 1] : undefined;
|
|
14
|
-
const archiveArgs = args.filter((arg, index) => arg !== "--dry-run" && arg !== "--receipt" && arg !== "--profile" && arg !== "--app" && (appIndex < 0 || index !== appIndex + 1) && (receiptIndex < 0 || index !== receiptIndex + 1) && (profileIndex < 0 || index !== profileIndex + 1));
|
|
15
|
-
if (archiveArgs.length !== 1) fail("usage: node notarize-macos.mjs [--dry-run] --receipt <path> [--profile <name>] [--app <bundle>] <archive>");
|
|
15
|
+
const archiveArgs = args.filter((arg, index) => arg !== "--dry-run" && arg !== "--no-staple" && arg !== "--receipt" && arg !== "--profile" && arg !== "--app" && (appIndex < 0 || index !== appIndex + 1) && (receiptIndex < 0 || index !== receiptIndex + 1) && (profileIndex < 0 || index !== profileIndex + 1));
|
|
16
|
+
if (archiveArgs.length !== 1) fail("usage: node notarize-macos.mjs [--dry-run] [--no-staple] --receipt <path> [--profile <name>] [--app <bundle>] <archive>");
|
|
16
17
|
if (!receiptPath || receiptPath.startsWith("--")) fail("--receipt requires a path");
|
|
17
18
|
if (appIndex >= 0 && (!app || app.startsWith("--"))) fail("--app requires an app bundle path");
|
|
18
19
|
const archive = path.resolve(archiveArgs[0]);
|
|
@@ -23,7 +24,7 @@ if (dryRun) {
|
|
|
23
24
|
if (process.platform !== "darwin") fail("macOS notarization must run on macOS");
|
|
24
25
|
if (!existsSync(archive)) fail(`missing archive: ${archive}`);
|
|
25
26
|
|
|
26
|
-
try { notarizeMacosArtifact({ archive, receiptPath, profile, app }); }
|
|
27
|
+
try { notarizeMacosArtifact({ archive, receiptPath, profile, app, staple: noStaple ? false : true }); }
|
|
27
28
|
catch (error) {
|
|
28
29
|
if (error.report) console.error(JSON.stringify(error.report));
|
|
29
30
|
fail(`${error.code ? `[${error.code}] ` : ""}${error.message}`);
|
package/package.json
CHANGED
package/release.mjs
CHANGED
|
@@ -160,6 +160,9 @@ if (opts.platform === "mac") {
|
|
|
160
160
|
if (!target.sign?.prePackageFiles?.length) fail(`${config.app ?? "app"} mac must declare at least one sign.prePackageFiles`);
|
|
161
161
|
if (!target.notarize?.file) fail(`${config.app ?? "app"} mac must declare notarize.file`);
|
|
162
162
|
if (target.notarize.appBeforePackage && !target.notarize.app) fail(`${config.app ?? "app"} mac notarize.appBeforePackage requires notarize.app`);
|
|
163
|
+
if (target.notarize.staple === false && (target.notarize.app || /\.(dmg|pkg)$/i.test(target.notarize.file))) {
|
|
164
|
+
fail(`${config.app ?? "app"} mac notarize.staple: false applies only to an archive of bare executables (no notarize.app, not a .dmg/.pkg)`);
|
|
165
|
+
}
|
|
163
166
|
const swiftDmgError = swiftMacDmgConfigError({ target, projectType: resolveProjectType({ appRoot: root, config, target }), appName: config.app ?? "app" });
|
|
164
167
|
if (swiftDmgError) fail(swiftDmgError);
|
|
165
168
|
}
|
|
@@ -931,6 +934,7 @@ async function notarizeMacos(archive, root) {
|
|
|
931
934
|
if (opts.dryRun) args.push("--dry-run");
|
|
932
935
|
args.push("--receipt", receipt);
|
|
933
936
|
if (target.notarize.profile) args.push("--profile", target.notarize.profile);
|
|
937
|
+
if (target.notarize.staple === false) args.push("--no-staple");
|
|
934
938
|
// With appBeforePackage the app already carries its own stapled ticket inside the packaged DMG.
|
|
935
939
|
if (target.notarize.app && !target.notarize.appBeforePackage) args.push("--app", resolveReleaseArtifactPath(root, target.notarize.app));
|
|
936
940
|
args.push(archive);
|
package/rightkit-versions.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@rightkit/platform-ui": "0.2.0",
|
|
30
30
|
"@rightkit/qa": "0.4.1",
|
|
31
31
|
"@rightkit/qa-chrome": "0.1.3",
|
|
32
|
-
"@rightkit/release": "0.2.
|
|
32
|
+
"@rightkit/release": "0.2.151",
|
|
33
33
|
"@rightkit/settings-ui": "0.3.1",
|
|
34
34
|
"@rightkit/shell": "0.1.0",
|
|
35
35
|
"@rightkit/tauri": "0.2.0",
|
|
@@ -186,7 +186,8 @@
|
|
|
186
186
|
"0.2.146",
|
|
187
187
|
"0.2.147",
|
|
188
188
|
"0.2.148",
|
|
189
|
-
"0.2.149"
|
|
189
|
+
"0.2.149",
|
|
190
|
+
"0.2.150"
|
|
190
191
|
],
|
|
191
192
|
"@rightkit/qa": [
|
|
192
193
|
"0.1.0",
|
|
@@ -390,9 +391,9 @@
|
|
|
390
391
|
"rightkit-watch": "0.3.1"
|
|
391
392
|
},
|
|
392
393
|
"npm": {
|
|
393
|
-
"@rightkit/app-shell": "0.
|
|
394
|
+
"@rightkit/app-shell": "0.4.0",
|
|
394
395
|
"@rightkit/ax": "0.2.4",
|
|
395
|
-
"@rightkit/doc-render": "0.1.
|
|
396
|
+
"@rightkit/doc-render": "0.1.5",
|
|
396
397
|
"@rightkit/git": "0.2.37",
|
|
397
398
|
"@rightkit/hooks": "0.1.2",
|
|
398
399
|
"@rightkit/i18n": "0.1.0",
|
|
@@ -400,17 +401,17 @@
|
|
|
400
401
|
"@rightkit/legal-ui": "0.2.0",
|
|
401
402
|
"@rightkit/license": "0.1.8",
|
|
402
403
|
"@rightkit/logs": "0.1.4",
|
|
403
|
-
"@rightkit/media-ui": "0.3.
|
|
404
|
-
"@rightkit/onboarding": "0.3.
|
|
405
|
-
"@rightkit/pdf-ui": "0.1.
|
|
404
|
+
"@rightkit/media-ui": "0.3.1",
|
|
405
|
+
"@rightkit/onboarding": "0.3.1",
|
|
406
|
+
"@rightkit/pdf-ui": "0.1.3",
|
|
406
407
|
"@rightkit/platform-ui": "0.2.0",
|
|
407
|
-
"@rightkit/qa": "0.4.
|
|
408
|
+
"@rightkit/qa": "0.4.1",
|
|
408
409
|
"@rightkit/qa-chrome": "0.1.3",
|
|
409
|
-
"@rightkit/release": "0.2.
|
|
410
|
-
"@rightkit/settings-ui": "0.3.
|
|
410
|
+
"@rightkit/release": "0.2.150",
|
|
411
|
+
"@rightkit/settings-ui": "0.3.1",
|
|
411
412
|
"@rightkit/shell": "0.1.0",
|
|
412
413
|
"@rightkit/tauri": "0.2.0",
|
|
413
|
-
"@rightkit/theme": "0.2.
|
|
414
|
+
"@rightkit/theme": "0.2.2",
|
|
414
415
|
"@rightkit/updates": "0.2.5"
|
|
415
416
|
}
|
|
416
417
|
},
|