@stacksjs/buddy 0.70.211 → 0.70.213
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.
|
@@ -24,6 +24,14 @@ declare interface AppleDesktopOptions {
|
|
|
24
24
|
skipBuild?: boolean
|
|
25
25
|
validateOnly?: boolean
|
|
26
26
|
packageOnly?: boolean
|
|
27
|
+
plan?: boolean
|
|
28
|
+
apply?: boolean
|
|
29
|
+
capabilities?: string
|
|
30
|
+
appCertificateCsr?: string
|
|
31
|
+
installerCertificateCsr?: string
|
|
32
|
+
profileName?: string
|
|
33
|
+
output?: string
|
|
34
|
+
commonName?: string
|
|
27
35
|
}
|
|
28
36
|
export declare interface AppleDesktopConfig {
|
|
29
37
|
appName: string
|
|
@@ -150,11 +150,20 @@ export function renderAppleWorkflowCaller() {
|
|
|
150
150
|
on:
|
|
151
151
|
workflow_dispatch:
|
|
152
152
|
inputs:
|
|
153
|
+
release-tag:
|
|
154
|
+
description: Git tag used for the GitHub release
|
|
155
|
+
required: true
|
|
156
|
+
type: string
|
|
153
157
|
validate-only:
|
|
154
158
|
description: Validate the signed package without uploading it
|
|
155
159
|
required: false
|
|
156
160
|
default: true
|
|
157
161
|
type: boolean
|
|
162
|
+
mirror-s3:
|
|
163
|
+
description: Mirror artifacts to the configured S3-compatible release registry
|
|
164
|
+
required: false
|
|
165
|
+
default: false
|
|
166
|
+
type: boolean
|
|
158
167
|
|
|
159
168
|
jobs:
|
|
160
169
|
publish:
|
|
@@ -164,9 +173,18 @@ jobs:
|
|
|
164
173
|
bundle-id: \${{ vars.APPLE_BUNDLE_ID }}
|
|
165
174
|
team-id: \${{ vars.APPLE_TEAM_ID }}
|
|
166
175
|
desktop-url: \${{ vars.DESKTOP_URL }}
|
|
176
|
+
app-version: \${{ vars.APPLE_APP_VERSION }}
|
|
167
177
|
app-signing-identity: \${{ vars.APPLE_APP_SIGNING_IDENTITY }}
|
|
168
178
|
installer-signing-identity: \${{ vars.APPLE_INSTALLER_SIGNING_IDENTITY }}
|
|
179
|
+
release-tag: \${{ inputs.release-tag }}
|
|
169
180
|
validate-only: \${{ inputs.validate-only }}
|
|
181
|
+
mirror-s3: \${{ inputs.mirror-s3 }}
|
|
182
|
+
s3-provider: \${{ vars.RELEASE_S3_PROVIDER || 'hetzner' }}
|
|
183
|
+
s3-bucket: \${{ vars.RELEASE_S3_BUCKET }}
|
|
184
|
+
s3-region: \${{ vars.RELEASE_S3_REGION }}
|
|
185
|
+
s3-endpoint: \${{ vars.RELEASE_S3_ENDPOINT }}
|
|
186
|
+
s3-prefix: \${{ vars.RELEASE_S3_PREFIX }}
|
|
187
|
+
s3-public-url: \${{ vars.RELEASE_S3_PUBLIC_URL }}
|
|
170
188
|
secrets: inherit
|
|
171
189
|
`;
|
|
172
190
|
}
|
|
@@ -324,6 +342,102 @@ function fail(error) {
|
|
|
324
342
|
process.exit(1);
|
|
325
343
|
}
|
|
326
344
|
export function desktopApple(buddy) {
|
|
345
|
+
buddy.command("desktop:apple:csr", "Generate local private keys and CSRs for Mac App Store distribution certificates").option("--common-name <name>", "Certificate request common name").option("--output <path>", "Directory for private keys and certificate requests").action(async (options) => {
|
|
346
|
+
try {
|
|
347
|
+
const metadata = packageMetadata(), outputDirectory = resolve(options.output || storagePath("framework/desktop-dist/apple/provisioning")), { generateMacCertificateRequests } = await import("ts-pantry");
|
|
348
|
+
generateMacCertificateRequests({
|
|
349
|
+
outputDirectory,
|
|
350
|
+
commonName: options.commonName || metadata.name
|
|
351
|
+
});
|
|
352
|
+
log.success(`Generated Apple certificate requests and private keys in ${outputDirectory}`);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
fail(error);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
buddy.command("desktop:apple:provision", "Plan or reconcile Apple Bundle ID, capabilities, certificates, and profile").option("--app-name <name>", "Mac App Store display name").option("--bundle-id <id>", "Reverse-DNS bundle identifier").option("--api-key-id <id>", "App Store Connect API key ID").option("--api-issuer-id <id>", "App Store Connect API issuer ID").option("--api-key-path <path>", "App Store Connect AuthKey .p8 file").option("--capabilities <types>", "Comma-separated Apple capability types").option("--app-certificate-csr <path>", "CSR for a missing Mac App Distribution certificate").option("--installer-certificate-csr <path>", "CSR for a missing Mac Installer Distribution certificate").option("--profile-name <name>", "Provisioning profile name").option("--output <path>", "Directory for the plan and downloaded Apple assets").option("--plan", "Report the idempotent Apple resource diff without mutating it").option("--apply", "Apply the Apple resource diff without revoking existing certificates").action(async (options) => {
|
|
358
|
+
try {
|
|
359
|
+
if (options.plan && options.apply)
|
|
360
|
+
throw Error("Choose either --plan or --apply");
|
|
361
|
+
const config = resolveAppleDesktopConfig(options);
|
|
362
|
+
if (!config.bundleId)
|
|
363
|
+
throw Error("APPLE_BUNDLE_ID or --bundle-id is required");
|
|
364
|
+
if (!config.apiKeyId || !config.apiIssuerId || !config.apiKeyPath || !existsSync(config.apiKeyPath))
|
|
365
|
+
throw Error("App Store Connect API key ID, issuer ID, and existing .p8 key path are required");
|
|
366
|
+
const readCsr = (file) => {
|
|
367
|
+
if (!file)
|
|
368
|
+
return;
|
|
369
|
+
const resolved = resolve(file);
|
|
370
|
+
if (!existsSync(resolved))
|
|
371
|
+
throw Error(`Apple certificate CSR does not exist: ${resolved}`);
|
|
372
|
+
return readFileSync(resolved, "utf8");
|
|
373
|
+
}, { exportAppleCertificateP12, provisionMacApp } = await import("ts-pantry"), result = await provisionMacApp({
|
|
374
|
+
identifier: config.bundleId,
|
|
375
|
+
name: config.appName,
|
|
376
|
+
capabilities: options.capabilities?.split(",").map((value) => value.trim()).filter(Boolean),
|
|
377
|
+
appCertificateCsr: readCsr(options.appCertificateCsr),
|
|
378
|
+
installerCertificateCsr: readCsr(options.installerCertificateCsr),
|
|
379
|
+
profileName: options.profileName,
|
|
380
|
+
keyId: config.apiKeyId,
|
|
381
|
+
issuerId: config.apiIssuerId,
|
|
382
|
+
keyPath: config.apiKeyPath,
|
|
383
|
+
checkOnly: !options.apply
|
|
384
|
+
}), outputDirectory = resolve(options.output || storagePath("framework/desktop-dist/apple/provisioning"));
|
|
385
|
+
mkdirSync(outputDirectory, { recursive: !0 });
|
|
386
|
+
for (const certificate of result.certificates) {
|
|
387
|
+
if (!certificate.certificateContent)
|
|
388
|
+
continue;
|
|
389
|
+
const fileName = certificate.type === "MAC_APP_DISTRIBUTION" ? "mac-app-distribution.cer" : "mac-installer-distribution.cer";
|
|
390
|
+
writeFileSync(join(outputDirectory, fileName), Buffer.from(certificate.certificateContent, "base64"), { mode: 384 });
|
|
391
|
+
}
|
|
392
|
+
if (result.profile.profileContent)
|
|
393
|
+
writeFileSync(join(outputDirectory, "mac-app-store.provisionprofile"), Buffer.from(result.profile.profileContent, "base64"), { mode: 384 });
|
|
394
|
+
const certificatePassword = env("APPLE_CERTIFICATE_PASSWORD"), certificateExports = [
|
|
395
|
+
{
|
|
396
|
+
type: "MAC_APP_DISTRIBUTION",
|
|
397
|
+
csr: options.appCertificateCsr,
|
|
398
|
+
certificate: "mac-app-distribution.cer",
|
|
399
|
+
output: "mac-app-distribution.p12",
|
|
400
|
+
name: `${config.appName} Mac App Distribution`
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
type: "MAC_INSTALLER_DISTRIBUTION",
|
|
404
|
+
csr: options.installerCertificateCsr,
|
|
405
|
+
certificate: "mac-installer-distribution.cer",
|
|
406
|
+
output: "mac-installer-distribution.p12",
|
|
407
|
+
name: `${config.appName} Mac Installer Distribution`
|
|
408
|
+
}
|
|
409
|
+
];
|
|
410
|
+
for (const certificateExport of certificateExports) {
|
|
411
|
+
if (!result.certificates.find((item) => item.type === certificateExport.type)?.certificateContent || !certificateExport.csr || !certificatePassword)
|
|
412
|
+
continue;
|
|
413
|
+
exportAppleCertificateP12({
|
|
414
|
+
certificatePath: join(outputDirectory, certificateExport.certificate),
|
|
415
|
+
privateKeyPath: resolve(certificateExport.csr.replace(/\.csr$/i, ".key")),
|
|
416
|
+
outputPath: join(outputDirectory, certificateExport.output),
|
|
417
|
+
password: certificatePassword,
|
|
418
|
+
name: certificateExport.name
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
const certificates = result.certificates.map((item) => {
|
|
422
|
+
const certificate = { ...item };
|
|
423
|
+
delete certificate.certificateContent;
|
|
424
|
+
return certificate;
|
|
425
|
+
}), profile = { ...result.profile };
|
|
426
|
+
delete profile.profileContent;
|
|
427
|
+
const report = {
|
|
428
|
+
...result,
|
|
429
|
+
certificates,
|
|
430
|
+
profile
|
|
431
|
+
}, reportPath = join(outputDirectory, "provisioning-plan.json");
|
|
432
|
+
writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}
|
|
433
|
+
`, { mode: 384 });
|
|
434
|
+
log.success(`${options.apply ? "Applied" : "Planned"} Apple provisioning: ${reportPath}`);
|
|
435
|
+
if (!result.appRecord.exists)
|
|
436
|
+
log.warn(result.appRecord.manualAction);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
fail(error);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
327
441
|
buddy.command("desktop:apple:doctor", "Validate Mac App Store tooling, credentials, certificates, and project metadata").option("--app-name <name>", "Mac App Store display name").option("--bundle-id <id>", "Reverse-DNS bundle identifier").option("--team-id <id>", "Apple Developer team ID").option("--app-signing-identity <identity>", "Mac App Distribution signing identity").option("--installer-signing-identity <identity>", "Mac Installer Distribution signing identity").option("--provisioning-profile <path>", "Mac App Store provisioning profile").option("--api-key-id <id>", "App Store Connect API key ID").option("--api-issuer-id <id>", "App Store Connect API issuer ID").option("--api-key-path <path>", "App Store Connect AuthKey .p8 file").action((options) => {
|
|
328
442
|
try {
|
|
329
443
|
const config = resolveAppleDesktopConfig(options), errors = validateAppleDesktopConfig(config, !0);
|
|
@@ -27,7 +27,7 @@ describe("desktop lifecycle workflow", () => {
|
|
|
27
27
|
it("retains artifacts through maintained Node 24 action runtimes", () => {
|
|
28
28
|
expect(repositoryWorkflows).not.toMatch(/actions\/upload-artifact@v[1-6]\b/);
|
|
29
29
|
expect(repositoryWorkflows).not.toMatch(/actions\/download-artifact@v[1-7]\b/);
|
|
30
|
-
expect(repositoryWorkflows.match(/actions\/upload-artifact@v7\b/g)).toHaveLength(
|
|
30
|
+
expect(repositoryWorkflows.match(/actions\/upload-artifact@v7\b/g)).toHaveLength(4);
|
|
31
31
|
expect(repositoryWorkflows.match(/actions\/download-artifact@v8\b/g)).toHaveLength(1);
|
|
32
32
|
});
|
|
33
33
|
});
|
package/dist/lazy-commands.js
CHANGED
|
@@ -17,8 +17,10 @@ const commandRegistry = {
|
|
|
17
17
|
deploy: { path: "./commands/deploy.js", exportName: "deploy" },
|
|
18
18
|
dev: { path: "./commands/dev.js", exportName: "dev" },
|
|
19
19
|
"desktop:apple:doctor": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
20
|
+
"desktop:apple:csr": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
20
21
|
"desktop:apple:init": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
21
22
|
"desktop:apple:package": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
23
|
+
"desktop:apple:provision": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
22
24
|
"desktop:apple:publish": { path: "./commands/desktop-apple.js", exportName: "desktopApple" },
|
|
23
25
|
dns: { path: "./commands/dns.js", exportName: "dns" },
|
|
24
26
|
"dns:pull": { path: "./commands/dns.js", exportName: "dns" },
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.213",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -139,7 +139,8 @@
|
|
|
139
139
|
"@stacksjs/validation": "^0.70.180",
|
|
140
140
|
"@stacksjs/ts-cloud": "^0.7.86",
|
|
141
141
|
"ajv": "^8.20.0",
|
|
142
|
-
"ajv-formats": "^3.0.1"
|
|
142
|
+
"ajv-formats": "^3.0.1",
|
|
143
|
+
"ts-pantry": "^0.11.0"
|
|
143
144
|
},
|
|
144
145
|
"devDependencies": {
|
|
145
146
|
"better-dx": "^0.2.17"
|