@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
|
@@ -43,15 +43,15 @@ module.exports = defineCases({
|
|
|
43
43
|
run: async (ctx) => {
|
|
44
44
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
45
45
|
try {
|
|
46
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
46
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
47
47
|
fakePng(path.join(emDefaultsRoot, 'icons', 'windows', 'icon.png'));
|
|
48
48
|
|
|
49
49
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
50
50
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
51
51
|
|
|
52
|
-
ctx.expect(out.
|
|
52
|
+
ctx.expect(out.mac.app).toBe(path.join(distRoot, 'config', 'icons', 'mac', 'icon.png'));
|
|
53
53
|
ctx.expect(out.windows.app).toBe(path.join(distRoot, 'config', 'icons', 'windows', 'icon.png'));
|
|
54
|
-
ctx.expect(jetpack.exists(out.
|
|
54
|
+
ctx.expect(jetpack.exists(out.mac.app)).toBeTruthy();
|
|
55
55
|
ctx.expect(jetpack.exists(out.windows.app)).toBeTruthy();
|
|
56
56
|
} finally {
|
|
57
57
|
fs.rmSync(root, { recursive: true, force: true });
|
|
@@ -63,15 +63,15 @@ module.exports = defineCases({
|
|
|
63
63
|
run: async (ctx) => {
|
|
64
64
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
65
65
|
try {
|
|
66
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
67
|
-
const consumerIcon = path.join(projectRoot, 'config', 'icons', '
|
|
66
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
67
|
+
const consumerIcon = path.join(projectRoot, 'config', 'icons', 'mac', 'icon.png');
|
|
68
68
|
fakePng(consumerIcon);
|
|
69
69
|
fs.writeFileSync(consumerIcon, Buffer.from('consumer-bytes'));
|
|
70
70
|
|
|
71
71
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
72
72
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
73
73
|
|
|
74
|
-
const bytes = fs.readFileSync(out.
|
|
74
|
+
const bytes = fs.readFileSync(out.mac.app);
|
|
75
75
|
ctx.expect(bytes.toString()).toBe('consumer-bytes');
|
|
76
76
|
} finally {
|
|
77
77
|
fs.rmSync(root, { recursive: true, force: true });
|
|
@@ -84,7 +84,7 @@ module.exports = defineCases({
|
|
|
84
84
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
85
85
|
try {
|
|
86
86
|
// Bundled defaults exist for all three platforms — but consumer-global wins.
|
|
87
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
87
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
88
88
|
fakePng(path.join(emDefaultsRoot, 'icons', 'windows', 'icon.png'));
|
|
89
89
|
|
|
90
90
|
// Consumer ships ONE file at the global path. All three platforms pick it up.
|
|
@@ -95,7 +95,7 @@ module.exports = defineCases({
|
|
|
95
95
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
96
96
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
97
97
|
|
|
98
|
-
for (const platform of ['
|
|
98
|
+
for (const platform of ['mac', 'windows', 'linux']) {
|
|
99
99
|
ctx.expect(out[platform].app).toBeDefined();
|
|
100
100
|
const bytes = fs.readFileSync(out[platform].app);
|
|
101
101
|
ctx.expect(bytes.toString()).toBe('global-bytes');
|
|
@@ -118,14 +118,14 @@ module.exports = defineCases({
|
|
|
118
118
|
fs.writeFileSync(globalIcon, Buffer.from('global-bytes'));
|
|
119
119
|
|
|
120
120
|
// Mac-specific override exists — should win for macOS.
|
|
121
|
-
const macIcon = path.join(projectRoot, 'config', 'icons', '
|
|
121
|
+
const macIcon = path.join(projectRoot, 'config', 'icons', 'mac', 'icon.png');
|
|
122
122
|
fakePng(macIcon);
|
|
123
123
|
fs.writeFileSync(macIcon, Buffer.from('mac-specific-bytes'));
|
|
124
124
|
|
|
125
125
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
126
126
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
127
127
|
|
|
128
|
-
ctx.expect(fs.readFileSync(out.
|
|
128
|
+
ctx.expect(fs.readFileSync(out.mac.app).toString()).toBe('mac-specific-bytes');
|
|
129
129
|
ctx.expect(fs.readFileSync(out.windows.app).toString()).toBe('global-bytes');
|
|
130
130
|
ctx.expect(fs.readFileSync(out.linux.app).toString()).toBe('global-bytes');
|
|
131
131
|
} finally {
|
|
@@ -200,37 +200,37 @@ module.exports = defineCases({
|
|
|
200
200
|
run: async (ctx) => {
|
|
201
201
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
202
202
|
try {
|
|
203
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
203
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
204
204
|
// Input source files at retina (native) size. @omega.js/desktop should emit both @1x + @2x in dist.
|
|
205
205
|
// Tray input is `tray.png`; @omega.js/desktop renames the dist output to `trayTemplate.png` (macOS magic).
|
|
206
|
-
await realPng(path.join(emDefaultsRoot, 'icons', '
|
|
207
|
-
await realPng(path.join(emDefaultsRoot, 'icons', '
|
|
206
|
+
await realPng(path.join(emDefaultsRoot, 'icons', 'mac', 'tray.png'), 32, 32);
|
|
207
|
+
await realPng(path.join(emDefaultsRoot, 'icons', 'mac', 'dmg.png'), 1080, 760);
|
|
208
208
|
|
|
209
209
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
210
210
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
211
211
|
|
|
212
212
|
// Both @1x and @2x slots populated.
|
|
213
|
-
ctx.expect(out.
|
|
214
|
-
ctx.expect(out.
|
|
215
|
-
ctx.expect(out.
|
|
216
|
-
ctx.expect(out.
|
|
213
|
+
ctx.expect(out.mac.tray).toBeDefined();
|
|
214
|
+
ctx.expect(out.mac.tray2x).toBeDefined();
|
|
215
|
+
ctx.expect(out.mac.dmg).toBeDefined();
|
|
216
|
+
ctx.expect(out.mac.dmg2x).toBeDefined();
|
|
217
217
|
// app slot has no retina flag.
|
|
218
|
-
ctx.expect(out.
|
|
218
|
+
ctx.expect(out.mac.app2x).toBeUndefined();
|
|
219
219
|
|
|
220
220
|
// Tray output filename is trayTemplate.png (renamed for macOS auto-inversion magic).
|
|
221
|
-
ctx.expect(path.basename(out.
|
|
222
|
-
ctx.expect(path.basename(out.
|
|
221
|
+
ctx.expect(path.basename(out.mac.tray)).toBe('trayTemplate.png');
|
|
222
|
+
ctx.expect(path.basename(out.mac.tray2x)).toBe('trayTemplate@2x.png');
|
|
223
223
|
|
|
224
224
|
// @1x derived at half the @2x dimensions.
|
|
225
|
-
const tray1xMeta = await sharp(out.
|
|
226
|
-
const tray2xMeta = await sharp(out.
|
|
225
|
+
const tray1xMeta = await sharp(out.mac.tray).metadata();
|
|
226
|
+
const tray2xMeta = await sharp(out.mac.tray2x).metadata();
|
|
227
227
|
ctx.expect(tray1xMeta.width).toBe(16);
|
|
228
228
|
ctx.expect(tray1xMeta.height).toBe(16);
|
|
229
229
|
ctx.expect(tray2xMeta.width).toBe(32);
|
|
230
230
|
ctx.expect(tray2xMeta.height).toBe(32);
|
|
231
231
|
|
|
232
|
-
const dmg1xMeta = await sharp(out.
|
|
233
|
-
const dmg2xMeta = await sharp(out.
|
|
232
|
+
const dmg1xMeta = await sharp(out.mac.dmg).metadata();
|
|
233
|
+
const dmg2xMeta = await sharp(out.mac.dmg2x).metadata();
|
|
234
234
|
ctx.expect(dmg1xMeta.width).toBe(540);
|
|
235
235
|
ctx.expect(dmg1xMeta.height).toBe(380);
|
|
236
236
|
ctx.expect(dmg2xMeta.width).toBe(1080);
|
|
@@ -245,20 +245,20 @@ module.exports = defineCases({
|
|
|
245
245
|
run: async (ctx) => {
|
|
246
246
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
247
247
|
try {
|
|
248
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
249
|
-
await realPng(path.join(emDefaultsRoot, 'icons', '
|
|
248
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
249
|
+
await realPng(path.join(emDefaultsRoot, 'icons', 'mac', 'tray.png'), 32, 32);
|
|
250
250
|
// Consumer ships ONE file as `tray.png` (at @2x native size).
|
|
251
|
-
const consumerTray = path.join(projectRoot, 'config', 'icons', '
|
|
251
|
+
const consumerTray = path.join(projectRoot, 'config', 'icons', 'mac', 'tray.png');
|
|
252
252
|
await realPng(consumerTray, 32, 32);
|
|
253
253
|
|
|
254
254
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
255
255
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
256
256
|
|
|
257
|
-
ctx.expect(out.
|
|
258
|
-
ctx.expect(out.
|
|
257
|
+
ctx.expect(out.mac.tray).toBeDefined();
|
|
258
|
+
ctx.expect(out.mac.tray2x).toBeDefined();
|
|
259
259
|
// Output is still trayTemplate.png regardless of input name.
|
|
260
|
-
ctx.expect(path.basename(out.
|
|
261
|
-
const tray1xMeta = await sharp(out.
|
|
260
|
+
ctx.expect(path.basename(out.mac.tray)).toBe('trayTemplate.png');
|
|
261
|
+
const tray1xMeta = await sharp(out.mac.tray).metadata();
|
|
262
262
|
ctx.expect(tray1xMeta.width).toBe(16);
|
|
263
263
|
} finally {
|
|
264
264
|
fs.rmSync(root, { recursive: true, force: true });
|
|
@@ -270,7 +270,7 @@ module.exports = defineCases({
|
|
|
270
270
|
run: async (ctx) => {
|
|
271
271
|
const { root, projectRoot, distRoot, emDefaultsRoot } = stage();
|
|
272
272
|
try {
|
|
273
|
-
fakePng(path.join(emDefaultsRoot, 'icons', '
|
|
273
|
+
fakePng(path.join(emDefaultsRoot, 'icons', 'mac', 'icon.png'));
|
|
274
274
|
fakePng(path.join(emDefaultsRoot, 'icons', 'windows', 'icon.png'));
|
|
275
275
|
|
|
276
276
|
// Consumer ships ONE tray file under global/.
|
|
@@ -279,13 +279,13 @@ module.exports = defineCases({
|
|
|
279
279
|
const { resolveAndCopy } = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'resolve-icons.js'));
|
|
280
280
|
const out = await resolveAndCopy({ config: {}, projectRoot, distRoot, emDefaultsRoot });
|
|
281
281
|
|
|
282
|
-
ctx.expect(out.
|
|
283
|
-
ctx.expect(out.
|
|
282
|
+
ctx.expect(out.mac.tray).toBeDefined();
|
|
283
|
+
ctx.expect(out.mac.tray2x).toBeDefined();
|
|
284
284
|
ctx.expect(out.windows.tray).toBeDefined();
|
|
285
285
|
ctx.expect(out.linux.tray).toBeDefined();
|
|
286
286
|
|
|
287
287
|
// macOS @1x derived at half size from the global @2x source.
|
|
288
|
-
const macTrayMeta = await sharp(out.
|
|
288
|
+
const macTrayMeta = await sharp(out.mac.tray).metadata();
|
|
289
289
|
ctx.expect(macTrayMeta.width).toBe(16);
|
|
290
290
|
} finally {
|
|
291
291
|
fs.rmSync(root, { recursive: true, force: true });
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// The self-hosted signer's job guard
|
|
2
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): the hook the
|
|
3
|
+
// runner runs before a job's first step, and the three files the runner install
|
|
4
|
+
// writes beside the runner so it has an allow list to read.
|
|
5
|
+
//
|
|
6
|
+
// The hook is run here the way the runner runs it (a node process with the
|
|
7
|
+
// job's environment and nothing else), because the EXIT CODE is the whole
|
|
8
|
+
// mechanism: nonzero and the job dies with the script's output, before the
|
|
9
|
+
// checkout, before npm, before signtool ever sees the token.
|
|
10
|
+
//
|
|
11
|
+
// Nothing in this file touches a real box: every write goes to a scratch home
|
|
12
|
+
// under the OS temp dir, and no verb of `commands/runner.js` is called at all.
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const { spawnSync } = require('child_process');
|
|
18
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
19
|
+
|
|
20
|
+
const guard = require('../../../utils/runner-job-guard.js');
|
|
21
|
+
const hook = require('../../../runner/job-started.js');
|
|
22
|
+
const { ensureRunnerDirEnv } = require('../../../utils/runner-env.js');
|
|
23
|
+
|
|
24
|
+
const scratchHome = () => fs.mkdtempSync(path.join(os.tmpdir(), 'omega-job-guard-'));
|
|
25
|
+
|
|
26
|
+
// One job, as the runner delivers it: the three names the hook reads, and no
|
|
27
|
+
// inherited GITHUB_* (a run of this suite inside a job carries its own).
|
|
28
|
+
function runHook(hookPath, job) {
|
|
29
|
+
return spawnSync(process.execPath, [hookPath], {
|
|
30
|
+
env: { PATH: process.env.PATH, SystemRoot: process.env.SystemRoot || '', ...job },
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = defineCases({
|
|
36
|
+
type: 'suite',
|
|
37
|
+
layer: 'build',
|
|
38
|
+
description: 'runner job guard (#875): the box refuses any job that is not a trusted dispatch',
|
|
39
|
+
tests: [
|
|
40
|
+
{
|
|
41
|
+
name: 'a dispatch from a listed repo by a listed actor is allowed, and every other job is refused with one line naming the check and the value',
|
|
42
|
+
run: (ctx) => {
|
|
43
|
+
const home = scratchHome();
|
|
44
|
+
const { hook: hookPath } = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
45
|
+
|
|
46
|
+
// The passing case, on the ONE trusted event (#923).
|
|
47
|
+
const ok = runHook(hookPath, { GITHUB_EVENT_NAME: 'workflow_dispatch', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'ianwieds' });
|
|
48
|
+
ctx.expect(ok.status).toBe(0);
|
|
49
|
+
ctx.expect(ok.stdout.trim()).toBe('Allowing this job: workflow_dispatch on Omega-JS-Stack/omega-omega by ianwieds.');
|
|
50
|
+
|
|
51
|
+
// Each failing check: nonzero, and ONE line carrying the env name that
|
|
52
|
+
// failed and the value seen.
|
|
53
|
+
const cases = [
|
|
54
|
+
[{ GITHUB_EVENT_NAME: 'pull_request', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'ianwieds' }, 'GITHUB_EVENT_NAME', 'pull_request'],
|
|
55
|
+
[{ GITHUB_EVENT_NAME: 'repository_dispatch', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'ianwieds' }, 'GITHUB_EVENT_NAME', 'repository_dispatch'],
|
|
56
|
+
[{ GITHUB_EVENT_NAME: 'push', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'ianwieds' }, 'GITHUB_EVENT_NAME', 'push'],
|
|
57
|
+
[{ GITHUB_EVENT_NAME: 'workflow_dispatch', GITHUB_REPOSITORY: 'someone-else/their-app', GITHUB_ACTOR: 'ianwieds' }, 'GITHUB_REPOSITORY', 'someone-else/their-app'],
|
|
58
|
+
[{ GITHUB_EVENT_NAME: 'workflow_dispatch', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'mallory' }, 'GITHUB_ACTOR', 'mallory'],
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
for (const [job, name, value] of cases) {
|
|
62
|
+
const refused = runHook(hookPath, job);
|
|
63
|
+
ctx.expect(refused.status).toBe(1);
|
|
64
|
+
ctx.expect(refused.stdout.trim().split('\n').length).toBe(1);
|
|
65
|
+
ctx.expect(refused.stdout).toContain(name);
|
|
66
|
+
ctx.expect(refused.stdout).toContain(value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'a job with no environment at all is refused, and so is one whose allow list is missing',
|
|
74
|
+
run: (ctx) => {
|
|
75
|
+
const home = scratchHome();
|
|
76
|
+
const { hook: hookPath, repos } = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
77
|
+
|
|
78
|
+
// The runner always sets these; a hook run without them is a hook run
|
|
79
|
+
// that cannot answer the question, which is a refusal.
|
|
80
|
+
ctx.expect(runHook(hookPath, {}).status).toBe(1);
|
|
81
|
+
|
|
82
|
+
// An allow list that is not there allows nothing: the guard never opens
|
|
83
|
+
// the box up by failing to read its own configuration.
|
|
84
|
+
fs.rmSync(repos, { force: true });
|
|
85
|
+
const refused = runHook(hookPath, { GITHUB_EVENT_NAME: 'workflow_dispatch', GITHUB_REPOSITORY: 'Omega-JS-Stack/omega-omega', GITHUB_ACTOR: 'ianwieds' });
|
|
86
|
+
ctx.expect(refused.status).toBe(1);
|
|
87
|
+
ctx.expect(refused.stdout).toContain('allowed-repos.txt');
|
|
88
|
+
|
|
89
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'the allow list reads `owner/*` and single repos alike, case-insensitively, and comments and blanks are not entries',
|
|
94
|
+
run: (ctx) => {
|
|
95
|
+
const lists = { repos: ['Omega-JS-Stack/*', 'other-org/one-app'], actors: ['ianwieds'], reposFile: 'allowed-repos.txt', actorsFile: 'allowed-actors.txt' };
|
|
96
|
+
const dispatch = (repository) => hook.checkJob({ GITHUB_EVENT_NAME: 'workflow_dispatch', GITHUB_REPOSITORY: repository, GITHUB_ACTOR: 'IanWieds' }, lists).allowed;
|
|
97
|
+
|
|
98
|
+
ctx.expect(dispatch('omega-js-stack/anything')).toBe(true);
|
|
99
|
+
ctx.expect(dispatch('other-org/one-app')).toBe(true);
|
|
100
|
+
ctx.expect(dispatch('other-org/another-app')).toBe(false);
|
|
101
|
+
// `owner/*` is one owner, never a prefix of another owner's name.
|
|
102
|
+
ctx.expect(dispatch('Omega-JS-Stack-evil/app')).toBe(false);
|
|
103
|
+
|
|
104
|
+
const home = scratchHome();
|
|
105
|
+
const file = path.join(home, 'allowed-repos.txt');
|
|
106
|
+
fs.writeFileSync(file, '# a comment\n\n Omega-JS-Stack/omega-omega # trailing\n');
|
|
107
|
+
ctx.expect(hook.readList(file)).toEqual(['Omega-JS-Stack/omega-omega']);
|
|
108
|
+
|
|
109
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'the setup writes the hook and both allow lists beside the runner, and rerunning writes the same bytes',
|
|
114
|
+
run: (ctx) => {
|
|
115
|
+
const home = scratchHome();
|
|
116
|
+
const first = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
117
|
+
|
|
118
|
+
ctx.expect(first.hook).toBe(path.join(home, 'job-started.js'));
|
|
119
|
+
ctx.expect(first.repos).toBe(path.join(home, 'allowed-repos.txt'));
|
|
120
|
+
ctx.expect(first.actors).toBe(path.join(home, 'allowed-actors.txt'));
|
|
121
|
+
ctx.expect(first.added.repos).toEqual(['Omega-JS-Stack/*']);
|
|
122
|
+
ctx.expect(first.added.actors).toEqual(['ianwieds']);
|
|
123
|
+
|
|
124
|
+
// The hook on the box is this package's file, so a framework update
|
|
125
|
+
// reaches the box on its next install or start.
|
|
126
|
+
ctx.expect(fs.readFileSync(first.hook, 'utf8')).toBe(fs.readFileSync(path.join(__dirname, '..', '..', '..', 'runner', 'job-started.js'), 'utf8'));
|
|
127
|
+
|
|
128
|
+
const bytes = () => [first.hook, first.repos, first.actors].map((file) => fs.readFileSync(file, 'utf8'));
|
|
129
|
+
const before = bytes();
|
|
130
|
+
const again = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
131
|
+
ctx.expect(again.added).toEqual({ repos: [], actors: [] });
|
|
132
|
+
ctx.expect(bytes()).toEqual(before);
|
|
133
|
+
|
|
134
|
+
// A second org registered later gets its line; the first one is not
|
|
135
|
+
// duplicated and the file the operator reads keeps its header.
|
|
136
|
+
const third = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack', 'ITW-Creative-Works'], actor: 'ianwieds' });
|
|
137
|
+
ctx.expect(third.added.repos).toEqual(['ITW-Creative-Works/*']);
|
|
138
|
+
ctx.expect(hook.readList(third.repos)).toEqual(['Omega-JS-Stack/*', 'ITW-Creative-Works/*']);
|
|
139
|
+
ctx.expect(fs.readFileSync(third.repos, 'utf8').startsWith('# The repositories this box will sign for')).toBe(true);
|
|
140
|
+
|
|
141
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'an allow list narrowed by hand is never widened back by a later setup',
|
|
146
|
+
run: (ctx) => {
|
|
147
|
+
const home = scratchHome();
|
|
148
|
+
const { repos } = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
149
|
+
|
|
150
|
+
// The operator narrows the org wildcard to the one repo that signs.
|
|
151
|
+
fs.writeFileSync(repos, '# mine\nOmega-JS-Stack/omega-omega\n');
|
|
152
|
+
const again = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
153
|
+
|
|
154
|
+
ctx.expect(again.added.repos).toEqual([]);
|
|
155
|
+
ctx.expect(hook.readList(repos)).toEqual(['Omega-JS-Stack/omega-omega']);
|
|
156
|
+
|
|
157
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "the hook path reaches the listener through the runner dir's own .env, beside HOME",
|
|
162
|
+
run: (ctx) => {
|
|
163
|
+
const home = scratchHome();
|
|
164
|
+
const runnerDir = path.join(home, 'actions-runner-omega-js-stack');
|
|
165
|
+
const { hook: hookPath } = guard.ensureRunnerJobGuard(home, { orgs: ['Omega-JS-Stack'], actor: 'ianwieds' });
|
|
166
|
+
|
|
167
|
+
// The file GitHub documents for runner env, which the listener reads at
|
|
168
|
+
// startup and applies to every job: the same one the private HOME
|
|
169
|
+
// travels in (#807), written once for both.
|
|
170
|
+
const file = ensureRunnerDirEnv(runnerDir, { HOME: path.join(home, 'home'), ACTIONS_RUNNER_HOOK_JOB_STARTED: hookPath });
|
|
171
|
+
const lines = fs.readFileSync(file, 'utf8').trim().split(/\r?\n/);
|
|
172
|
+
|
|
173
|
+
ctx.expect(lines).toContain(`ACTIONS_RUNNER_HOOK_JOB_STARTED=${hookPath}`);
|
|
174
|
+
ctx.expect(lines).toContain(`HOME=${path.join(home, 'home')}`);
|
|
175
|
+
// Bare, never quoted: the listener takes the rest of the line verbatim.
|
|
176
|
+
ctx.expect(fs.readFileSync(file, 'utf8')).not.toContain('"');
|
|
177
|
+
|
|
178
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
});
|