@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.
Files changed (268) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/css/tokens/_index.scss +1 -1
  3. package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
  4. package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
  5. package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
  6. package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
  7. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
  8. package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
  9. package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
  10. package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
  11. package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
  12. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
  13. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
  14. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
  15. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
  16. package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
  17. package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
  18. package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
  19. package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
  20. package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
  21. package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
  22. package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
  23. package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
  24. package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
  25. package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
  26. package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
  27. package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
  28. package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
  29. package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
  30. package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
  31. package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
  32. package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
  33. package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
  34. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
  35. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
  36. package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
  37. package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
  38. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
  39. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
  40. package/dist/build.js +69 -28
  41. package/dist/cli-run.js +20 -13
  42. package/dist/cli.js +12 -7
  43. package/dist/commands/build.js +0 -2
  44. package/dist/commands/deploy.js +116 -44
  45. package/dist/commands/finalize-release.js +5 -4
  46. package/dist/commands/launch.js +12 -7
  47. package/dist/commands/lib/deploy-precheck.js +66 -34
  48. package/dist/commands/lib/ensure-target.js +71 -11
  49. package/dist/commands/package.js +0 -1
  50. package/dist/commands/publish.js +11 -4
  51. package/dist/commands/release.js +99 -252
  52. package/dist/commands/runner.js +176 -42
  53. package/dist/commands/sign-windows.js +46 -15
  54. package/dist/commands/test.js +4 -3
  55. package/dist/commands/validate-certs.js +291 -115
  56. package/dist/config/page-template.html +4 -0
  57. package/dist/defaults/.github/workflows/build.yml +146 -64
  58. package/dist/defaults/AGENTS.md +3 -2
  59. package/dist/defaults/_.gitignore +4 -2
  60. package/dist/defaults/config/certs/README.md +25 -45
  61. package/dist/defaults/config/omega.json5 +66 -32
  62. package/dist/defaults/hooks/deploy/pre.js +10 -0
  63. package/dist/defaults/src/assets/scss/main.scss +12 -2
  64. package/dist/defaults/src/integrations/tray/index.js +1 -1
  65. package/dist/gulp/main.js +13 -25
  66. package/dist/gulp/tasks/audit.js +18 -6
  67. package/dist/gulp/tasks/build-config.js +181 -60
  68. package/dist/gulp/tasks/bundle.js +108 -36
  69. package/dist/gulp/tasks/release.js +86 -4
  70. package/dist/gulp/tasks/sass.js +11 -0
  71. package/dist/hooks/lib/notarize-tools.js +137 -0
  72. package/dist/hooks/notarize-artifacts.js +57 -0
  73. package/dist/hooks/notarize.js +59 -8
  74. package/dist/lib/auth-persistence.js +25 -0
  75. package/dist/lib/client-bridge.js +11 -8
  76. package/dist/lib/deep-link.js +15 -8
  77. package/dist/lib/protocol.js +7 -1
  78. package/dist/lib/restart-manager/install.js +6 -3
  79. package/dist/lib/sign-helpers/auto-unlock.js +65 -27
  80. package/dist/lib/sign-helpers/console-lock.js +34 -0
  81. package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
  82. package/dist/lib/sign-helpers/resolve-icons.js +6 -4
  83. package/dist/lib/tray.js +7 -6
  84. package/dist/main.js +16 -0
  85. package/dist/preload.js +8 -0
  86. package/dist/renderer.js +16 -4
  87. package/dist/runner/job-started.js +104 -0
  88. package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
  89. package/dist/test/fixtures/consumer-app/package.json +1 -1
  90. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
  91. package/dist/test/harness/main-entry.js +2 -1
  92. package/dist/test/harness/renderer-preload.js +12 -3
  93. package/dist/test/runners/boot.js +101 -11
  94. package/dist/test/runners/electron.js +1 -1
  95. package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
  96. package/dist/test/suites/build/audit.test.js +45 -6
  97. package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
  98. package/dist/test/suites/build/auto-unlock.test.js +105 -0
  99. package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
  100. package/dist/test/suites/build/brand-scss.test.js +106 -0
  101. package/dist/test/suites/build/build-config.test.js +146 -36
  102. package/dist/test/suites/build/build-json-bake.test.js +245 -0
  103. package/dist/test/suites/build/build-verbs.test.js +48 -15
  104. package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
  105. package/dist/test/suites/build/cli.test.js +32 -10
  106. package/dist/test/suites/build/config-schema.test.js +4 -4
  107. package/dist/test/suites/build/console-lock.test.js +51 -0
  108. package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
  109. package/dist/test/suites/build/deploy-direct.test.js +241 -0
  110. package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
  111. package/dist/test/suites/build/deploy-hook.test.js +169 -0
  112. package/dist/test/suites/build/ensure-target.test.js +14 -2
  113. package/dist/test/suites/build/env-delivery.test.js +19 -10
  114. package/dist/test/suites/build/env-watch.test.js +18 -7
  115. package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
  116. package/dist/test/suites/build/exec-with-limit.test.js +53 -0
  117. package/dist/test/suites/build/finalize-release.test.js +2 -2
  118. package/dist/test/suites/build/get-config.test.js +120 -8
  119. package/dist/test/suites/build/github-utils.test.js +12 -6
  120. package/dist/test/suites/build/license-stamp.test.js +6 -4
  121. package/dist/test/suites/build/manager.test.js +88 -68
  122. package/dist/test/suites/build/manifest-deps.test.js +116 -0
  123. package/dist/test/suites/build/merge-line-files.test.js +27 -4
  124. package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
  125. package/dist/test/suites/build/notarize-tools.test.js +38 -0
  126. package/dist/test/suites/build/notarize.test.js +207 -0
  127. package/dist/test/suites/build/release-pipeline.test.js +38 -60
  128. package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
  129. package/dist/test/suites/build/resolve-icons.test.js +35 -35
  130. package/dist/test/suites/build/runner-job-guard.test.js +182 -0
  131. package/dist/test/suites/build/runner.test.js +635 -5
  132. package/dist/test/suites/build/sentry.test.js +8 -3
  133. package/dist/test/suites/build/setup-scripts.test.js +3 -0
  134. package/dist/test/suites/build/sign-windows.test.js +92 -8
  135. package/dist/test/suites/build/test-stealth.test.js +17 -11
  136. package/dist/test/suites/build/url-helpers.test.js +37 -17
  137. package/dist/test/suites/build/validate-certs.test.js +428 -55
  138. package/dist/test/suites/build/validate-config.test.js +3 -3
  139. package/dist/test/suites/main/auth-flow.test.js +12 -0
  140. package/dist/test/suites/main/auth-persistence.test.js +14 -17
  141. package/dist/test/suites/main/auto-updater.test.js +2 -2
  142. package/dist/test/suites/main/boot-sequence.test.js +1 -1
  143. package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
  144. package/dist/test/suites/main/client-bridge.test.js +19 -6
  145. package/dist/test/suites/main/deep-link.test.js +54 -0
  146. package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
  147. package/dist/test/suites/main/url-helpers.test.js +81 -72
  148. package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
  149. package/dist/utils/build-pipeline.js +10 -10
  150. package/dist/utils/github.js +12 -51
  151. package/dist/utils/load-env.js +66 -0
  152. package/dist/utils/mode-helpers.js +43 -111
  153. package/dist/utils/platform.js +37 -0
  154. package/dist/utils/runner-env.js +2 -1
  155. package/dist/utils/runner-job-guard.js +149 -0
  156. package/dist/utils/ship-keys.js +52 -0
  157. package/dist/utils/test-stealth.js +5 -3
  158. package/dist/utils/url-helpers.js +33 -17
  159. package/dist/vendor/config/bundle-id.js +53 -0
  160. package/dist/vendor/config/client-config.js +141 -0
  161. package/dist/vendor/config/company.js +334 -15
  162. package/dist/vendor/config/dev-facts.js +48 -0
  163. package/dist/vendor/config/env-delivery.js +231 -9
  164. package/dist/vendor/config/env-retired.js +137 -0
  165. package/dist/vendor/config/env-rules.js +22 -3
  166. package/dist/vendor/config/env-schema.js +234 -117
  167. package/dist/vendor/config/env.js +55 -26
  168. package/dist/vendor/config/environment.js +189 -0
  169. package/dist/vendor/config/hooks.js +13 -11
  170. package/dist/vendor/config/index.js +125 -44
  171. package/dist/vendor/config/load.js +366 -115
  172. package/dist/vendor/config/merge.js +2 -2
  173. package/dist/vendor/config/order.js +3 -3
  174. package/dist/vendor/config/platforms.js +276 -0
  175. package/dist/vendor/config/repo.js +249 -103
  176. package/dist/vendor/config/retired-keys.js +232 -27
  177. package/dist/vendor/config/schema.js +525 -99
  178. package/dist/vendor/config/site-global.js +63 -53
  179. package/dist/vendor/config/targets.js +187 -0
  180. package/dist/vendor/config/validate.js +119 -59
  181. package/dist/vendor/devkit/argv.js +118 -0
  182. package/dist/vendor/devkit/attach-log-file.js +21 -13
  183. package/dist/vendor/devkit/brand-tokens.js +278 -0
  184. package/dist/vendor/devkit/brand-version.js +425 -0
  185. package/dist/vendor/devkit/build-json.js +91 -0
  186. package/dist/vendor/devkit/bundle.js +48 -0
  187. package/dist/vendor/devkit/certificate-expiry.js +108 -0
  188. package/dist/vendor/devkit/certs.js +16 -194
  189. package/dist/vendor/devkit/ci-workflows.js +124 -8
  190. package/dist/vendor/devkit/cli-router.js +3 -3
  191. package/dist/vendor/devkit/defaults-engine.js +69 -7
  192. package/dist/vendor/devkit/deploy-follow.js +297 -0
  193. package/dist/vendor/devkit/deploy-precheck.js +23 -8
  194. package/dist/vendor/devkit/deploy-record.js +11 -27
  195. package/dist/vendor/devkit/deploy-snapshot.js +661 -0
  196. package/dist/vendor/devkit/deploy.js +505 -75
  197. package/dist/vendor/devkit/git-auth.js +73 -0
  198. package/dist/vendor/devkit/git-remote.js +172 -0
  199. package/dist/vendor/devkit/github-repo.js +290 -0
  200. package/dist/vendor/devkit/local.js +98 -3
  201. package/dist/vendor/devkit/lockfile.js +127 -0
  202. package/dist/vendor/devkit/merge-line-files.js +23 -16
  203. package/dist/vendor/devkit/omega-bin.js +18 -3
  204. package/dist/vendor/devkit/pack-local.js +388 -0
  205. package/dist/vendor/devkit/preludes/index.js +120 -0
  206. package/dist/vendor/devkit/preludes/origin-heal.js +142 -0
  207. package/dist/vendor/devkit/service-account.js +43 -0
  208. package/dist/vendor/devkit/ship-plan.js +112 -0
  209. package/dist/vendor/devkit/signing-env.js +180 -0
  210. package/dist/vendor/devkit/signing-tree.js +92 -0
  211. package/dist/vendor/devkit/target-seams.js +142 -0
  212. package/dist/vendor/devkit/target-secrets.js +231 -57
  213. package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
  214. package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
  215. package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
  216. package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
  217. package/dist/vendor/monitoring/env.js +20 -10
  218. package/dist/vendor/monitoring/main.js +1 -1
  219. package/dist/vendor/monitoring/preload.js +1 -1
  220. package/dist/vendor/monitoring/renderer.js +1 -1
  221. package/docs/analytics.md +1 -1
  222. package/docs/auto-updater.md +5 -5
  223. package/docs/boot-sequence.md +1 -1
  224. package/docs/build-system.md +15 -7
  225. package/docs/client-bridge.md +9 -7
  226. package/docs/config-schema.md +4 -4
  227. package/docs/css.md +8 -2
  228. package/docs/deep-link.md +12 -4
  229. package/docs/environment-detection.md +32 -24
  230. package/docs/hooks.md +3 -1
  231. package/docs/icons.md +7 -7
  232. package/docs/index.md +61 -23
  233. package/docs/installer-options.md +24 -21
  234. package/docs/logging.md +5 -5
  235. package/docs/releasing.md +29 -19
  236. package/docs/runner.md +51 -14
  237. package/docs/shared/brands.md +12 -6
  238. package/docs/shared/breaking-changes.md +375 -21
  239. package/docs/shared/config.md +764 -199
  240. package/docs/shared/deploys.md +217 -91
  241. package/docs/shared/icons.md +18 -0
  242. package/docs/shared/local-dev.md +28 -8
  243. package/docs/shared/logging.md +9 -6
  244. package/docs/shared/monitoring.md +27 -13
  245. package/docs/shared/publishing.md +3 -3
  246. package/docs/shared/rulings.md +2 -2
  247. package/docs/shared/testing.md +1 -1
  248. package/docs/shared/theming.md +26 -1
  249. package/docs/shared/translation.md +49 -7
  250. package/docs/shared/updates.md +1 -1
  251. package/docs/signing.md +60 -34
  252. package/docs/test-framework.md +10 -5
  253. package/docs/themes.md +15 -1
  254. package/package.json +18 -12
  255. package/bin/omega-desktop +0 -2
  256. package/dist/commands/push-secrets.js +0 -141
  257. package/dist/test/suites/build/deliver-certs.test.js +0 -95
  258. package/dist/test/suites/build/derive-signing-env.test.js +0 -122
  259. package/dist/test/suites/build/push-secrets.test.js +0 -226
  260. package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
  261. package/dist/utils/deliver-certs.js +0 -69
  262. package/dist/utils/derive-signing-env.js +0 -56
  263. package/dist/utils/resolve-signing-cert.js +0 -175
  264. package/dist/vendor/config/desktop-artifacts.js +0 -110
  265. package/dist/vendor/config/instances.js +0 -208
  266. /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
  267. /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
  268. /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', 'macos', 'icon.png'));
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.macos.app).toBe(path.join(distRoot, 'config', 'icons', 'macos', 'icon.png'));
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.macos.app)).toBeTruthy();
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', 'macos', 'icon.png'));
67
- const consumerIcon = path.join(projectRoot, 'config', 'icons', 'macos', 'icon.png');
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.macos.app);
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', 'macos', 'icon.png'));
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 ['macos', 'windows', 'linux']) {
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', 'macos', 'icon.png');
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.macos.app).toString()).toBe('mac-specific-bytes');
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', 'macos', 'icon.png'));
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', 'macos', 'tray.png'), 32, 32);
207
- await realPng(path.join(emDefaultsRoot, 'icons', 'macos', 'dmg.png'), 1080, 760);
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.macos.tray).toBeDefined();
214
- ctx.expect(out.macos.tray2x).toBeDefined();
215
- ctx.expect(out.macos.dmg).toBeDefined();
216
- ctx.expect(out.macos.dmg2x).toBeDefined();
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.macos.app2x).toBeUndefined();
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.macos.tray)).toBe('trayTemplate.png');
222
- ctx.expect(path.basename(out.macos.tray2x)).toBe('trayTemplate@2x.png');
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.macos.tray).metadata();
226
- const tray2xMeta = await sharp(out.macos.tray2x).metadata();
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.macos.dmg).metadata();
233
- const dmg2xMeta = await sharp(out.macos.dmg2x).metadata();
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', 'macos', 'icon.png'));
249
- await realPng(path.join(emDefaultsRoot, 'icons', 'macos', 'tray.png'), 32, 32);
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', 'macos', 'tray.png');
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.macos.tray).toBeDefined();
258
- ctx.expect(out.macos.tray2x).toBeDefined();
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.macos.tray)).toBe('trayTemplate.png');
261
- const tray1xMeta = await sharp(out.macos.tray).metadata();
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', 'macos', 'icon.png'));
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.macos.tray).toBeDefined();
283
- ctx.expect(out.macos.tray2x).toBeDefined();
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.macos.tray).metadata();
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
+ });