@omega.js/desktop 0.50.0 → 0.52.0
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 +2 -2
- package/dist/assets/css/tokens/_index.scss +1 -1
- package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
- package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
- package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
- package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
- package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
- package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
- package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
- package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
- package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
- package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
- package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
- package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
- package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
- package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
- package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
- package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
- package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
- package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
- package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
- package/dist/build.js +69 -28
- package/dist/cli-run.js +20 -13
- package/dist/cli.js +12 -7
- package/dist/commands/build.js +0 -2
- package/dist/commands/deploy.js +116 -44
- package/dist/commands/finalize-release.js +5 -4
- package/dist/commands/launch.js +12 -7
- package/dist/commands/lib/deploy-precheck.js +66 -34
- package/dist/commands/lib/ensure-target.js +71 -11
- package/dist/commands/package.js +0 -1
- package/dist/commands/publish.js +11 -4
- package/dist/commands/release.js +99 -252
- package/dist/commands/runner.js +176 -42
- package/dist/commands/sign-windows.js +46 -15
- package/dist/commands/test.js +4 -3
- package/dist/commands/validate-certs.js +291 -115
- package/dist/config/page-template.html +4 -0
- package/dist/defaults/.github/workflows/build.yml +146 -64
- package/dist/defaults/AGENTS.md +3 -2
- package/dist/defaults/_.gitignore +4 -2
- package/dist/defaults/config/certs/README.md +25 -45
- package/dist/defaults/config/omega.json5 +66 -32
- package/dist/defaults/hooks/deploy/pre.js +10 -0
- package/dist/defaults/src/assets/scss/main.scss +12 -2
- package/dist/defaults/src/integrations/tray/index.js +1 -1
- package/dist/gulp/main.js +13 -25
- package/dist/gulp/tasks/audit.js +18 -6
- package/dist/gulp/tasks/build-config.js +181 -60
- package/dist/gulp/tasks/bundle.js +108 -36
- package/dist/gulp/tasks/release.js +86 -4
- package/dist/gulp/tasks/sass.js +11 -0
- package/dist/hooks/lib/notarize-tools.js +137 -0
- package/dist/hooks/notarize-artifacts.js +57 -0
- package/dist/hooks/notarize.js +59 -8
- package/dist/lib/auth-persistence.js +25 -0
- package/dist/lib/client-bridge.js +11 -8
- package/dist/lib/deep-link.js +15 -8
- package/dist/lib/protocol.js +7 -1
- package/dist/lib/restart-manager/install.js +6 -3
- package/dist/lib/sign-helpers/auto-unlock.js +65 -27
- package/dist/lib/sign-helpers/console-lock.js +34 -0
- package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
- package/dist/lib/sign-helpers/resolve-icons.js +6 -4
- package/dist/lib/tray.js +7 -6
- package/dist/main.js +16 -0
- package/dist/preload.js +8 -0
- package/dist/renderer.js +16 -4
- package/dist/runner/job-started.js +104 -0
- package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
- package/dist/test/fixtures/consumer-app/package.json +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
- package/dist/test/harness/main-entry.js +2 -1
- package/dist/test/harness/renderer-preload.js +12 -3
- package/dist/test/runners/boot.js +101 -11
- package/dist/test/runners/electron.js +1 -1
- package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
- package/dist/test/suites/build/audit.test.js +45 -6
- package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
- package/dist/test/suites/build/auto-unlock.test.js +105 -0
- package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
- package/dist/test/suites/build/brand-scss.test.js +106 -0
- package/dist/test/suites/build/build-config.test.js +146 -36
- package/dist/test/suites/build/build-json-bake.test.js +245 -0
- package/dist/test/suites/build/build-verbs.test.js +48 -15
- package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
- package/dist/test/suites/build/cli.test.js +32 -10
- package/dist/test/suites/build/config-schema.test.js +4 -4
- package/dist/test/suites/build/console-lock.test.js +51 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
- package/dist/test/suites/build/deploy-direct.test.js +241 -0
- package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
- package/dist/test/suites/build/deploy-hook.test.js +169 -0
- package/dist/test/suites/build/ensure-target.test.js +14 -2
- package/dist/test/suites/build/env-delivery.test.js +19 -10
- package/dist/test/suites/build/env-watch.test.js +18 -7
- package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
- package/dist/test/suites/build/exec-with-limit.test.js +53 -0
- package/dist/test/suites/build/finalize-release.test.js +2 -2
- package/dist/test/suites/build/get-config.test.js +120 -8
- package/dist/test/suites/build/github-utils.test.js +12 -6
- package/dist/test/suites/build/license-stamp.test.js +6 -4
- package/dist/test/suites/build/manager.test.js +88 -68
- package/dist/test/suites/build/manifest-deps.test.js +116 -0
- package/dist/test/suites/build/merge-line-files.test.js +27 -4
- package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
- package/dist/test/suites/build/notarize-tools.test.js +38 -0
- package/dist/test/suites/build/notarize.test.js +207 -0
- package/dist/test/suites/build/release-pipeline.test.js +38 -60
- package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
- package/dist/test/suites/build/resolve-icons.test.js +35 -35
- package/dist/test/suites/build/runner-job-guard.test.js +182 -0
- package/dist/test/suites/build/runner.test.js +635 -5
- package/dist/test/suites/build/sentry.test.js +8 -3
- package/dist/test/suites/build/setup-scripts.test.js +3 -0
- package/dist/test/suites/build/sign-windows.test.js +92 -8
- package/dist/test/suites/build/test-stealth.test.js +17 -11
- package/dist/test/suites/build/url-helpers.test.js +37 -17
- package/dist/test/suites/build/validate-certs.test.js +428 -55
- package/dist/test/suites/build/validate-config.test.js +3 -3
- package/dist/test/suites/main/auth-flow.test.js +12 -0
- package/dist/test/suites/main/auth-persistence.test.js +14 -17
- package/dist/test/suites/main/auto-updater.test.js +2 -2
- package/dist/test/suites/main/boot-sequence.test.js +1 -1
- package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
- package/dist/test/suites/main/client-bridge.test.js +19 -6
- package/dist/test/suites/main/deep-link.test.js +54 -0
- package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
- package/dist/test/suites/main/url-helpers.test.js +81 -72
- package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
- package/dist/utils/build-pipeline.js +10 -10
- package/dist/utils/github.js +12 -51
- package/dist/utils/load-env.js +66 -0
- package/dist/utils/mode-helpers.js +43 -111
- package/dist/utils/platform.js +37 -0
- package/dist/utils/runner-env.js +2 -1
- package/dist/utils/runner-job-guard.js +149 -0
- package/dist/utils/ship-keys.js +52 -0
- package/dist/utils/test-stealth.js +5 -3
- package/dist/utils/url-helpers.js +33 -17
- package/dist/vendor/config/bundle-id.js +53 -0
- package/dist/vendor/config/client-config.js +141 -0
- package/dist/vendor/config/company.js +334 -15
- package/dist/vendor/config/dev-facts.js +48 -0
- package/dist/vendor/config/env-delivery.js +231 -9
- package/dist/vendor/config/env-retired.js +137 -0
- package/dist/vendor/config/env-rules.js +22 -3
- package/dist/vendor/config/env-schema.js +234 -117
- package/dist/vendor/config/env.js +55 -26
- package/dist/vendor/config/environment.js +189 -0
- package/dist/vendor/config/hooks.js +13 -11
- package/dist/vendor/config/index.js +125 -44
- package/dist/vendor/config/load.js +366 -115
- package/dist/vendor/config/merge.js +2 -2
- package/dist/vendor/config/order.js +3 -3
- package/dist/vendor/config/platforms.js +276 -0
- package/dist/vendor/config/repo.js +249 -103
- package/dist/vendor/config/retired-keys.js +232 -27
- package/dist/vendor/config/schema.js +525 -99
- package/dist/vendor/config/site-global.js +63 -53
- package/dist/vendor/config/targets.js +187 -0
- package/dist/vendor/config/validate.js +119 -59
- package/dist/vendor/devkit/argv.js +118 -0
- package/dist/vendor/devkit/attach-log-file.js +21 -13
- package/dist/vendor/devkit/brand-tokens.js +278 -0
- package/dist/vendor/devkit/brand-version.js +425 -0
- package/dist/vendor/devkit/build-json.js +91 -0
- package/dist/vendor/devkit/bundle.js +48 -0
- package/dist/vendor/devkit/certificate-expiry.js +108 -0
- package/dist/vendor/devkit/certs.js +16 -194
- package/dist/vendor/devkit/ci-workflows.js +124 -8
- package/dist/vendor/devkit/cli-router.js +3 -3
- package/dist/vendor/devkit/defaults-engine.js +69 -7
- package/dist/vendor/devkit/deploy-follow.js +297 -0
- package/dist/vendor/devkit/deploy-precheck.js +23 -8
- package/dist/vendor/devkit/deploy-record.js +11 -27
- package/dist/vendor/devkit/deploy-snapshot.js +661 -0
- package/dist/vendor/devkit/deploy.js +505 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +172 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +98 -3
- package/dist/vendor/devkit/lockfile.js +127 -0
- package/dist/vendor/devkit/merge-line-files.js +23 -16
- package/dist/vendor/devkit/omega-bin.js +18 -3
- package/dist/vendor/devkit/pack-local.js +388 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +142 -0
- package/dist/vendor/devkit/service-account.js +43 -0
- package/dist/vendor/devkit/ship-plan.js +112 -0
- package/dist/vendor/devkit/signing-env.js +180 -0
- package/dist/vendor/devkit/signing-tree.js +92 -0
- package/dist/vendor/devkit/target-seams.js +142 -0
- package/dist/vendor/devkit/target-secrets.js +231 -57
- package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
- package/dist/vendor/monitoring/env.js +20 -10
- package/dist/vendor/monitoring/main.js +1 -1
- package/dist/vendor/monitoring/preload.js +1 -1
- package/dist/vendor/monitoring/renderer.js +1 -1
- package/docs/analytics.md +1 -1
- package/docs/auto-updater.md +5 -5
- package/docs/boot-sequence.md +1 -1
- package/docs/build-system.md +15 -7
- package/docs/client-bridge.md +9 -7
- package/docs/config-schema.md +4 -4
- package/docs/css.md +8 -2
- package/docs/deep-link.md +12 -4
- package/docs/environment-detection.md +32 -24
- package/docs/hooks.md +3 -1
- package/docs/icons.md +7 -7
- package/docs/index.md +61 -23
- package/docs/installer-options.md +24 -21
- package/docs/logging.md +5 -5
- package/docs/releasing.md +29 -19
- package/docs/runner.md +51 -14
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +764 -199
- package/docs/shared/deploys.md +217 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +28 -8
- package/docs/shared/logging.md +9 -6
- package/docs/shared/monitoring.md +27 -13
- package/docs/shared/publishing.md +3 -3
- package/docs/shared/rulings.md +2 -2
- package/docs/shared/testing.md +1 -1
- package/docs/shared/theming.md +26 -1
- package/docs/shared/translation.md +49 -7
- package/docs/shared/updates.md +1 -1
- package/docs/signing.md +60 -34
- package/docs/test-framework.md +10 -5
- package/docs/themes.md +15 -1
- package/package.json +18 -12
- package/bin/omega-desktop +0 -2
- package/dist/commands/push-secrets.js +0 -141
- package/dist/test/suites/build/deliver-certs.test.js +0 -95
- package/dist/test/suites/build/derive-signing-env.test.js +0 -122
- package/dist/test/suites/build/push-secrets.test.js +0 -226
- package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
- package/dist/utils/deliver-certs.js +0 -69
- package/dist/utils/derive-signing-env.js +0 -56
- package/dist/utils/resolve-signing-cert.js +0 -175
- package/dist/vendor/config/desktop-artifacts.js +0 -110
- package/dist/vendor/config/instances.js +0 -208
- /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
|
@@ -1,100 +1,473 @@
|
|
|
1
|
-
// Build-layer tests for commands/validate-certs.js
|
|
1
|
+
// Build-layer tests for commands/validate-certs.js: what CSC_LINK is allowed to
|
|
2
|
+
// carry, the three validity rungs every surface shares
|
|
3
|
+
// ([#892](https://github.com/Omega-JS-Stack/omega/issues/892)), and the rung an
|
|
4
|
+
// UNSET key is now ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)):
|
|
5
|
+
// the step READS the env the boot derived, and the `config/certs/` scan that
|
|
6
|
+
// used to stop a deploy the build would have signed fine is gone.
|
|
2
7
|
// The full validate flow (Keychain query, env vars) is exercised via real `npx omega deploy` prechecks.
|
|
3
8
|
|
|
4
9
|
const path = require('path');
|
|
5
10
|
const fs = require('fs');
|
|
6
11
|
const os = require('os');
|
|
12
|
+
const { execFileSync } = require('child_process');
|
|
7
13
|
|
|
8
14
|
const validateCerts = require(path.join(__dirname, '..', '..', '..', 'commands', 'validate-certs.js'));
|
|
9
15
|
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
10
16
|
|
|
11
|
-
// A
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return
|
|
17
|
+
// A REAL signing certificate: a self-signed cert exported to a .p12 with a
|
|
18
|
+
// password, so the expiry read is the same openssl path a build takes.
|
|
19
|
+
function stageSigningCert({ days = 365 } = {}) {
|
|
20
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-p12-'));
|
|
21
|
+
const keyPath = path.join(dir, 'private.key');
|
|
22
|
+
const certPath = path.join(dir, 'cert.cer');
|
|
23
|
+
const p12Path = path.join(dir, 'dev-id.p12');
|
|
24
|
+
const password = 'fixture-pass';
|
|
25
|
+
|
|
26
|
+
execFileSync('openssl', [
|
|
27
|
+
'req', '-x509', '-nodes', '-newkey', 'rsa:2048', '-keyout', keyPath, '-out', certPath,
|
|
28
|
+
'-days', String(days), '-subj', '/CN=Developer ID Application: Fixture/C=US', '-outform', 'DER',
|
|
29
|
+
], { stdio: 'pipe' });
|
|
30
|
+
execFileSync('openssl', [
|
|
31
|
+
'pkcs12', '-export', '-legacy', '-inkey', keyPath, '-in', certPath, '-out', p12Path,
|
|
32
|
+
'-passout', 'env:OMEGA_P12_PASSWORD',
|
|
33
|
+
], { stdio: 'pipe', env: { ...process.env, OMEGA_P12_PASSWORD: password } });
|
|
34
|
+
|
|
35
|
+
return { dir, p12Path, password };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Run one call with exactly these env vars set (undefined deletes the key), then
|
|
39
|
+
// put the environment back the way it was. An ASYNC call holds the window until
|
|
40
|
+
// it settles: checkMac awaits the Keychain query, and a restore that fired at
|
|
41
|
+
// the first await would hand the rest of the run this machine's real signing env.
|
|
42
|
+
function withEnv(vars, run) {
|
|
43
|
+
const previous = {};
|
|
44
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
45
|
+
previous[key] = process.env[key];
|
|
46
|
+
if (value === undefined) {
|
|
47
|
+
delete process.env[key];
|
|
48
|
+
} else {
|
|
49
|
+
process.env[key] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const restore = () => {
|
|
54
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
55
|
+
if (value === undefined) {
|
|
56
|
+
delete process.env[key];
|
|
57
|
+
} else {
|
|
58
|
+
process.env[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
let result;
|
|
64
|
+
try {
|
|
65
|
+
result = run();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
restore();
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (result && typeof result.then === 'function') {
|
|
72
|
+
return result.finally(restore);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
restore();
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Run one call as if this leg were `platform`, then put the real value back.
|
|
80
|
+
// The mac rungs are darwin-only (#891), so a case about them has to say which
|
|
81
|
+
// leg it is rather than inherit the machine the suite happens to run on.
|
|
82
|
+
function withPlatform(platform, run) {
|
|
83
|
+
const descriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
84
|
+
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
85
|
+
|
|
86
|
+
const restore = () => Object.defineProperty(process, 'platform', descriptor);
|
|
87
|
+
|
|
88
|
+
let result;
|
|
89
|
+
try {
|
|
90
|
+
result = run();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
restore();
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (result && typeof result.then === 'function') {
|
|
97
|
+
return result.finally(restore);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
restore();
|
|
101
|
+
return result;
|
|
30
102
|
}
|
|
31
103
|
|
|
32
104
|
module.exports = defineCases({
|
|
33
105
|
type: 'suite',
|
|
34
106
|
layer: 'build',
|
|
35
|
-
description: 'validate-certs
|
|
107
|
+
description: 'validate-certs: the shapes CSC_LINK takes, the three validity rungs, and the unset-key rung',
|
|
36
108
|
tests: [
|
|
109
|
+
// BOTH mac credentials take three shapes
|
|
110
|
+
// ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)): a path, an https
|
|
111
|
+
// URL, or the file itself as inline base64. The build workflow ships two of them,
|
|
112
|
+
// because only the mac job decodes the base64 secrets to files, and treating that
|
|
113
|
+
// base64 as a path threw ENAMETOOLONG out of the precheck: first on CSC_LINK,
|
|
114
|
+
// then, once that was fixed, on APPLE_API_KEY.
|
|
115
|
+
// The cloud provider is read where sign-windows and the build read it,
|
|
116
|
+
// `platforms.windows.signing.cloud.provider` (#872): the checker used to look
|
|
117
|
+
// under `targets`, so a configured provider was always "not set" and its
|
|
118
|
+
// env vars were never checked.
|
|
119
|
+
{
|
|
120
|
+
name: 'the Windows cloud provider is read from platforms.windows, and its env vars are checked',
|
|
121
|
+
run: (ctx) => {
|
|
122
|
+
const config = { platforms: { windows: { signing: { strategy: 'cloud', cloud: { provider: 'azure' } } } } };
|
|
123
|
+
const azure = { AZURE_TENANT_ID: 't', AZURE_CLIENT_ID: 'c', AZURE_CLIENT_SECRET: 's', AZURE_TRUSTED_SIGNING_ENDPOINT: 'e' };
|
|
124
|
+
const none = Object.fromEntries(Object.keys(azure).map((key) => [key, undefined]));
|
|
125
|
+
|
|
126
|
+
const configured = [];
|
|
127
|
+
withEnv(azure, () => validateCerts.checkWindows(configured, 'cloud', config));
|
|
128
|
+
ctx.expect(configured).toEqual([]);
|
|
129
|
+
|
|
130
|
+
const bare = [];
|
|
131
|
+
withEnv(none, () => validateCerts.checkWindows(bare, 'cloud', config));
|
|
132
|
+
ctx.expect(bare.length).toBe(1);
|
|
133
|
+
ctx.expect(bare[0].message).toContain('Missing cloud-signing env vars for azure');
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'CSC_LINK carrying an inline base64 cert is reported, not statted',
|
|
138
|
+
run: (ctx) => {
|
|
139
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-csc-'));
|
|
140
|
+
const inline = 'MIIKvwIBAzCCCn8GCSqGSIb3DQEHAaCCCnAEggpsMIIKaDCCBR8'.repeat(60);
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
ctx.expect(validateCerts.describeCertRef(inline, tmpDir).kind).toBe('inline');
|
|
144
|
+
|
|
145
|
+
const issues = [];
|
|
146
|
+
withEnv({ CSC_KEY_PASSWORD: 'hunter2' }, () => validateCerts.checkSigningCert(issues, inline, tmpDir));
|
|
147
|
+
ctx.expect(issues).toEqual([]);
|
|
148
|
+
} finally {
|
|
149
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'CSC_LINK carrying a URL is reported, not statted',
|
|
155
|
+
run: (ctx) => {
|
|
156
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-csc-'));
|
|
157
|
+
const url = 'https://certs.example.com/dev-id.p12';
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
ctx.expect(validateCerts.describeCertRef(url, tmpDir).kind).toBe('url');
|
|
161
|
+
|
|
162
|
+
const issues = [];
|
|
163
|
+
withEnv({ CSC_KEY_PASSWORD: 'hunter2' }, () => validateCerts.checkSigningCert(issues, url, tmpDir));
|
|
164
|
+
ctx.expect(issues).toEqual([]);
|
|
165
|
+
} finally {
|
|
166
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'CSC_LINK naming a missing file is still the error it always was',
|
|
172
|
+
run: (ctx) => {
|
|
173
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-csc-'));
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const described = validateCerts.describeCertRef('config/certs/dev-id.p12', tmpDir);
|
|
177
|
+
ctx.expect(described.kind).toBe('file');
|
|
178
|
+
ctx.expect(described.exists).toBe(false);
|
|
179
|
+
|
|
180
|
+
const issues = [];
|
|
181
|
+
withEnv({ CSC_KEY_PASSWORD: 'hunter2' }, () => validateCerts.checkSigningCert(issues, 'config/certs/dev-id.p12', tmpDir));
|
|
182
|
+
ctx.expect(issues.length).toBe(1);
|
|
183
|
+
ctx.expect(issues[0].severity).toBe('error');
|
|
184
|
+
ctx.expect(issues[0].message).toContain('CSC_LINK points to a missing file');
|
|
185
|
+
} finally {
|
|
186
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
// Flipped by #891: a certificate nobody can open signs nothing, and the
|
|
192
|
+
// run that discovered this shipped an unsigned app on a warning.
|
|
193
|
+
name: 'a cert of any shape without CSC_KEY_PASSWORD is an ERROR',
|
|
194
|
+
run: (ctx) => {
|
|
195
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-csc-'));
|
|
196
|
+
const inline = 'MIIKvwIBAzCCCn8GCSqGSIb3DQEHAaCCCnAEggpsMIIKaDCCBR8'.repeat(60);
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const issues = [];
|
|
200
|
+
withEnv({ CSC_KEY_PASSWORD: undefined }, () => validateCerts.checkSigningCert(issues, inline, tmpDir));
|
|
201
|
+
ctx.expect(issues.length).toBe(1);
|
|
202
|
+
ctx.expect(issues[0].severity).toBe('error');
|
|
203
|
+
ctx.expect(issues[0].message).toContain('CSC_KEY_PASSWORD');
|
|
204
|
+
} finally {
|
|
205
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
// ── The three validity rungs, one rule (#892) ───────────────────────────
|
|
210
|
+
// The manager's certificates walk and this step read the SAME function and
|
|
211
|
+
// apply the same window, so a cert is never "fine" in one and stale in the
|
|
212
|
+
// other.
|
|
213
|
+
{
|
|
214
|
+
name: 'a real .p12 reports its expiry through the shared reader, and a healthy one raises nothing',
|
|
215
|
+
run: (ctx) => {
|
|
216
|
+
const { dir, p12Path, password } = stageSigningCert();
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const issues = [];
|
|
220
|
+
withEnv({ CSC_KEY_PASSWORD: password }, () => validateCerts.checkSigningCert(issues, p12Path, dir));
|
|
221
|
+
ctx.expect(issues).toEqual([]);
|
|
222
|
+
} finally {
|
|
223
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
},
|
|
37
227
|
{
|
|
38
|
-
name: '
|
|
228
|
+
name: 'under 30 days WARNS, expired ERRORS, and a healthy date says nothing',
|
|
39
229
|
run: (ctx) => {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
230
|
+
const days = (n) => ({ expiresAt: new Date(Date.now() + n * 86400000), daysLeft: n });
|
|
231
|
+
|
|
232
|
+
ctx.expect(validateCerts.expiryRung('config/certs/dev-id.p12', days(200))).toBeNull();
|
|
233
|
+
|
|
234
|
+
const soon = validateCerts.expiryRung('config/certs/dev-id.p12', days(10));
|
|
235
|
+
ctx.expect(soon.severity).toBe('warn');
|
|
236
|
+
ctx.expect(soon.message).toContain('expires in 10 day(s)');
|
|
237
|
+
|
|
238
|
+
const expired = validateCerts.expiryRung('config/certs/dev-id.p12', days(-5));
|
|
239
|
+
ctx.expect(expired.severity).toBe('error');
|
|
240
|
+
ctx.expect(expired.message).toContain('EXPIRED on');
|
|
241
|
+
ctx.expect(expired.message).toContain('omega manage --service certificates');
|
|
242
|
+
|
|
243
|
+
// A profile with no date at all is not a finding
|
|
244
|
+
ctx.expect(validateCerts.expiryRung('x.provisionprofile', null)).toBeNull();
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'a .p12 whose password does not open it is an error, not a silent pass',
|
|
249
|
+
run: (ctx) => {
|
|
250
|
+
const { dir, p12Path } = stageSigningCert();
|
|
46
251
|
|
|
47
252
|
try {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
ctx.expect(
|
|
51
|
-
ctx.expect(
|
|
52
|
-
|
|
253
|
+
const issues = [];
|
|
254
|
+
withEnv({ CSC_KEY_PASSWORD: 'the-wrong-password' }, () => validateCerts.checkSigningCert(issues, p12Path, dir));
|
|
255
|
+
ctx.expect(issues.length).toBe(1);
|
|
256
|
+
ctx.expect(issues[0].severity).toBe('error');
|
|
257
|
+
} finally {
|
|
258
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'APPLE_API_KEY carrying an inline base64 key is reported, not statted',
|
|
264
|
+
run: (ctx) => {
|
|
265
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-key-'));
|
|
266
|
+
const inline = 'LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tTUlHVEFnRUFNQk1HQnlxR1NNNDk'.repeat(50);
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
ctx.expect(validateCerts.describeCertRef(inline, tmpDir).kind).toBe('inline');
|
|
270
|
+
|
|
271
|
+
// An inline key has no filename, so the AuthKey_<id>.p8 cross-check has
|
|
272
|
+
// nothing to read, while the id and issuer are still wanted.
|
|
273
|
+
const issues = [];
|
|
274
|
+
withEnv({ APPLE_API_KEY_ID: 'ABCDE12345', APPLE_API_ISSUER: '00000000-0000-0000-0000-000000000000' }, () => {
|
|
275
|
+
validateCerts.checkNotarizationKey(issues, inline, tmpDir);
|
|
276
|
+
});
|
|
277
|
+
ctx.expect(issues).toEqual([]);
|
|
53
278
|
} finally {
|
|
54
279
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
55
280
|
}
|
|
56
281
|
},
|
|
57
282
|
},
|
|
58
283
|
{
|
|
59
|
-
name: '
|
|
284
|
+
name: 'an inline APPLE_API_KEY still wants its key id and issuer',
|
|
60
285
|
run: (ctx) => {
|
|
61
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-
|
|
62
|
-
const
|
|
63
|
-
fs.writeFileSync(profPath, 'this is not a plist at all');
|
|
286
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-key-'));
|
|
287
|
+
const inline = 'LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tTUlHVEFnRUFNQk1HQnlxR1NNNDk'.repeat(50);
|
|
64
288
|
|
|
65
289
|
try {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
290
|
+
const issues = [];
|
|
291
|
+
withEnv({ APPLE_API_KEY_ID: undefined, APPLE_API_ISSUER: undefined }, () => {
|
|
292
|
+
validateCerts.checkNotarizationKey(issues, inline, tmpDir);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
ctx.expect(issues.length).toBe(2);
|
|
296
|
+
ctx.expect(issues.map((issue) => issue.message).join(' ')).toContain('APPLE_API_KEY_ID is missing');
|
|
297
|
+
ctx.expect(issues.map((issue) => issue.message).join(' ')).toContain('APPLE_API_ISSUER is missing');
|
|
69
298
|
} finally {
|
|
70
299
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
71
300
|
}
|
|
72
301
|
},
|
|
73
302
|
},
|
|
74
303
|
{
|
|
75
|
-
name: '
|
|
304
|
+
name: 'APPLE_API_KEY naming a missing file is still the error it always was',
|
|
76
305
|
run: (ctx) => {
|
|
77
|
-
const
|
|
78
|
-
|
|
306
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-key-'));
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const issues = [];
|
|
310
|
+
withEnv({ APPLE_API_KEY_ID: 'ABCDE12345', APPLE_API_ISSUER: 'x' }, () => {
|
|
311
|
+
validateCerts.checkNotarizationKey(issues, 'config/certs/AuthKey.p8', tmpDir);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
ctx.expect(issues.length).toBe(1);
|
|
315
|
+
ctx.expect(issues[0].severity).toBe('error');
|
|
316
|
+
ctx.expect(issues[0].message).toContain('APPLE_API_KEY points to a missing file');
|
|
317
|
+
} finally {
|
|
318
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
319
|
+
}
|
|
79
320
|
},
|
|
80
321
|
},
|
|
81
322
|
{
|
|
82
|
-
name: '
|
|
323
|
+
name: 'a real AuthKey file still gets the filename/key-id cross-check',
|
|
83
324
|
run: (ctx) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const profPath = path.join(tmpDir, 'app.provisionprofile');
|
|
88
|
-
fs.writeFileSync(profPath, makeMockProvision({
|
|
89
|
-
appId: 'TEAMID.com.itwcw.somiibo',
|
|
90
|
-
expirationDate: new Date('2099-01-01T00:00:00Z'),
|
|
91
|
-
}));
|
|
325
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-key-'));
|
|
326
|
+
fs.mkdirSync(path.join(tmpDir, 'config', 'certs'), { recursive: true });
|
|
327
|
+
fs.writeFileSync(path.join(tmpDir, 'config', 'certs', 'AuthKey_ABCDE12345.p8'), 'key');
|
|
92
328
|
|
|
93
329
|
try {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
330
|
+
const issues = [];
|
|
331
|
+
withEnv({ APPLE_API_KEY_ID: 'ZZZZZ99999', APPLE_API_ISSUER: 'x' }, () => {
|
|
332
|
+
validateCerts.checkNotarizationKey(issues, 'config/certs/AuthKey_ABCDE12345.p8', tmpDir);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
ctx.expect(issues.length).toBe(1);
|
|
336
|
+
ctx.expect(issues[0].message).toContain('filename suggests key ID "ABCDE12345"');
|
|
337
|
+
} finally {
|
|
338
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
// #891: the boot derives CSC_LINK from the signing tree, so an unset key
|
|
344
|
+
// here means the TREE has none. The line names where it looked and the
|
|
345
|
+
// walk that fills it, and there is no `config/certs/` scan left to
|
|
346
|
+
// contradict the build beside it.
|
|
347
|
+
name: 'an unset CSC_LINK names the signing tree it looked in, never a certs-dir scan (#891)',
|
|
348
|
+
run: async (ctx) => {
|
|
349
|
+
const brand = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-brand-'));
|
|
350
|
+
fs.mkdirSync(path.join(brand, 'config'), { recursive: true });
|
|
351
|
+
fs.writeFileSync(path.join(brand, 'config', 'omega.json5'), '{ brand: { id: "b" } }');
|
|
352
|
+
const target = path.join(brand, 'targets', 'desktop');
|
|
353
|
+
fs.mkdirSync(target, { recursive: true });
|
|
354
|
+
// A .p12 sitting in the OLD dispersed location: nothing may read it.
|
|
355
|
+
fs.mkdirSync(path.join(target, 'config', 'certs'), { recursive: true });
|
|
356
|
+
fs.writeFileSync(path.join(target, 'config', 'certs', 'developer-id-application.p12'), 'stale');
|
|
357
|
+
|
|
358
|
+
const cwd = process.cwd();
|
|
359
|
+
process.chdir(target);
|
|
360
|
+
try {
|
|
361
|
+
const issues = [];
|
|
362
|
+
await withPlatform('darwin', () => withEnv({ CSC_LINK: undefined, APPLE_API_KEY: undefined, APPLE_API_KEY_ID: undefined, CSC_KEY_PASSWORD: undefined }, () => (
|
|
363
|
+
validateCerts.checkMac(issues, { certificates: { providers: { apple: { teamId: 'TEAMTEST12' } } } }, { execFn: () => Promise.resolve('') })
|
|
364
|
+
)));
|
|
365
|
+
|
|
366
|
+
const csc = issues.find((issue) => issue.message.includes('CSC_LINK'));
|
|
367
|
+
ctx.expect(csc.message).toContain('.omega/certificates/apple/certificates/DEVELOPER_ID_APPLICATION_G2.p12');
|
|
368
|
+
ctx.expect(csc.message).toContain('omega manage --service certificates');
|
|
369
|
+
ctx.expect(issues.map((issue) => issue.message).join(' ')).not.toContain('Found .p12 in config/certs/');
|
|
370
|
+
} finally {
|
|
371
|
+
process.chdir(cwd);
|
|
372
|
+
fs.rmSync(brand, { recursive: true, force: true });
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
// #891: electron-builder imports a CSC_LINK .p12 into its OWN temporary
|
|
378
|
+
// keychain, so the login keychain answers nothing about that build. The
|
|
379
|
+
// rung that read it anyway failed a runner whose file rungs had both just
|
|
380
|
+
// passed, and it now belongs to the no-CSC_LINK path alone.
|
|
381
|
+
name: 'a CSC_LINK cert never consults the Keychain, and an unset one still does (#891)',
|
|
382
|
+
run: async (ctx) => {
|
|
383
|
+
const { dir, p12Path, password } = stageSigningCert();
|
|
384
|
+
const apple = { certificates: { providers: { apple: { teamId: 'TEAMTEST12' } } } };
|
|
385
|
+
// A machine with no Developer ID identity at all.
|
|
386
|
+
const queried = [];
|
|
387
|
+
const execFn = (command) => { queried.push(command); return Promise.resolve(''); };
|
|
388
|
+
const cwd = process.cwd();
|
|
389
|
+
process.chdir(dir);
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const withCert = [];
|
|
393
|
+
await withPlatform('darwin', () => withEnv({ CSC_LINK: p12Path, CSC_KEY_PASSWORD: password, APPLE_API_KEY: p12Path, APPLE_API_KEY_ID: 'ABCDE12345', APPLE_API_ISSUER: 'x' }, () => (
|
|
394
|
+
validateCerts.checkMac(withCert, apple, { execFn })
|
|
395
|
+
)));
|
|
396
|
+
|
|
397
|
+
ctx.expect(queried).toEqual([]);
|
|
398
|
+
ctx.expect(withCert.filter((issue) => issue.severity === 'error')).toEqual([]);
|
|
399
|
+
|
|
400
|
+
const without = [];
|
|
401
|
+
await withPlatform('darwin', () => withEnv({ CSC_LINK: undefined, CSC_KEY_PASSWORD: undefined, APPLE_API_KEY: undefined, APPLE_API_KEY_ID: undefined }, () => (
|
|
402
|
+
validateCerts.checkMac(without, apple, { execFn })
|
|
403
|
+
)));
|
|
404
|
+
|
|
405
|
+
const keychain = without.find((issue) => issue.message.includes('macOS Keychain'));
|
|
406
|
+
ctx.expect(queried.length).toBe(1);
|
|
407
|
+
ctx.expect(keychain.severity).toBe('error');
|
|
408
|
+
} finally {
|
|
409
|
+
process.chdir(cwd);
|
|
410
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
// The gate the env schema already uses for the whole mac set: a brand
|
|
416
|
+
// that declares no Apple signing owes no credential, so the finding is a
|
|
417
|
+
// note rather than the rung that stops a deploy.
|
|
418
|
+
name: 'the unsigned findings are ERRORS only when the config declares Apple signing (#891)',
|
|
419
|
+
run: async (ctx) => {
|
|
420
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-gate-'));
|
|
421
|
+
const cwd = process.cwd();
|
|
422
|
+
process.chdir(tmpDir);
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
const declared = [];
|
|
426
|
+
const undeclared = [];
|
|
427
|
+
const execFn = () => Promise.resolve('');
|
|
428
|
+
await withPlatform('darwin', () => withEnv({ CSC_LINK: undefined, APPLE_API_KEY: undefined, APPLE_API_KEY_ID: undefined }, async () => {
|
|
429
|
+
await validateCerts.checkMac(declared, { certificates: { providers: { apple: { teamId: 'TEAMTEST12' } } } }, { execFn });
|
|
430
|
+
await validateCerts.checkMac(undeclared, {}, { execFn });
|
|
431
|
+
}));
|
|
432
|
+
|
|
433
|
+
const severityOf = (issues, key) => issues.find((issue) => issue.message.includes(key)).severity;
|
|
434
|
+
ctx.expect(severityOf(declared, 'CSC_LINK')).toBe('error');
|
|
435
|
+
ctx.expect(severityOf(declared, 'APPLE_API_KEY')).toBe('error');
|
|
436
|
+
ctx.expect(severityOf(undeclared, 'CSC_LINK')).toBe('warn');
|
|
437
|
+
ctx.expect(severityOf(undeclared, 'APPLE_API_KEY')).toBe('warn');
|
|
438
|
+
} finally {
|
|
439
|
+
process.chdir(cwd);
|
|
440
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
// #891: the linux and windows legs of the build workflow blank the mac
|
|
446
|
+
// credentials on purpose (they cannot sign for mac), so running the mac
|
|
447
|
+
// rungs there only prints two warnings about material nobody put on that
|
|
448
|
+
// leg. The rungs belong to the leg that ships mac, and to no other.
|
|
449
|
+
name: 'off darwin the mac rungs do not run at all (#891)',
|
|
450
|
+
run: async (ctx) => {
|
|
451
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-leg-'));
|
|
452
|
+
const cwd = process.cwd();
|
|
453
|
+
process.chdir(tmpDir);
|
|
454
|
+
|
|
455
|
+
try {
|
|
456
|
+
const queried = [];
|
|
457
|
+
const execFn = (command) => { queried.push(command); return Promise.resolve(''); };
|
|
458
|
+
|
|
459
|
+
for (const platform of ['linux', 'win32']) {
|
|
460
|
+
const issues = [];
|
|
461
|
+
await withPlatform(platform, () => withEnv({ CSC_LINK: undefined, APPLE_API_KEY: undefined, APPLE_API_KEY_ID: undefined, CSC_KEY_PASSWORD: undefined }, () => (
|
|
462
|
+
validateCerts.checkMac(issues, { certificates: { providers: { apple: { teamId: 'TEAMTEST12' } } } }, { execFn })
|
|
463
|
+
)));
|
|
464
|
+
|
|
465
|
+
ctx.expect(issues).toEqual([]);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
ctx.expect(queried).toEqual([]);
|
|
97
469
|
} finally {
|
|
470
|
+
process.chdir(cwd);
|
|
98
471
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
99
472
|
}
|
|
100
473
|
},
|
|
@@ -56,11 +56,11 @@ module.exports = defineCases({
|
|
|
56
56
|
},
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
name: 'platforms.
|
|
59
|
+
name: 'platforms.windows.signing.strategy enum enforced under desktop',
|
|
60
60
|
run: (ctx) => {
|
|
61
|
-
const cfg = { ...VALID, platforms: {
|
|
61
|
+
const cfg = { ...VALID, platforms: { windows: { signing: { strategy: 'banana' } } } };
|
|
62
62
|
const { errors } = validateConfig(cfg, { target: 'desktop' });
|
|
63
|
-
ctx.expect(errors.some((e) => e.includes('platforms.
|
|
63
|
+
ctx.expect(errors.some((e) => e.includes('platforms.windows.signing.strategy'))).toBe(true);
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
66
|
{
|
|
@@ -20,17 +20,28 @@ function get(url) {
|
|
|
20
20
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21
21
|
|
|
22
22
|
// Stub the externals for one test body. Returns { opened, tokens, shown, restore }.
|
|
23
|
+
//
|
|
24
|
+
// The baked `dev` block is staged too: the sign-in chain starts at
|
|
25
|
+
// getWebsiteUrl(), which since
|
|
26
|
+
// [#834](https://github.com/Omega-JS-Stack/omega/issues/834) answers from the
|
|
27
|
+
// resolved dev map the bundle task bakes (whose floor is @omega.js/config's
|
|
28
|
+
// classic numbers) and throws when an artifact carries none. The harness manager
|
|
29
|
+
// loads src/defaults' config, which has no build behind it, so a real dev
|
|
30
|
+
// artifact's block is stated here.
|
|
23
31
|
function stubExternals(ctx) {
|
|
24
32
|
const electron = require('electron');
|
|
33
|
+
const { CLASSIC_PORTS } = require('../../../vendor/config/index.js');
|
|
25
34
|
const opened = [];
|
|
26
35
|
const tokens = [];
|
|
27
36
|
const shown = [];
|
|
28
37
|
const origOpen = electron.shell.openExternal;
|
|
29
38
|
const origHandle = ctx.manager.omega.handleAuthToken;
|
|
30
39
|
const origShow = ctx.manager.windows.show;
|
|
40
|
+
const origDev = ctx.manager.config.dev;
|
|
31
41
|
electron.shell.openExternal = async (url) => { opened.push(url); };
|
|
32
42
|
ctx.manager.omega.handleAuthToken = (t) => { tokens.push(t); };
|
|
33
43
|
ctx.manager.windows.show = (name) => { shown.push(name); };
|
|
44
|
+
ctx.manager.config.dev = { ports: { ...CLASSIC_PORTS } };
|
|
34
45
|
return {
|
|
35
46
|
opened,
|
|
36
47
|
tokens,
|
|
@@ -39,6 +50,7 @@ function stubExternals(ctx) {
|
|
|
39
50
|
electron.shell.openExternal = origOpen;
|
|
40
51
|
ctx.manager.omega.handleAuthToken = origHandle;
|
|
41
52
|
ctx.manager.windows.show = origShow;
|
|
53
|
+
if (origDev !== undefined) ctx.manager.config.dev = origDev; else delete ctx.manager.config.dev;
|
|
42
54
|
ctx.manager.authFlow.cancel();
|
|
43
55
|
},
|
|
44
56
|
};
|
|
@@ -25,22 +25,24 @@ module.exports = defineCases({
|
|
|
25
25
|
description: 'auth-persistence (main)',
|
|
26
26
|
tests: [
|
|
27
27
|
{
|
|
28
|
-
name: 'resolve():
|
|
28
|
+
name: 'resolve(): a test run is none, whatever the config says',
|
|
29
29
|
run: async (ctx) => {
|
|
30
30
|
const m = ctx.manager;
|
|
31
|
+
ctx.expect(m.isTesting()).toBe(true);
|
|
31
32
|
m.config.omega = m.config.omega || {};
|
|
32
33
|
const orig = m.config.omega.authPersistence;
|
|
33
34
|
try {
|
|
35
|
+
// Unset, and explicitly asking for the vault, both land on none: the harness
|
|
36
|
+
// never signs a real user in, so it never asks the OS keychain
|
|
37
|
+
// ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)).
|
|
34
38
|
delete m.config.omega.authPersistence;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// both are valid environments; assert it never picks something else.
|
|
38
|
-
if (def) ctx.expect(def.name).toBe('safeStorage');
|
|
39
|
+
ctx.expect(await authPersistence.resolve(m)).toBeNull();
|
|
40
|
+
ctx.expect(authPersistence.getActive()).toBeNull();
|
|
39
41
|
|
|
40
|
-
m.config.omega.authPersistence = '
|
|
42
|
+
m.config.omega.authPersistence = 'safeStorage';
|
|
41
43
|
ctx.expect(await authPersistence.resolve(m)).toBeNull();
|
|
42
44
|
|
|
43
|
-
m.config.omega.authPersistence = '
|
|
45
|
+
m.config.omega.authPersistence = 'none';
|
|
44
46
|
ctx.expect(await authPersistence.resolve(m)).toBeNull();
|
|
45
47
|
} finally {
|
|
46
48
|
if (orig !== undefined) m.config.omega.authPersistence = orig;
|
|
@@ -50,23 +52,18 @@ module.exports = defineCases({
|
|
|
50
52
|
},
|
|
51
53
|
},
|
|
52
54
|
{
|
|
53
|
-
name: 'register(): validates the strategy surface and
|
|
55
|
+
name: 'register(): validates the strategy surface and adds it to the registry',
|
|
54
56
|
run: async (ctx) => {
|
|
55
|
-
const m = ctx.manager;
|
|
56
57
|
ctx.expect(() => authPersistence.register('bad', {})).toThrow(/must implement/);
|
|
57
58
|
|
|
58
59
|
authPersistence.register('desktop-test-custom', fakeStrategy());
|
|
59
|
-
m.config.omega = m.config.omega || {};
|
|
60
|
-
const orig = m.config.omega.authPersistence;
|
|
61
60
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
ctx.expect(
|
|
61
|
+
// Selection by config is proven at the build layer, on a production manager:
|
|
62
|
+
// under test mode resolve() answers none before it reads a thing.
|
|
63
|
+
ctx.expect(authPersistence._strategies['desktop-test-custom'].name).toBe('desktop-test-custom');
|
|
64
|
+
ctx.expect(await authPersistence._strategies['desktop-test-custom'].available()).toBe(true);
|
|
65
65
|
} finally {
|
|
66
|
-
if (orig !== undefined) m.config.omega.authPersistence = orig;
|
|
67
|
-
else delete m.config.omega.authPersistence;
|
|
68
66
|
delete authPersistence._strategies['desktop-test-custom'];
|
|
69
|
-
await authPersistence.resolve(m);
|
|
70
67
|
}
|
|
71
68
|
},
|
|
72
69
|
},
|