@omega.js/desktop 0.50.0 → 0.51.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 (267) hide show
  1. package/README.md +1 -1
  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 +42 -5
  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 +144 -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 +25 -2
  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 +121 -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 +226 -104
  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 +264 -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 +445 -75
  197. package/dist/vendor/devkit/git-auth.js +73 -0
  198. package/dist/vendor/devkit/git-remote.js +95 -0
  199. package/dist/vendor/devkit/github-repo.js +290 -0
  200. package/dist/vendor/devkit/local.js +47 -0
  201. package/dist/vendor/devkit/merge-line-files.js +23 -16
  202. package/dist/vendor/devkit/omega-bin.js +18 -3
  203. package/dist/vendor/devkit/pack-local.js +391 -0
  204. package/dist/vendor/devkit/preludes/index.js +120 -0
  205. package/dist/vendor/devkit/preludes/origin-heal.js +156 -0
  206. package/dist/vendor/devkit/service-account.js +43 -0
  207. package/dist/vendor/devkit/ship-plan.js +112 -0
  208. package/dist/vendor/devkit/signing-env.js +180 -0
  209. package/dist/vendor/devkit/signing-tree.js +92 -0
  210. package/dist/vendor/devkit/target-seams.js +142 -0
  211. package/dist/vendor/devkit/target-secrets.js +235 -50
  212. package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
  213. package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
  214. package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
  215. package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
  216. package/dist/vendor/monitoring/env.js +20 -10
  217. package/dist/vendor/monitoring/main.js +1 -1
  218. package/dist/vendor/monitoring/preload.js +1 -1
  219. package/dist/vendor/monitoring/renderer.js +1 -1
  220. package/docs/analytics.md +1 -1
  221. package/docs/auto-updater.md +5 -5
  222. package/docs/boot-sequence.md +1 -1
  223. package/docs/build-system.md +15 -7
  224. package/docs/client-bridge.md +9 -7
  225. package/docs/config-schema.md +4 -4
  226. package/docs/css.md +8 -2
  227. package/docs/deep-link.md +12 -4
  228. package/docs/environment-detection.md +32 -24
  229. package/docs/hooks.md +3 -1
  230. package/docs/icons.md +7 -7
  231. package/docs/index.md +61 -23
  232. package/docs/installer-options.md +24 -21
  233. package/docs/logging.md +5 -5
  234. package/docs/releasing.md +25 -17
  235. package/docs/runner.md +40 -5
  236. package/docs/shared/brands.md +12 -6
  237. package/docs/shared/breaking-changes.md +375 -21
  238. package/docs/shared/config.md +757 -199
  239. package/docs/shared/deploys.md +194 -91
  240. package/docs/shared/icons.md +18 -0
  241. package/docs/shared/local-dev.md +24 -6
  242. package/docs/shared/logging.md +9 -6
  243. package/docs/shared/monitoring.md +27 -13
  244. package/docs/shared/publishing.md +3 -3
  245. package/docs/shared/rulings.md +2 -2
  246. package/docs/shared/testing.md +1 -1
  247. package/docs/shared/theming.md +26 -1
  248. package/docs/shared/translation.md +49 -7
  249. package/docs/shared/updates.md +1 -1
  250. package/docs/signing.md +59 -33
  251. package/docs/test-framework.md +10 -5
  252. package/docs/themes.md +15 -1
  253. package/package.json +18 -12
  254. package/bin/omega-desktop +0 -2
  255. package/dist/commands/push-secrets.js +0 -141
  256. package/dist/test/suites/build/deliver-certs.test.js +0 -95
  257. package/dist/test/suites/build/derive-signing-env.test.js +0 -122
  258. package/dist/test/suites/build/push-secrets.test.js +0 -226
  259. package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
  260. package/dist/utils/deliver-certs.js +0 -69
  261. package/dist/utils/derive-signing-env.js +0 -56
  262. package/dist/utils/resolve-signing-cert.js +0 -175
  263. package/dist/vendor/config/desktop-artifacts.js +0 -110
  264. package/dist/vendor/config/instances.js +0 -208
  265. /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
  266. /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
  267. /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
package/dist/preload.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // Wires contextBridge so renderer code can call `window.desktop.ipc.invoke(...)` without nodeIntegration.
4
4
 
5
5
  const LoggerLite = require('./lib/logger-lite.js');
6
+ const { ENVIRONMENT_VAR } = require('./vendor/config/environment.js');
6
7
 
7
8
  function Manager() {
8
9
  const self = this;
@@ -27,6 +28,13 @@ Manager.prototype.initialize = async function () {
27
28
  // Expose a stable, namespaced surface to the renderer.
28
29
  // Real impl in pass 2 will type the channel list and proxy storage through here.
29
30
  contextBridge.exposeInMainWorld('desktop', {
31
+ // The RUNNING environment, for the one context that cannot read it: a page has
32
+ // no `process`, so its Manager answers `OMEGA_BUILD_JSON.config.environment`,
33
+ // the word the BUILD was for. A test lane boots a production artifact with
34
+ // `OMEGA_ENVIRONMENT=testing`, so the two differ there, and a preload is Node
35
+ // ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). The renderer
36
+ // bootstrap applies this over the baked word, so it answers what main answers.
37
+ environment: process.env[ENVIRONMENT_VAR] || null,
30
38
  ipc: {
31
39
  invoke: (channel, payload) => ipcRenderer.invoke(channel, payload),
32
40
  // Returns an unsubscribe fn (docs/ipc.md contract — same shape as the
package/dist/renderer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Renderer-process Manager singleton.
2
2
  // Consumer entry (per view): `new (require('@omega.js/desktop/renderer'))().initialize()`.
3
- // Reads window.OMEGA_BUILD_JSON.config (injected by the bundle task's esbuild `define`), bootstraps @omega.js/client + auth.
3
+ // Reads window.OMEGA_BUILD_JSON.config (the one dist/build.js the view's shell loads, #743), bootstraps @omega.js/client + auth.
4
4
  //
5
5
  // Auth bridge:
6
6
  // - On init, asks main "I'm at UID X (or null), are we in sync?" via desktop:auth:sync-request.
@@ -32,11 +32,23 @@ Manager.prototype.initialize = async function (overrides) {
32
32
  const self = this;
33
33
 
34
34
  // Merge runtime overrides on top of build-time config.
35
- // OMEGA_BUILD_JSON is injected by the bundle task's esbuild `define`; its `banner`
36
- // also makes it available on globalThis.OMEGA_BUILD_JSON for DevTools introspection.
37
- const buildJson = (typeof OMEGA_BUILD_JSON !== 'undefined' && OMEGA_BUILD_JSON) || {};
35
+ // OMEGA_BUILD_JSON comes off the window: the view's shell loads the ONE
36
+ // `dist/build.js` ahead of this bundle (#743), which is also what makes it
37
+ // readable from DevTools.
38
+ const buildJson = (typeof window !== 'undefined' && window.OMEGA_BUILD_JSON) || {};
38
39
  self.config = Object.assign({}, buildJson.config || {}, overrides || {});
39
40
 
41
+ // The RUNNING environment beats the baked one, exactly as it does in main
42
+ // ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). A page has no
43
+ // `process`, so `isTesting()` here reads `config.environment`, the word the
44
+ // BUILD was for; the preload does have it and hands it over on the bridge, so a
45
+ // test lane booting a production artifact gets the same answer in this renderer
46
+ // that main gives. No second signal: it is the one input, one context removed.
47
+ const runningEnvironment = (typeof window !== 'undefined' && window.desktop?.environment) || null;
48
+ if (runningEnvironment) {
49
+ self.config.environment = runningEnvironment;
50
+ }
51
+
40
52
  self.logger.log('Initializing @omega.js/desktop (renderer)...');
41
53
 
42
54
  // Boot @omega.js/client so Firebase Auth is available in this renderer.
@@ -0,0 +1,104 @@
1
+ // The self-hosted signer's job-started hook
2
+ // ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): the box refuses
3
+ // any job that is not a trusted dispatch, before the job's first step runs.
4
+ //
5
+ // The runner runs this file through `ACTIONS_RUNNER_HOOK_JOB_STARTED`, an
6
+ // absolute path in the runner's own `<runner dir>\.env`. A nonzero exit fails
7
+ // the job with this script's output and NOTHING of the job runs: no checkout,
8
+ // no install, and no signtool call against the EV token. GitHub documents the
9
+ // hook at https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/run-scripts
10
+ // (the docs name `.sh` and `.ps1`; the runner ALSO handles `.js`, running it
11
+ // with its OWN bundled node, per `GetDefaultShellForScript` in
12
+ // `src/Runner.Common/HostContext.cs` of actions/runner v2.319.1, the version
13
+ // `omega runner install` pins). So this is one plain Node file, no PowerShell,
14
+ // and the unit suite runs it on any platform.
15
+ //
16
+ // The three checks, every one of which must pass:
17
+ // GITHUB_EVENT_NAME the one trusted dispatch: `workflow_dispatch`
18
+ // GITHUB_REPOSITORY listed in allowed-repos.txt
19
+ // GITHUB_ACTOR listed in allowed-actors.txt
20
+ // All three are the job's standard environment, exported to the hook by the
21
+ // runner's `_contextEnvAllowlist` (`src/Runner.Worker/GitHubContext.cs`:
22
+ // `actor`, `event_name`, `repository`).
23
+ //
24
+ // Node BUILTINS only, on purpose: this file is installed beside the runner, in
25
+ // the runner home, where there is no `node_modules` to resolve `fs-jetpack`
26
+ // from, and the runner's own node runs it, not the box's.
27
+ const fs = require('fs');
28
+ const path = require('path');
29
+
30
+ // ONE trusted event (#923): every publish path (`omega deploy`, a CMS button, a
31
+ // plain HTTP call) dispatches `workflow_dispatch` at the deploy ref, and its
32
+ // actor is the deploy token's user, the same account the box owner signs in as.
33
+ const DISPATCH_EVENTS = ['workflow_dispatch'];
34
+
35
+ const REPOS_FILE = 'allowed-repos.txt';
36
+ const ACTORS_FILE = 'allowed-actors.txt';
37
+
38
+ // One entry per line, `#` comments and blank lines dropped. An unreadable file
39
+ // reads as NO entries, which refuses every job: a guard that cannot read its
40
+ // allow list allows nothing.
41
+ function readList(file) {
42
+ let raw;
43
+ try {
44
+ raw = fs.readFileSync(file, 'utf8');
45
+ } catch (e) {
46
+ return [];
47
+ }
48
+ return raw.split(/\r?\n/)
49
+ .map((line) => line.replace(/#.*$/, '').trim())
50
+ .filter(Boolean);
51
+ }
52
+
53
+ // `owner/name`, or `owner/*` for every repo of one owner, which is the scope a
54
+ // runner registration already has, and the line `omega runner install` writes.
55
+ // Narrowing it to individual repos is an edit of the file, by hand.
56
+ function repoMatches(repository, entry) {
57
+ const listed = entry.toLowerCase();
58
+ const seen = String(repository || '').toLowerCase();
59
+ if (listed.endsWith('/*')) return seen.startsWith(listed.slice(0, -1));
60
+ return seen === listed;
61
+ }
62
+
63
+ // The verdict, as data: `{ allowed, line }`, one line whatever the answer, so
64
+ // the caller below is only an exit code and a `console.log`.
65
+ function checkJob(env, lists) {
66
+ const { repos = [], actors = [], reposFile = REPOS_FILE, actorsFile = ACTORS_FILE } = lists || {};
67
+ const event = env.GITHUB_EVENT_NAME || '';
68
+ const repository = env.GITHUB_REPOSITORY || '';
69
+ const actor = env.GITHUB_ACTOR || '';
70
+
71
+ if (!DISPATCH_EVENTS.includes(event)) {
72
+ return { allowed: false, line: `Refusing this job: GITHUB_EVENT_NAME is "${event}", and this runner serves ${DISPATCH_EVENTS.join(' and ')} only.` };
73
+ }
74
+ if (repos.length === 0) {
75
+ return { allowed: false, line: `Refusing this job: ${reposFile} lists no repository, so this runner allows none. Run \`npx omega runner install\` on the box, or add one \`owner/name\` per line.` };
76
+ }
77
+ if (!repos.some((entry) => repoMatches(repository, entry))) {
78
+ return { allowed: false, line: `Refusing this job: GITHUB_REPOSITORY is "${repository}", which is not listed in ${reposFile}.` };
79
+ }
80
+ if (actors.length === 0) {
81
+ return { allowed: false, line: `Refusing this job: ${actorsFile} lists no actor, so this runner allows none. Run \`npx omega runner install\` on the box, or add one login per line.` };
82
+ }
83
+ if (!actors.some((entry) => entry.toLowerCase() === actor.toLowerCase())) {
84
+ return { allowed: false, line: `Refusing this job: GITHUB_ACTOR is "${actor}", which is not listed in ${actorsFile}.` };
85
+ }
86
+
87
+ return { allowed: true, line: `Allowing this job: ${event} on ${repository} by ${actor}.` };
88
+ }
89
+
90
+ // The allow lists sit BESIDE this file, in the runner home the install writes
91
+ // them to, so the hook needs no configuration of its own to find them.
92
+ function loadLists(dir) {
93
+ const reposFile = path.join(dir, REPOS_FILE);
94
+ const actorsFile = path.join(dir, ACTORS_FILE);
95
+ return { repos: readList(reposFile), actors: readList(actorsFile), reposFile, actorsFile };
96
+ }
97
+
98
+ if (require.main === module) {
99
+ const verdict = checkJob(process.env, loadLists(__dirname));
100
+ console.log(verdict.line);
101
+ process.exit(verdict.allowed ? 0 : 1);
102
+ }
103
+
104
+ module.exports = { checkJob, loadLists, readList, repoMatches, DISPATCH_EVENTS, REPOS_FILE, ACTORS_FILE };
@@ -6,6 +6,12 @@
6
6
  brand: {
7
7
  id: 'desktop-fixture',
8
8
  name: 'Desktop Fixture Consumer',
9
+ // The .deb target needs a homepage and a maintainer (#872): build-config
10
+ // refuses the config without them, so the fixture spells both.
11
+ url: 'https://desktop-fixture.test',
12
+ contact: {
13
+ email: 'support@desktop-fixture.test',
14
+ },
9
15
  images: {
10
16
  // Empty → build-config falls back to @omega.js/desktop's bundled default icon (no icon file shipped).
11
17
  icon: '',
@@ -27,6 +33,7 @@
27
33
  cloud: { provider: 'firebase', config: {} },
28
34
  targets: {
29
35
  desktop: {
36
+ type: 'desktop',
30
37
  startup: {
31
38
  mode: 'normal',
32
39
  },
@@ -7,7 +7,7 @@
7
7
  "devDependencies": {
8
8
  "@omega.js/desktop": "^0.1.0",
9
9
  "electron": ">=42",
10
- "electron-builder": ">=26",
10
+ "electron-builder": ">=26.16.1",
11
11
  "gulp": "^5.0.1"
12
12
  }
13
13
  }
@@ -1,7 +1,13 @@
1
1
  // Minimal main-window renderer entry for the boot-layer self-test fixture.
2
2
  const Manager = require('@omega.js/desktop/renderer');
3
3
 
4
- new Manager().initialize();
4
+ const manager = new Manager();
5
+ manager.initialize();
6
+
7
+ // #925 pins that this renderer answers the lane's environment and not the word
8
+ // baked into the bundle, so the boot inspect needs a handle on the Manager the
9
+ // answer is given on.
10
+ window.__omegaManager = manager;
5
11
 
6
12
  // #111 — pins that the vendored core module resolves through the renderer's
7
13
  // `__main_assets__` alias AND runs: with no .omega-shell in this window the
@@ -19,7 +19,8 @@ const { app, BrowserWindow, ipcMain } = require('electron');
19
19
  // steals keyboard focus app-wide even when no window is ever focused. This file
20
20
  // only initializes its Manager after whenReady (too late: activation fires when
21
21
  // the app finishes launching), so flip the accessory policy here at require time.
22
- // This process is always a test run (runners/electron.js sets OMEGA_TEST_MODE), so
22
+ // This process is always a test run (runners/electron.js spawns it naming
23
+ // OMEGA_ENVIRONMENT=testing, the one environment input), so
23
24
  // the shared predicate needs no Manager. OMEGA_TEST_SHOW=1 opts back into normal
24
25
  // activation along with visible windows.
25
26
  if (process.platform === 'darwin' && require('../../utils/test-stealth.js')()) {
@@ -67,10 +67,19 @@ try {
67
67
  ? require(process.env.OMEGA_TEST_RENDERER_MANAGER_PATH)
68
68
  : require('@omega.js/desktop/renderer');
69
69
  testManager = new RendererManager();
70
- // Seed config so getApiUrl / getFunctionsUrl / getWebsiteUrl have something to
71
- // read in their prod branches. Tests can mutate this via __emTestManager.config.set().
70
+ // Seed config the way a real BUILD bakes it, so the URL helpers have the same
71
+ // inputs here that they have in a shipped renderer. Tests can mutate this via
72
+ // __emTestManager.config.set().
73
+ // `environment` is the build fact every OMEGA surface bakes
74
+ // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), which is
75
+ // what a real renderer (no process.env) answers from.
76
+ // `dev.ports` is the resolved local map, whose floor is @omega.js/config's
77
+ // classic numbers ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)):
78
+ // nothing carries a browser-side copy of them any more, so an artifact
79
+ // without the map cannot reach a localhost port at all.
72
80
  testManager.config = {
73
- em: { environment: 'production' },
81
+ environment: 'production',
82
+ dev: { ports: { ...require('../../vendor/config/index.js').CLASSIC_PORTS } },
74
83
  brand: { url: 'https://example.com' },
75
84
  cloud: { provider: 'firebase', config: { projectId: 'demo-app', authDomain: 'demo-app.firebaseapp.com' } },
76
85
  };
@@ -28,6 +28,13 @@ const chalk = require('chalk').default;
28
28
  const distSnapshot = require('../utils/dist-snapshot.js');
29
29
  const { renderEvent } = require('./render-event.js');
30
30
 
31
+ // How long a booted app gets to say anything at all before the run is declared
32
+ // failed. Generous: the app under test is the consumer's real one, cold.
33
+ const DEFAULT_BOOT_TIMEOUT_MS = 60000;
34
+
35
+ // How long the child gets to go down politely before SIGKILL.
36
+ const KILL_GRACE_MS = 2000;
37
+
31
38
  async function runBootTests({ tests, suites, projectRoot, frameworkDistRoot }) {
32
39
  suites = suites || [];
33
40
 
@@ -148,7 +155,7 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
148
155
  // OMEGA_TEST_BOOT_SPEC — JSON file with the test definitions
149
156
  // Argv would be cleaner but Electron rejects unknown CLI flags.
150
157
  const childEnv = Object.assign({}, process.env, {
151
- OMEGA_TEST_MODE: 'true', // canonical signal — manager.isTesting() picks it up
158
+ OMEGA_ENVIRONMENT: 'testing', // the one environment input (#817): this lane names it
152
159
  OMEGA_TEST_BOOT: '1', // boot-runner-specific dispatch marker (main.js reads this to load the harness instead of doing normal init)
153
160
  OMEGA_TEST_BOOT_HARNESS: bootEntry,
154
161
  OMEGA_TEST_BOOT_SPEC: specFile,
@@ -171,8 +178,27 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
171
178
  // @omega.js/desktop's main.js detects OMEGA_TEST_BOOT and `require()`s the boot harness itself after init.
172
179
  const args = [testApp.appRoot];
173
180
 
181
+ return runBootChild({ electronBin, args, childEnv, effectiveRoot, specFile, skipEvents, testCount });
182
+ }
183
+
184
+ // Spawn the booted app, render what its harness emits, and end the run.
185
+ //
186
+ // A boot that never produces harness output is a FAILED run with a report, never a
187
+ // hung runner ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)): the child
188
+ // can block inside initialize(), long before main.js requires the harness, so the
189
+ // per-test timeout in harness/boot-entry.js never gets the chance to fire. The report
190
+ // quotes the last line of the booted app's runtime.log, which is the one clue about
191
+ // where it stopped.
192
+ //
193
+ // The budget is IDLE time, never total run time: every harness line rearms it, so a
194
+ // healthy suite that legitimately runs longer than the budget is left alone and only
195
+ // SILENCE for a whole budget fails the run.
196
+ //
197
+ // `spawnFn`, `timeoutMs` and `killGraceMs` are the seams the build-layer suite drives
198
+ // (suites/build/boot-runner-timeout.test.js), the way the deploy modules take an execFn.
199
+ function runBootChild({ electronBin, args, childEnv, effectiveRoot, specFile, skipEvents, testCount, spawnFn = spawn, timeoutMs = bootTimeoutMs(), killGraceMs = KILL_GRACE_MS }) {
174
200
  return new Promise((resolve) => {
175
- const child = spawn(electronBin, args, {
201
+ const child = spawnFn(electronBin, args, {
176
202
  cwd: effectiveRoot,
177
203
  env: childEnv,
178
204
  stdio: ['ignore', 'pipe', 'pipe'],
@@ -184,44 +210,108 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
184
210
  // Suites the module skipped whole: reported before the run they never join.
185
211
  skipEvents.forEach((evt) => renderEvent(evt, counts));
186
212
 
187
- child.stdout.on('data', (chunk) => {
213
+ let timer = null;
214
+
215
+ // Rearmed by every harness line below, so the budget measures SILENCE.
216
+ function armBudget() {
217
+ clearTimeout(timer);
218
+ timer = setTimeout(() => {
219
+ console.log(chalk.red(` ✗ boot: no harness output after ${Math.round(timeoutMs / 1000)}s; last runtime.log line: "${lastRuntimeLogLine(effectiveRoot)}"`));
220
+ counts.failed += testCount;
221
+ // Detached BEFORE the counts are handed out: a line the child emits
222
+ // while it is being killed must not move numbers already reported.
223
+ cleanup();
224
+ endChild(child, killGraceMs);
225
+ resolve(counts);
226
+ }, timeoutMs);
227
+ }
228
+
229
+ function onStdout(chunk) {
188
230
  buffer += chunk.toString();
189
231
  let nl;
190
232
  while ((nl = buffer.indexOf('\n')) >= 0) {
191
233
  const line = buffer.slice(0, nl);
192
234
  buffer = buffer.slice(nl + 1);
193
235
  if (line.startsWith('__EM_TEST__')) {
236
+ armBudget();
194
237
  renderEvent(JSON.parse(line.slice('__EM_TEST__'.length)), counts);
195
238
  } else if (process.env.OMEGA_TEST_DEBUG && line.trim().length > 0) {
196
239
  process.stdout.write(chalk.gray(` ${line}\n`));
197
240
  }
198
241
  }
199
- });
242
+ }
200
243
 
201
- child.stderr.on('data', (chunk) => {
244
+ function onStderr(chunk) {
202
245
  if (process.env.OMEGA_TEST_DEBUG) {
203
246
  process.stderr.write(chalk.gray(`[boot:stderr] ${chunk.toString()}`));
204
247
  }
205
- });
248
+ }
206
249
 
207
- child.on('error', (err) => {
250
+ function onError(err) {
208
251
  console.log(chalk.red(` ✗ Failed to spawn boot harness: ${err.message}`));
209
252
  counts.failed += 1;
210
253
  cleanup();
211
254
  resolve(counts);
212
- });
255
+ }
213
256
 
214
- child.on('exit', () => {
257
+ function onExit() {
215
258
  cleanup();
216
259
  resolve(counts);
217
- });
260
+ }
261
+
262
+ child.stdout.on('data', onStdout);
263
+ child.stderr.on('data', onStderr);
264
+ child.on('error', onError);
265
+ child.on('exit', onExit);
266
+
267
+ armBudget();
218
268
 
219
269
  function cleanup() {
270
+ clearTimeout(timer);
271
+ child.stdout.removeListener('data', onStdout);
272
+ child.stderr.removeListener('data', onStderr);
273
+ child.removeListener('error', onError);
274
+ child.removeListener('exit', onExit);
220
275
  try { fs.unlinkSync(specFile); } catch (_) { /* ignore */ }
221
276
  }
222
277
  });
223
278
  }
224
279
 
280
+ // The boot budget, overridable with OMEGA_TEST_BOOT_TIMEOUT_MS the way
281
+ // OMEGA_TEST_SKIP_BUILD opts out of the rebuild above.
282
+ function bootTimeoutMs() {
283
+ const override = Number(process.env.OMEGA_TEST_BOOT_TIMEOUT_MS);
284
+ return Number.isFinite(override) && override > 0 ? override : DEFAULT_BOOT_TIMEOUT_MS;
285
+ }
286
+
287
+ // The last non-empty line of the booted app's runtime log: where a blocked boot got to.
288
+ // A boot that died before the logger opened a file has none, which is itself the report.
289
+ function lastRuntimeLogLine(effectiveRoot) {
290
+ let contents;
291
+ try {
292
+ contents = fs.readFileSync(path.join(effectiveRoot, 'logs', 'runtime.log'), 'utf8');
293
+ } catch (_) {
294
+ return '(no runtime.log)';
295
+ }
296
+
297
+ const lines = contents.split('\n');
298
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
299
+ if (lines[i].trim().length > 0) return lines[i].trim();
300
+ }
301
+ return '(runtime.log is empty)';
302
+ }
303
+
304
+ // End a child that outlived its budget. Polite first, then SIGKILL: the direct child
305
+ // is the orphan the hang used to leave behind. The grace timer is unref'd so it never
306
+ // holds the runner open on its own.
307
+ function endChild(child, killGraceMs) {
308
+ try { child.kill(); } catch (_) { /* already gone */ }
309
+ const grace = setTimeout(() => {
310
+ try { child.kill('SIGKILL'); } catch (_) { /* already gone */ }
311
+ }, killGraceMs);
312
+ if (typeof grace.unref === 'function') grace.unref();
313
+ }
314
+
225
315
  // Serialize the boot-bound renderer suites (`view: '<name>'`) for the spec file, the same
226
316
  // shape main-entry.js ships to the harness page (plus the view name). A suite the module
227
317
  // skipped whole runs nothing and reports its test count as skipped, exactly as the harness
@@ -411,4 +501,4 @@ function removeFixtureDeps(links) {
411
501
  }
412
502
  }
413
503
 
414
- module.exports = { runBootTests };
504
+ module.exports = { runBootTests, runBootChild };
@@ -36,7 +36,7 @@ function runElectronTests({ harnessEntry, suiteFiles, rendererSuiteFiles, filter
36
36
  }
37
37
 
38
38
  const childEnv = Object.assign({}, process.env, {
39
- OMEGA_TEST_MODE: 'true', // canonical signal — manager.isTesting() picks it up
39
+ OMEGA_ENVIRONMENT: 'testing', // the one environment input (#817): this lane names it
40
40
  ELECTRON_NO_ATTACH_CONSOLE: '1',
41
41
  NODE_OPTIONS: '',
42
42
  });
@@ -95,5 +95,59 @@ module.exports = defineCases({
95
95
  expect(bundle.includes('data-shell-dismiss')).toBe(true);
96
96
  },
97
97
  },
98
+
99
+ {
100
+ // #925: the lane spawns this child with OMEGA_ENVIRONMENT=testing and the
101
+ // artifact it boots was BUILT production, so the booted app used to answer
102
+ // `production` and every isTesting() gate in it was silently off. The proof
103
+ // is a gate that writes to the log: auth persistence resolves to `none` in a
104
+ // test run alone, and that is the line the booted app records. (The emulator
105
+ // line the bridge logs next is out of reach here, because the fixture's
106
+ // `cloud.config` is empty and this boot never initializes Firebase auth.)
107
+ description: 'the booted app runs in the lane environment, not the one baked into its bundle (#925)',
108
+ inspect: async ({ manager, expect, projectRoot }) => {
109
+ const fs = require('fs');
110
+ const path = require('path');
111
+
112
+ expect(manager.isTesting()).toBe(true);
113
+ expect(manager.config.environment).toBe('production'); // the artifact IS a production build
114
+
115
+ const log = fs.readFileSync(path.join(projectRoot, 'logs', 'runtime.log'), 'utf8');
116
+ expect(log.includes('auth persistence: none (test mode)')).toBe(true);
117
+ },
118
+ },
119
+
120
+ {
121
+ // #925: a page has no `process`, so its Manager reads the baked word. The
122
+ // preload hands the running one over on `window.desktop`, and the renderer
123
+ // bootstrap applies it, so this window answers what main answers.
124
+ description: 'the main window renderer answers the lane environment too (#925)',
125
+ inspect: async ({ manager, expect }) => {
126
+ const { BrowserWindow } = require('electron');
127
+
128
+ // The window is created in the consumer's initialize().then(), and its
129
+ // bootstrap sets the config a moment later; poll for both, the way the
130
+ // view test above polls for the window.
131
+ let answer = null;
132
+ let win = null;
133
+ for (let i = 0; i < 40; i++) {
134
+ win = manager.windows.get('main') || BrowserWindow.getAllWindows()[0];
135
+ if (win && !win.isDestroyed() && !win.webContents.isLoading()) {
136
+ answer = await win.webContents.executeJavaScript(
137
+ 'window.__omegaManager && window.__omegaManager.config ? window.__omegaManager.getEnvironment() : null',
138
+ );
139
+ if (answer) break;
140
+ }
141
+ await new Promise((resolve) => setTimeout(resolve, 100));
142
+ }
143
+
144
+ const baked = await win.webContents.executeJavaScript('window.OMEGA_BUILD_JSON.config.environment');
145
+ const bridged = await win.webContents.executeJavaScript('window.desktop.environment');
146
+
147
+ expect(baked).toBe('production'); // what the build baked
148
+ expect(bridged).toBe('testing'); // what the preload read off the lane
149
+ expect(answer).toBe('testing'); // what the renderer's Manager answers
150
+ },
151
+ },
98
152
  ],
99
153
  });
@@ -31,7 +31,7 @@ function stageConsumer(overrides = {}, desktopOverrides = {}) {
31
31
  brand: { id: 'testapp', name: 'TestApp', images: { icon: '' } },
32
32
  app: { appId: 'com.test.app', productName: 'TestApp' },
33
33
  };
34
- const merged = { ...baseConfig, ...overrides, targets: { desktop: desktopOverrides } };
34
+ const merged = { ...baseConfig, ...overrides, targets: { desktop: { type: 'desktop', ...desktopOverrides } } };
35
35
  jetpack.write(path.join(tmp, 'config', 'omega.json5'), JSON.stringify(merged));
36
36
 
37
37
  return tmp;
@@ -42,7 +42,12 @@ function runAudit(cwd, env = {}) {
42
42
  const origCwd = process.cwd();
43
43
  // Force build/publish env off — minimal scaffolds don't include icons/cert files.
44
44
  // Tests that want to exercise publish-mode checks pass env explicitly.
45
- const baseEnv = { OMEGA_BUILD_MODE: '', OMEGA_IS_PUBLISH: '', OMEGA_IS_SERVER: '' };
45
+ // OMEGA_ENVIRONMENT is NAMED here, not blanked: it is the ONE environment
46
+ // input ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), every
47
+ // lane sets it, and an audit run is a dev-lane read. Naming it also keeps
48
+ // the value from leaking between cases, because src/build.js writes it at
49
+ // load from whichever lane flags were set when it was required.
50
+ const baseEnv = { OMEGA_ENVIRONMENT: 'development', OMEGA_BUILD_MODE: '', OMEGA_IS_PUBLISH: '', OMEGA_IS_SERVER: '' };
46
51
  const allEnv = { ...baseEnv, ...env };
47
52
  const origEnv = {};
48
53
  for (const k of Object.keys(allEnv)) {
@@ -64,6 +69,22 @@ function runAudit(cwd, env = {}) {
64
69
  });
65
70
  }
66
71
 
72
+ // The audit REPORTS through the logger, so a case that reads the report reads
73
+ // the console the logger writes to (warnings on `warn`, the ok line on `log`).
74
+ async function runAuditCapturing(cwd, env = {}) {
75
+ const lines = [];
76
+ const original = { log: console.log, warn: console.warn };
77
+ console.log = (...args) => lines.push(args.join(' '));
78
+ console.warn = (...args) => lines.push(args.join(' '));
79
+
80
+ try {
81
+ const err = await runAudit(cwd, env);
82
+ return { err, output: lines.join('\n') };
83
+ } finally {
84
+ Object.assign(console, original);
85
+ }
86
+ }
87
+
67
88
  module.exports = defineCases({
68
89
  type: 'suite',
69
90
  layer: 'build',
@@ -81,6 +102,24 @@ module.exports = defineCases({
81
102
  }
82
103
  },
83
104
  },
105
+ {
106
+ // #911: the task took only `errors` off validateConfig, so a consumer
107
+ // read `audit ok (0 warnings)` while the validator's list named real
108
+ // findings (a key the schema does not declare, which is what a typo
109
+ // looks like). The report is both lists now.
110
+ name: 'prints the validator\'s warnings and counts them (#911)',
111
+ run: async (ctx) => {
112
+ const tmp = stageConsumer({ brand: { id: 'testapp', name: 'TestApp' } }, { notAKey: true });
113
+ try {
114
+ const { err, output } = await runAuditCapturing(tmp);
115
+ ctx.expect(err).toBeNull();
116
+ ctx.expect(output).toMatch(/notAKey/);
117
+ ctx.expect(output).toMatch(/audit ok \(1 warning\)/);
118
+ } finally {
119
+ fs.rmSync(tmp, { recursive: true, force: true });
120
+ }
121
+ },
122
+ },
84
123
  {
85
124
  name: 'fails when brand.id is missing',
86
125
  run: async (ctx) => {
@@ -121,10 +160,10 @@ module.exports = defineCases({
121
160
  },
122
161
  },
123
162
  {
124
- name: 'publish mode: no releases.repo still passes, since the default names `<brand.id>-releases` (#799)',
163
+ name: 'publish mode: a bare `releases: {}` passes, since the repo derives as `<brand.id>-releases` (#799, #883)',
125
164
  run: async (ctx) => {
126
165
  const tmp = stageConsumer(
127
- { brand: { id: 'acme', name: 'Acme', images: { icon: 'icon.png' } }, repo: { providers: { github: { org: 'Acme-Org' } } } },
166
+ { brand: { id: 'acme', name: 'Acme', images: { icon: 'icon.png' } }, repo: { provider: 'github', org: 'Acme-Org' } },
128
167
  { releases: {} },
129
168
  );
130
169
  jetpack.write(path.join(tmp, 'icon.png'), 'stub');
@@ -219,12 +258,12 @@ module.exports = defineCases({
219
258
  run: async (ctx) => {
220
259
  const tmp = stageConsumer(
221
260
  { brand: { id: 'testapp', name: 'TestApp' }, app: { appId: 'com.test.app', productName: 'TestApp' } },
222
- { platforms: { win: { signing: { strategy: 'banana' } } } },
261
+ { platforms: { windows: { signing: { strategy: 'banana' } } } },
223
262
  );
224
263
  try {
225
264
  const err = await runAudit(tmp);
226
265
  ctx.expect(err).toBeDefined();
227
- ctx.expect(err.message).toMatch(/platforms\.win\.signing\.strategy "banana" is not allowed/);
266
+ ctx.expect(err.message).toMatch(/platforms\.windows\.signing\.strategy "banana" is not allowed/);
228
267
  } finally {
229
268
  fs.rmSync(tmp, { recursive: true, force: true });
230
269
  }