@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
@@ -63,15 +63,20 @@ module.exports = defineCases({
63
63
  // in the sibling `package` key.
64
64
  name: 'the bundle bake folds the app version into the config the renderer hands the client',
65
65
  run: (ctx) => {
66
- const { composeBuildConfig } = require(path.join(FRAMEWORK_ROOT, 'src', 'gulp', 'tasks', 'bundle.js'));
66
+ const { composeBuildConfig, buildFacts } = require(path.join(FRAMEWORK_ROOT, 'src', 'gulp', 'tasks', 'bundle.js'));
67
67
 
68
- const packaged = composeBuildConfig({ brand: { id: 'paperloom' } }, null, { version: '3.1.4' });
68
+ const pkg = { version: '3.1.4' };
69
+ const mode = { environment: 'production', build: true, publish: false };
70
+ const packaged = composeBuildConfig({ brand: { id: 'paperloom' } }, buildFacts({ pkg, mode, dev: null }));
69
71
  ctx.expect(packaged.version).toBe('3.1.4');
70
72
  ctx.expect(packaged.brand.id).toBe('paperloom');
71
73
  ctx.expect(packaged.dev).toBeUndefined();
72
74
 
73
75
  // A dev build carries the resolved local-stack map beside it (#300).
74
- const local = composeBuildConfig({ brand: { id: 'paperloom' } }, { ports: { auth: 9099 } }, { version: '3.1.4' });
76
+ const local = composeBuildConfig(
77
+ { brand: { id: 'paperloom' } },
78
+ buildFacts({ pkg, mode: { ...mode, environment: 'development', build: false }, dev: { ports: { auth: 9099 } } }),
79
+ );
75
80
  ctx.expect(local.version).toBe('3.1.4');
76
81
  ctx.expect(local.dev.ports.auth).toBe(9099);
77
82
  },
@@ -72,6 +72,9 @@ module.exports = defineCases({
72
72
  const written = JSON.parse(contents);
73
73
  ctx.expect(written.scripts.build).toBe('omega build');
74
74
  ctx.expect(written.private).toBe(true);
75
+ // Every OMEGA target states its license when it states none of its
76
+ // own (#884): npm's word for closed-source commercial code
77
+ ctx.expect(written.license).toBe('UNLICENSED');
75
78
  ctx.expect(written.main).toBe('dist/main.bundle.js');
76
79
  ctx.expect(contents).toContain('\n "name": "staged-app"');
77
80
  });
@@ -14,7 +14,7 @@ module.exports = defineCases({
14
14
  description: 'sign-windows — signtool command construction + retry policy',
15
15
  tests: [
16
16
  {
17
- name: 'this suite can never sign for real: every signWithRetry call injects its exec',
17
+ name: 'this suite can never sign for real: every call that reaches signtool injects its exec',
18
18
  run: (ctx) => {
19
19
  // The box runs this lane too. `signWithRetry` shells out to signtool by
20
20
  // DEFAULT, so a case that forgets `exec:` would drive the real EV token
@@ -22,13 +22,17 @@ module.exports = defineCases({
22
22
  // lives in sign-windows-e2e.test.js, gated. This pins the invariant.
23
23
  const fs = require('fs');
24
24
  const source = fs.readFileSync(__filename, 'utf8');
25
- // The needle is assembled so this case's own text is not one of its hits.
26
- const calls = source.split(`signWithRetry${'('}`).slice(1);
27
- ctx.expect(calls.length).toBeGreaterThan(0);
28
- for (const call of calls) {
29
- const body = call.slice(0, call.indexOf('});'));
30
- if (!body.includes('exec:')) {
31
- throw new Error(`a signWithRetry call in this suite does not inject exec — it would run the real signtool:\n${body.slice(0, 200)}`);
25
+ // Both entry points reach signtool: the retry wrapper directly, and the
26
+ // signing loop through it plus its own verify call.
27
+ for (const entry of ['signWithRetry', 'signWithSigntool']) {
28
+ // The needle is assembled so this case's own text is not one of its hits.
29
+ const calls = source.split(`${entry}${'('}`).slice(1);
30
+ ctx.expect(calls.length).toBeGreaterThan(0);
31
+ for (const call of calls) {
32
+ const body = call.slice(0, call.indexOf('});'));
33
+ if (!body.includes('exec:')) {
34
+ throw new Error(`a ${entry} call in this suite does not inject exec, it would run the real signtool:\n${body.slice(0, 200)}`);
35
+ }
32
36
  }
33
37
  }
34
38
  },
@@ -143,6 +147,59 @@ module.exports = defineCases({
143
147
  .toBe('"signtool" verify /pa "C:\\out\\App.exe"');
144
148
  },
145
149
  },
150
+ {
151
+ name: 'a signed artifact prints the proof line in the mac shape, after verify passes (#918)',
152
+ run: async (ctx) => {
153
+ // The mac lane ends with `Stapled and verified: ...` (hooks/notarize.js).
154
+ // Windows runs the same kind of proof (`signtool verify /pa`, a failure
155
+ // aborts the job), so it says so in the same shape, naming the check it
156
+ // ran. Driven here through the injected signtool: the ORDER (sign, then
157
+ // verify, THEN the line) is what makes the line true.
158
+ const os = require('os');
159
+ const jetpack = require('fs-jetpack');
160
+
161
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-sign-proof-'));
162
+ const inDir = path.join(tmp, 'release');
163
+ const outDir = path.join(inDir, 'signed');
164
+ const target = path.join(inDir, 'App-windows.msi');
165
+ // .msi on purpose: it needs no latest.yml, so the loop is the whole test.
166
+ jetpack.write(target, 'unsigned bytes');
167
+
168
+ const commands = [];
169
+ const lines = [];
170
+ const fakeLogger = {
171
+ log: (m) => lines.push(String(m)),
172
+ warn: (m) => lines.push(String(m)),
173
+ error: (m) => lines.push(String(m)),
174
+ };
175
+
176
+ const origToken = process.env.WIN_EV_TOKEN_PATH;
177
+ const origPassword = process.env.WIN_CSC_KEY_PASSWORD;
178
+ try {
179
+ // Thumbprint mode with no PIN: SafeNet owns it, so no console-lock check.
180
+ process.env.WIN_EV_TOKEN_PATH = 'f'.repeat(40);
181
+ delete process.env.WIN_CSC_KEY_PASSWORD;
182
+
183
+ await signWindows.signWithSigntool([target], inDir, outDir, {
184
+ exec: (cmd) => { commands.push(cmd); return Promise.resolve('Successfully signed'); },
185
+ logger: fakeLogger,
186
+ });
187
+ } finally {
188
+ if (origToken === undefined) delete process.env.WIN_EV_TOKEN_PATH; else process.env.WIN_EV_TOKEN_PATH = origToken;
189
+ if (origPassword === undefined) delete process.env.WIN_CSC_KEY_PASSWORD; else process.env.WIN_CSC_KEY_PASSWORD = origPassword;
190
+ jetpack.remove(tmp);
191
+ }
192
+
193
+ ctx.expect(commands.length).toBe(2);
194
+ ctx.expect(commands[0]).toContain(' sign /sha1 ');
195
+ ctx.expect(commands[1]).toContain('verify /pa');
196
+ // The proof line is the LAST thing this file's turn prints, and it names
197
+ // the check as well as the artifact: mac punctuation, basename, period.
198
+ ctx.expect(lines[lines.length - 1]).toBe('Signed and verified: signtool verify /pa accepts App-windows.msi.');
199
+ // The old line claimed only a signature, which is what sent the owner asking.
200
+ ctx.expect(lines.some((line) => line.includes('Signed: '))).toBe(false);
201
+ },
202
+ },
146
203
  {
147
204
  name: 'WIN_EV_TOKEN_PATH is the ONE cert-reference key — WIN_CSC_LINK is not read',
148
205
  run: (ctx) => {
@@ -309,5 +366,32 @@ module.exports = defineCases({
309
366
  ctx.expect(signWindows.isTransientSignFailure(new Error('The specified network password is not correct'))).toBe(false);
310
367
  },
311
368
  },
369
+ {
370
+ name: 'a terminated attempt reads as transient, so the next one gets a fresh PIN watcher',
371
+ run: async (ctx) => {
372
+ // The wording is execWithLimit's (exec-with-limit.test.js proves the
373
+ // mechanism); here it only matters that nothing classifies it as final.
374
+ const limitError = new Error('signtool produced no verdict within 180s and was terminated');
375
+ ctx.expect(signWindows.isTransientSignFailure(limitError)).toBe(true);
376
+ ctx.expect(signWindows.SIGN_TIME_LIMIT_MS).toBe(3 * 60 * 1000);
377
+
378
+ let watchers = 0;
379
+ let calls = 0;
380
+ let threw;
381
+ try {
382
+ await signWindows.signWithRetry('signtool sign ...', {
383
+ file: 'App.exe',
384
+ exec: () => { calls += 1; throw limitError; },
385
+ sleep: () => Promise.resolve(),
386
+ emit: () => {},
387
+ startUnlock: () => { watchers += 1; return { stop: () => {} }; },
388
+ });
389
+ } catch (e) { threw = e; }
390
+
391
+ ctx.expect(calls).toBe(3);
392
+ ctx.expect(watchers).toBe(3);
393
+ ctx.expect(threw.message).toMatch(/no verdict within 180s/);
394
+ },
395
+ },
312
396
  ],
313
397
  });
@@ -2,13 +2,15 @@
2
2
  // invisible and non-intrusive". Consumed by window-manager (stealth surfacing),
3
3
  // main.js (macOS app-activation suppression), and the test harness.
4
4
  //
5
- // Build layer runs in plain Node, so the env-var contract (OMEGA_TEST_MODE /
5
+ // Build layer runs in plain Node, so the env-var contract (OMEGA_ENVIRONMENT,
6
+ // the ONE environment input since
7
+ // [#817](https://github.com/Omega-JS-Stack/omega/issues/817), plus
6
8
  // OMEGA_TEST_SHOW) is exercised directly with save/restore around each case.
7
9
 
8
10
  const isTestStealth = require('../../../utils/test-stealth.js');
9
11
  const defineCases = require('../../../vendor/devkit/test/define-cases.js');
10
12
 
11
- // Run fn with OMEGA_TEST_MODE / OMEGA_TEST_SHOW set to the given values (undefined = unset),
13
+ // Run fn with OMEGA_ENVIRONMENT / OMEGA_TEST_SHOW set to the given values (undefined = unset),
12
14
  // restoring the real environment afterwards so other build suites are unaffected.
13
15
  function withEnv(vars, fn) {
14
16
  const saved = {};
@@ -41,7 +43,7 @@ module.exports = defineCases({
41
43
  {
42
44
  name: 'true in testing mode without OMEGA_TEST_SHOW',
43
45
  run: (ctx) => {
44
- withEnv({ OMEGA_TEST_MODE: 'true', OMEGA_TEST_SHOW: undefined }, () => {
46
+ withEnv({ OMEGA_ENVIRONMENT: 'testing', OMEGA_TEST_SHOW: undefined }, () => {
45
47
  ctx.expect(isTestStealth()).toBe(true);
46
48
  });
47
49
  },
@@ -49,7 +51,7 @@ module.exports = defineCases({
49
51
  {
50
52
  name: 'OMEGA_TEST_SHOW=1 opts out even in testing mode',
51
53
  run: (ctx) => {
52
- withEnv({ OMEGA_TEST_MODE: 'true', OMEGA_TEST_SHOW: '1' }, () => {
54
+ withEnv({ OMEGA_ENVIRONMENT: 'testing', OMEGA_TEST_SHOW: '1' }, () => {
53
55
  ctx.expect(isTestStealth()).toBe(false);
54
56
  });
55
57
  },
@@ -57,24 +59,28 @@ module.exports = defineCases({
57
59
  {
58
60
  name: 'false outside testing mode regardless of OMEGA_TEST_SHOW',
59
61
  run: (ctx) => {
60
- withEnv({ OMEGA_TEST_MODE: undefined, OMEGA_TEST_SHOW: undefined, OMEGA_BUILD_MODE: undefined, NODE_ENV: 'development' }, () => {
62
+ withEnv({ OMEGA_ENVIRONMENT: 'development', OMEGA_TEST_SHOW: undefined }, () => {
63
+ ctx.expect(isTestStealth()).toBe(false);
64
+ });
65
+ withEnv({ OMEGA_ENVIRONMENT: 'production', OMEGA_TEST_SHOW: '1' }, () => {
61
66
  ctx.expect(isTestStealth()).toBe(false);
62
67
  });
63
68
  },
64
69
  },
65
70
  {
66
- name: 'a provided manager is authoritative over the env fallback',
71
+ name: 'a provided manager answers from the config IT was baked with',
67
72
  run: (ctx) => {
68
- // Build-time Manager carries the same mode-helpers mixin as the runtime
69
- // Managers — config.em.environment overrides the env detection.
73
+ // The build-time Manager carries the same mixin as the runtime Managers,
74
+ // and since #817 they all read the ONE input: the process variable, or
75
+ // the baked `config.environment` when the process has none.
70
76
  const Manager = require('../../../build.js');
71
- withEnv({ OMEGA_TEST_MODE: undefined, OMEGA_TEST_SHOW: undefined }, () => {
77
+ withEnv({ OMEGA_ENVIRONMENT: undefined, OMEGA_TEST_SHOW: undefined }, () => {
72
78
  const testing = new Manager();
73
- testing.config = { em: { environment: 'testing' } };
79
+ testing.config = { environment: 'testing' };
74
80
  ctx.expect(isTestStealth(testing)).toBe(true);
75
81
 
76
82
  const production = new Manager();
77
- production.config = { em: { environment: 'production' } };
83
+ production.config = { environment: 'production' };
78
84
  ctx.expect(isTestStealth(production)).toBe(false);
79
85
  });
80
86
  },
@@ -69,14 +69,15 @@ const NO_ENV = {
69
69
  module.exports = defineCases({
70
70
  type: 'group', // independent tests; run all even on failure
71
71
  layer: 'build',
72
- description: 'utils/url-helpers: every local helper resolves env → baked dev.ports → classic',
72
+ description: 'utils/url-helpers: every local helper resolves env, then the baked dev.ports, then throws',
73
73
  tests: [
74
74
  {
75
- name: 'exports { attachTo, getApiUrl, localPort }',
75
+ name: 'exports { attachTo, getApiUrl, localPort, requiredPort }',
76
76
  run: (ctx) => {
77
77
  ctx.expect(typeof helpers.attachTo).toBe('function');
78
78
  ctx.expect(typeof helpers.getApiUrl).toBe('function');
79
79
  ctx.expect(typeof helpers.localPort).toBe('function');
80
+ ctx.expect(typeof helpers.requiredPort).toBe('function');
80
81
  },
81
82
  },
82
83
  {
@@ -107,11 +108,19 @@ module.exports = defineCases({
107
108
  },
108
109
  },
109
110
  {
110
- name: 'neither channel → the classic hosting port 5002',
111
+ // The classic 5002 used to answer here (#834). It is gone: a dev build
112
+ // always bakes the resolved map, so neither channel answering means the
113
+ // artifact is broken, and a wrong API base is a silent connection refusal
114
+ // or a hit on a neighbouring project's stack.
115
+ name: 'neither channel → a throw naming the port and the bundle task',
111
116
  run: (ctx) => {
112
117
  withEnv(NO_ENV, () => {
113
- ctx.expect(helpers.getApiUrl.call(fakeManager('testing'))).toBe('http://localhost:5002');
114
- ctx.expect(helpers.getApiUrl.call(fakeManager('development'))).toBe('http://localhost:5002');
118
+ for (const environment of ['testing', 'development']) {
119
+ ctx.expect(() => helpers.getApiUrl.call(fakeManager(environment)))
120
+ .toThrow(/dev port for `hosting`/);
121
+ ctx.expect(() => helpers.getApiUrl.call(fakeManager(environment)))
122
+ .toThrow(/bundle task/);
123
+ }
115
124
  });
116
125
  },
117
126
  },
@@ -163,11 +172,11 @@ module.exports = defineCases({
163
172
  },
164
173
  },
165
174
  {
166
- name: 'getFunctionsUrl: neither channel → the classic functions port 5001',
175
+ name: 'getFunctionsUrl: neither channel → a throw naming the port (#834)',
167
176
  run: (ctx) => {
168
177
  withEnv(NO_ENV, () => {
169
- ctx.expect(helpers.getFunctionsUrl.call(fakeManager('development')))
170
- .toBe('http://localhost:5001/demo-app/us-central1');
178
+ ctx.expect(() => helpers.getFunctionsUrl.call(fakeManager('development')))
179
+ .toThrow(/dev port for `functions`/);
171
180
  });
172
181
  },
173
182
  },
@@ -200,10 +209,11 @@ module.exports = defineCases({
200
209
  },
201
210
  },
202
211
  {
203
- name: 'getWebsiteUrl: neither channel → the classic dev origin https://localhost:4000',
212
+ name: 'getWebsiteUrl: neither channel → a throw naming the port (#834)',
204
213
  run: (ctx) => {
205
214
  withEnv(NO_ENV, () => {
206
- ctx.expect(helpers.getWebsiteUrl.call(fakeManager('development'))).toBe('https://localhost:4000');
215
+ ctx.expect(() => helpers.getWebsiteUrl.call(fakeManager('development')))
216
+ .toThrow(/dev port for `website`/);
207
217
  });
208
218
  },
209
219
  },
@@ -228,12 +238,18 @@ module.exports = defineCases({
228
238
  },
229
239
  },
230
240
  {
231
- // The lockstep the renderer bundle forces: url-helpers rides the browser
232
- // bundle, so it cannot require @omega.js/config (fs/net/json5) and mirrors
233
- // the constant instead. This Node-side case is what keeps the copy honest.
234
- name: 'CLASSIC_DEV_ORIGIN is in lockstep with @omega.js/config',
241
+ // There is no lockstep copy to keep honest any more (#834): the classic
242
+ // numbers live ONLY in @omega.js/config, the bundle task bakes them into
243
+ // the artifact as the floor of the resolved map, and this module reads
244
+ // that map. A copy here would be the exact defect the issue closed.
245
+ name: 'no classic constants live in this module (#834)',
235
246
  run: (ctx) => {
236
- ctx.expect(helpers.CLASSIC_DEV_ORIGIN).toBe(require('../../../vendor/config/index.js').CLASSIC_DEV_ORIGIN);
247
+ ctx.expect(helpers.CLASSIC_DEV_ORIGIN).toBe(undefined);
248
+ const source = require('fs').readFileSync(require.resolve('../../../utils/url-helpers.js'), 'utf8');
249
+ const code = source.split('\n').filter((line) => !line.trim().startsWith('//')).join('\n');
250
+ for (const classic of ['4000', '5001', '5002', '9099']) {
251
+ ctx.expect(code.includes(classic)).toBe(false);
252
+ }
237
253
  },
238
254
  },
239
255
  {
@@ -244,7 +260,7 @@ module.exports = defineCases({
244
260
  withEnv(NO_ENV, () => {
245
261
  // getAuthUrl calls `this.getWebsiteUrl()`, which attachTo() supplies on a
246
262
  // real Manager — hand the stand-in the same helper.
247
- const manager = fakeManager('development');
263
+ const manager = fakeManager('development', { website: 4000 });
248
264
  manager.getWebsiteUrl = helpers.getWebsiteUrl;
249
265
  const url = new URL(helpers.getAuthUrl.call(manager));
250
266
  ctx.expect(url.origin).toBe('https://localhost:4000');
@@ -274,8 +290,12 @@ module.exports = defineCases({
274
290
  withBridgeManager(fakeManager('testing', { auth: 9109 }), () => {
275
291
  ctx.expect(clientBridge._authEmulatorPort()).toBe(9109);
276
292
  });
293
+ // The classic 9099 used to answer here (#834): nothing identity-checks
294
+ // what holds that port, so a neighbouring project's emulator read as
295
+ // an auth mystery instead of a port problem.
277
296
  withBridgeManager(fakeManager('testing'), () => {
278
- ctx.expect(clientBridge._authEmulatorPort()).toBe(9099);
297
+ ctx.expect(() => clientBridge._authEmulatorPort()).toThrow(/dev port for `auth`/);
298
+ ctx.expect(() => clientBridge._authEmulatorPort()).toThrow(/bundle task/);
279
299
  });
280
300
  });
281
301
  withEnv({ OMEGA_AUTH_PORT: '9119' }, () => {