@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
@@ -7,11 +7,15 @@
7
7
  * `omega deploy` — as a precheck before the dispatch:
8
8
  *
9
9
  * framework freshness the npm registry's latest vs the installed version
10
- * validate-certs the signing prereqs, soft (a warning, never fatal)
10
+ * validate-certs the signing prereqs, STRICT and fatal (#891)
11
11
  * provision-repos the public releases repo the config names (idempotent)
12
- * push-secrets the composed target env → GitHub Actions repo secrets
12
+ * push-secrets the composed target env into GitHub Actions repo
13
+ * secrets, fatal (#891)
13
14
  *
14
- * Every step is soft: a precheck reports, the deploy proceeds. `--no-secrets`
15
+ * The two SIGNING steps are fatal and everything else is soft: a deploy is how
16
+ * a signed, notarized release ships, so material that is missing or expired
17
+ * stops the run here ([#891](https://github.com/Omega-JS-Stack/omega/issues/891))
18
+ * instead of producing a green run with an app Gatekeeper refuses. `--no-secrets`
15
19
  * skips the whole precheck — the same opt-out name on web, desktop and
16
20
  * extension (parity; desktop's old `--quick` is gone).
17
21
  *
@@ -21,45 +25,60 @@
21
25
  const Manager = new (require('../../build.js'));
22
26
  const { runDeployPrecheck } = require('../../vendor/devkit/deploy-precheck.js');
23
27
  const { releasesRepo } = require('../../vendor/config/index.js');
28
+ const { publishTargetSecrets } = require('../../vendor/devkit/target-secrets.js');
29
+ const { resolveToken } = require('../../vendor/devkit/deploy.js');
24
30
  const { updateManager } = require('./dependencies.js');
25
- const { publishEnvSecrets } = require('../push-secrets.js');
26
31
 
27
32
  const package = Manager.getPackage('main');
28
33
 
29
34
  /**
30
35
  * Auto-provision the brand's ONE public releases repo, addressed by
31
- * @omega.js/config's `releasesRepo` (`<brand.id>-releases` under the brand repo
32
- * owner unless the config names another). Idempotent: only creates if missing.
33
- * Config-only, never the git remote: a brand nested in another repo would
34
- * provision under the enclosing repo's owner (#799).
36
+ * @omega.js/config's `releasesRepo` (`<brand.id>-releases` under the brand's
37
+ * org, #883: no repo name is ever typed). Idempotent: only creates if
38
+ * missing. Config-only, never the git remote: a brand nested in another repo
39
+ * would provision under the enclosing repo's owner (#799).
40
+ *
41
+ * PUBLIC, always: a shipped app polls this feed with no token, and so does a
42
+ * download button on the site. It is created with a first commit (`autoInit`),
43
+ * because a release needs a tag and a tag needs a commit.
44
+ *
45
+ * The repo itself is created by `@omega.js/devkit/github-repo`'s ensureRepo,
46
+ * the ONE home every OMEGA repo is created and reconciled from (#883): the
47
+ * manage walk and the web deploy call the same function.
35
48
  *
36
49
  * @param {object} input
37
50
  * @param {Function} input.log - Progress line sink.
38
51
  * @param {Function} input.warn - Warning sink.
39
- * @param {object} [input.octokit] - Injectable client (tests); defaults to the GH_TOKEN one.
40
52
  * @param {object} [input.config] - Injectable resolved config (tests).
53
+ * @param {boolean} [input.dryRun] - Plan only: ensureRepo builds the plan and
54
+ * creates nothing (#895).
55
+ * @param {Function} [input.execFn] - Injectable `gh` exec (tests).
41
56
  */
42
- async function provisionReleaseRepos({ log, warn, octokit, config }) {
43
- const { getOctokit, ensureRepo } = require('../../utils/github.js');
44
- const client = octokit || getOctokit();
45
- if (!client) return;
57
+ async function provisionReleaseRepos({ log, warn, config, execFn, dryRun }) {
58
+ const { ensureRepo } = require('../../vendor/devkit/github-repo.js');
46
59
 
47
60
  const resolved = config || Manager.getConfig() || {};
48
61
  if (resolved.releases?.enabled === false) return;
49
62
 
50
- const { owner, name, repo } = releasesRepo(resolved);
51
- if (!repo) {
52
- warn('provision-repos: could not address the releases repo. Set repo.providers.github.org (or targets.desktop.releases.owner) and brand.id in config/omega.json5.');
63
+ const releases = releasesRepo(resolved);
64
+ if (!releases) {
65
+ warn('provision-repos: could not address the releases repo. Set repo.org and brand.id in config/omega.json5 (the releases repo is <brand.id>-releases under that org).');
53
66
  return;
54
67
  }
55
68
 
56
- const description = `Public release artifacts + auto-update feed for ${owner}'s @omega.js/desktop apps. Managed by @omega.js/desktop.`;
69
+ const description = `Public release artifacts + auto-update feed for ${releases.owner}'s @omega.js/desktop apps. Managed by @omega.js/desktop.`;
57
70
 
58
71
  try {
59
- const result = await ensureRepo(client, owner, name, { description, private: false });
60
- log(`provision-repos: ✓ ${result.created ? 'created ' : ''}${repo}${result.created ? '' : ' already exists'} — releases (auto-update feed + the site's download links)`);
72
+ const result = await ensureRepo({
73
+ owner: releases.owner,
74
+ name: releases.name,
75
+ private: false,
76
+ description,
77
+ autoInit: true,
78
+ }, { execFn, dryRun });
79
+ log(`provision-repos: ✓ ${result.created ? 'created ' : ''}${releases.slug}${result.created ? '' : ' already exists'}: releases (auto-update feed + the site's download links)`);
61
80
  } catch (e) {
62
- warn(`provision-repos: ✗ ${repo} (releases) — ${e.message}`);
81
+ warn(`provision-repos: ✗ ${releases.slug} (releases): ${e.message}`);
63
82
  }
64
83
  }
65
84
 
@@ -73,32 +92,44 @@ const STEPS = [
73
92
  run: ({ projectDir, log, warn }) => updateManager({ projectDir, package, log, error: warn }),
74
93
  },
75
94
  {
95
+ // STRICT, and fatal: a deploy is how a signed release ships, so signing
96
+ // material that is missing, expired or unreadable stops it here rather than
97
+ // producing a green run with an unsigned app in it (#891).
76
98
  name: 'validate-certs',
77
- run: async ({ log }) => {
99
+ fatal: true,
100
+ run: async () => {
78
101
  const validateCerts = require('../validate-certs.js');
79
- const result = await validateCerts({ strict: false });
80
- if (result?.ok === false) {
81
- log('(Run `npx omega validate-certs` after wiring up your signing assets to re-check.)');
82
- }
102
+ await validateCerts({ strict: true });
83
103
  },
84
104
  },
85
105
  {
86
106
  name: 'provision-repos',
87
- run: async ({ projectDir, log, warn }) => {
107
+ run: async ({ projectDir, log, warn, dryRun }) => {
88
108
  require('../../vendor/config/index.js').loadEnv(projectDir);
89
- if (!process.env.GH_TOKEN) {
90
- return log('(Skipping repo provisioning: GH_TOKEN not set.)');
109
+ // The same token chain the dispatch resolves (`GH_TOKEN` →
110
+ // `GITHUB_TOKEN` → `gh auth token`): a machine signed in with `gh` and
111
+ // no variable exported can provision its repos like any other.
112
+ if (!resolveToken()) {
113
+ return log('(Skipping repo provisioning: no GitHub token. Set GH_TOKEN, or sign in with `gh auth login`.)');
91
114
  }
92
- await provisionReleaseRepos({ log, warn });
115
+ await provisionReleaseRepos({ log, warn, dryRun });
93
116
  },
94
117
  },
95
118
  {
96
119
  name: 'push-secrets',
97
120
  // No .env check and no PAT: the keys come from the composed target env (the
98
121
  // brand root's .env, #678) and the transport is `gh`'s own auth session
99
- // ([#682](https://github.com/Omega-JS-Stack/omega/issues/682)) — the same
100
- // one-line call web and the extension make.
101
- run: ({ projectDir, log, warn }) => publishEnvSecrets({ targetDir: projectDir, logger: { log, warn, error: warn } }),
122
+ // ([#682](https://github.com/Omega-JS-Stack/omega/issues/682)), the same
123
+ // one-line call web, backend and the extension make. Fatal: the runner
124
+ // signs with what this step sends, so a refused or half publish must stop
125
+ // the deploy instead of handing CI a set it cannot sign with (#891).
126
+ fatal: true,
127
+ run: ({ projectDir, log, warn, dryRun }) => publishTargetSecrets({
128
+ targetDir: projectDir,
129
+ target: 'desktop',
130
+ logger: { log, warn, error: warn },
131
+ dryRun,
132
+ }),
102
133
  },
103
134
  ];
104
135
 
@@ -108,10 +139,11 @@ const STEPS = [
108
139
  * @param {object} input.options - The parsed CLI options (`secrets: false` = opted out).
109
140
  * @param {object} input.logger - `{ log, warn, error }`.
110
141
  * @param {Array} [input.steps] - Injectable step list (tests).
142
+ * @param {boolean} [input.dryRun] - Plan only; handed to every step (#895).
111
143
  * @returns {Promise<{ skipped: string }|{ ran: string[] }>} The steps that ran, or the opt-out marker.
112
144
  */
113
- function deployPrecheck({ projectDir, options, logger, steps }) {
114
- return runDeployPrecheck({ projectDir, options, logger, steps: steps || STEPS });
145
+ function deployPrecheck({ projectDir, options, logger, steps, dryRun }) {
146
+ return runDeployPrecheck({ projectDir, options, logger, steps: steps || STEPS, dryRun });
115
147
  }
116
148
 
117
149
  module.exports = { deployPrecheck, STEPS, provisionReleaseRepos };
@@ -34,7 +34,7 @@ const version = require('wonderful-version');
34
34
  const Manager = new (require('../../build.js'));
35
35
  const { ensurePeerDependencies, readProject } = require('./dependencies.js');
36
36
  const { renderSecretsBlock } = require('../../vendor/config/env-delivery.js');
37
- const { composeTargetWorkflows } = require('../../vendor/devkit/ci-workflows.js');
37
+ const { composeTargetWorkflows, renderInstallFirewall, renderInstallWorkspace } = require('../../vendor/devkit/ci-workflows.js');
38
38
  const { assertScaffoldable } = require('../../vendor/devkit/scaffold-guard.js');
39
39
 
40
40
  const logger = Manager.logger('ensure-target');
@@ -42,7 +42,8 @@ const package = Manager.getPackage('main');
42
42
 
43
43
  /**
44
44
  * Sync the consumer manifest: the omega verb scripts, the npm-private latch,
45
- * and the electron main entry (the gulp `bundle` task's output bundle).
45
+ * the license (#884, seeded only when the manifest states none), and the
46
+ * electron main entry (the gulp `bundle` task's output bundle).
46
47
  * Identical content is not a write (#590).
47
48
  */
48
49
  function setupScripts(projectDir, result) {
@@ -60,6 +61,12 @@ function setupScripts(projectDir, result) {
60
61
  // Electron consumer projects should not be published to npm
61
62
  project.private = true;
62
63
 
64
+ // The license every OMEGA target states when it states none of its own
65
+ // ([#884](https://github.com/Omega-JS-Stack/omega/issues/884)): UNLICENSED is
66
+ // npm's word for closed-source commercial code, and electron-builder reads
67
+ // the field for the packaged app's metadata. A brand's own license is kept.
68
+ project.license = project.license || 'UNLICENSED';
69
+
63
70
  // Point electron at the built main bundle.
64
71
  // The gulp `bundle` task emits dist/main.bundle.js; the consumer's src/main.js is the *source* entry.
65
72
  project.main = 'dist/main.bundle.js';
@@ -75,7 +82,7 @@ function setupScripts(projectDir, result) {
75
82
  }
76
83
 
77
84
  jetpack.write(projectPath, contents);
78
- result.changed.push('package.json (scripts + main + private)');
85
+ result.changed.push('package.json (scripts + main + private + license)');
79
86
  }
80
87
 
81
88
  /**
@@ -141,9 +148,15 @@ async function copyDefaults(projectDir, engineLogger) {
141
148
  // `KEY: ${{ secrets.KEY }}` line per key the schema delivers to desktop, at
142
149
  // the token's two-space indent. The yml rule below re-renders on every verb,
143
150
  // so the block tracks the schema like the node version tracks the pin.
151
+ // The composed half (#835): the brand's PRODUCTION values name the keys the
152
+ // schema cannot, which on desktop is the consumer's own `.env` lines. NAMES
153
+ // only ever reach the workflow file; no value is rendered anywhere.
154
+ const { composeTargetEnv } = require('../../vendor/config/index.js');
155
+ const { values: composed } = composeTargetEnv({ targetDir: projectDir, target: 'desktop', environment: 'production' });
156
+
144
157
  const templateContext = {
145
158
  versions: { ...(package.engines || {}), node: package.omega.nodeRuntime },
146
- githubSecrets: renderSecretsBlock('desktop', { indent: ' ' }),
159
+ githubSecrets: renderSecretsBlock('desktop', { indent: ' ', values: composed }),
147
160
  };
148
161
 
149
162
  // Scaffolding runs through the shared devkit engine (vendored at prepare time).
@@ -177,6 +190,11 @@ async function copyDefaults(projectDir, engineLogger) {
177
190
  // target .env is an optional per-key override a HUMAN writes, and no
178
191
  // machine writes a target .env — so the template is gone.
179
192
  '_.gitignore': { mergeLines: true, template: templateContext },
193
+ // The one TRACKED file under config/certs/ ([#913](https://github.com/Omega-JS-Stack/omega/issues/913)),
194
+ // and framework-owned like the workflow YAMLs: it explains where signing
195
+ // material really lives, so a target keeps the explanation that matches
196
+ // the ignore rules the scaffold just wrote, never an older one.
197
+ 'config/certs/README.md': { overwrite: true },
180
198
  // The agent-docs chain (#63): AGENTS.md carries the content (marker-merged
181
199
  // like .gitignore), CLAUDE.md is the one-line `@AGENTS.md` pointer — copied
182
200
  // when missing by the `**/*` rule above, never clobbered.
@@ -205,6 +223,15 @@ async function copyDefaults(projectDir, engineLogger) {
205
223
  // rule above; a STANDALONE target (its own git root) keeps its own copy.
206
224
  ...(isBrandTarget ? { '.github/**/*': { skip: true } } : {}),
207
225
  },
226
+ // The firewall step and the workspace flag are devkit's, rendered wherever
227
+ // a workflow is WRITTEN ([#872](https://github.com/Omega-JS-Stack/omega/issues/872),
228
+ // [#898](https://github.com/Omega-JS-Stack/omega/issues/898)): the brand
229
+ // lane gets both inside composeWorkflow below, a STANDALONE target here, on
230
+ // the copy this engine writes. The action, its pin and the flag live in ONE
231
+ // place, so none of the four templates restates them. A standalone target
232
+ // is its own repo root and declares no workspaces, so the flag renders to
233
+ // nothing here.
234
+ transform: (contents) => renderInstallWorkspace(renderInstallFirewall(contents)),
208
235
  logger: engineLogger,
209
236
  });
210
237
 
@@ -221,21 +248,54 @@ async function copyDefaults(projectDir, engineLogger) {
221
248
  });
222
249
  }
223
250
 
251
+ removeRetiredCertsIgnore(projectDir, engineLogger);
252
+
224
253
  return applied;
225
254
  }
226
255
 
227
- /** Warn when the framework is a `file:` link — that install never publishes. */
228
- function checkLocality(projectDir, warn) {
256
+ /**
257
+ * Remove the sibling `config/certs/.gitignore` left over from the era when
258
+ * `config/certs/` was ignored whole
259
+ * ([#913](https://github.com/Omega-JS-Stack/omega/issues/913)). The directory's
260
+ * README is the one tracked explanation of where signing material really lives,
261
+ * and a nested ignore file of `*` + `!.gitignore` beats the parent file, so it
262
+ * keeps hiding the README on a target scaffolded before the new rules. The
263
+ * parent's own retired `config/certs/` line needs no healing: the marker merge
264
+ * drops it with the rest of the framework block
265
+ * ([#926](https://github.com/Omega-JS-Stack/omega/issues/926)). A copy an
266
+ * EARLIER run already moved into the consumer's Custom section is the
267
+ * consumer's by that rule and is left alone.
268
+ *
269
+ * The sibling is framework-written and known byte for byte, so only that exact
270
+ * shape is removed. Anything a consumer wrote stays.
271
+ *
272
+ * @param {string} projectDir - The target root.
273
+ * @param {object} engineLogger - `{ log, warn }`.
274
+ */
275
+ function removeRetiredCertsIgnore(projectDir, engineLogger) {
276
+ const siblingPath = path.join(projectDir, 'config', 'certs', '.gitignore');
277
+ const sibling = jetpack.read(siblingPath);
278
+
279
+ if (sibling && sibling.replace(/\r\n/g, '\n').trim() === '*\n!.gitignore') {
280
+ jetpack.remove(siblingPath);
281
+ engineLogger.log('Healed → config/certs/.gitignore (retired: the target .gitignore owns this directory)');
282
+ }
283
+ }
284
+
285
+ /**
286
+ * The framework must BE a dependency of the target: everything below it reads
287
+ * the installed version. A `file:` spec is no finding of its own
288
+ * ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)): the deploy
289
+ * snapshot packs every locally linked package into the mirror it pushes, so a
290
+ * local install is exactly what the deploy is built for.
291
+ */
292
+ function checkLocality(projectDir) {
229
293
  const project = readProject(projectDir);
230
294
  const installedVersion = project.devDependencies[package.name] || project.dependencies[package.name];
231
295
 
232
296
  if (!installedVersion) {
233
297
  throw new Error(`No installed version of ${package.name} found in dependencies or devDependencies.`);
234
298
  }
235
-
236
- if (installedVersion.startsWith('file:')) {
237
- warn(`⚠️ You are using the local version of ${package.name}. This WILL NOT WORK when published.`);
238
- }
239
299
  }
240
300
 
241
301
  /**
@@ -288,7 +348,7 @@ async function ensureTarget(options) {
288
348
  result.merged.push(...applied.merged);
289
349
  }
290
350
 
291
- checkLocality(projectDir, warn);
351
+ checkLocality(projectDir);
292
352
 
293
353
  for (const [label, files] of [['Created', result.written], ['Merged', result.merged], ['Synced', result.changed]]) {
294
354
  if (files.length > 0) log(`${label} ${files.join(', ')}`);
@@ -16,7 +16,6 @@ function plan(options) {
16
16
  env: { OMEGA_BUILD_MODE: 'true' },
17
17
  steps: [
18
18
  { type: 'clean' },
19
- { type: 'certs' },
20
19
  { type: 'gulp', task: quick ? 'packageQuick' : 'packageBuild' },
21
20
  ],
22
21
  };
@@ -5,9 +5,16 @@ const { runPipeline } = require('../utils/build-pipeline.js');
5
5
 
6
6
  // `npx omega publish` publishes from an already-built tree (the CI lane calls it
7
7
  // after its own build); `--local` (the consumer's `release:local` script) cleans
8
- // first. Both deliver the Apple signing artifacts (#678) and then run cert
9
- // validation before the gulp task — a warning gate unless `--strict` makes it
10
- // fatal (validate-certs.js owns that).
8
+ // first. Both check the SHIP credentials the brand's declared formats need
9
+ // before anything else runs (#867: a declared snap with no Snap Store login is
10
+ // a release that dies on a runner, so it is refused in a second rather than in
11
+ // a build), then deliver the Apple signing artifacts (#678) and run cert
12
+ // validation before the gulp task, STRICT
13
+ // ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)): publish is the
14
+ // verb that puts a build in front of users, so signing material it cannot find
15
+ // stops it here rather than shipping an app Gatekeeper refuses. What is strict
16
+ // about it is the mac leg (validate-certs.js owns that rule: a leg that cannot
17
+ // sign for mac only warns).
11
18
  function plan(options) {
12
19
  options = options || {};
13
20
 
@@ -17,7 +24,7 @@ function plan(options) {
17
24
  steps.push({ type: 'clean' });
18
25
  }
19
26
 
20
- steps.push({ type: 'certs' }, { type: 'validate-certs' }, { type: 'gulp', task: 'publish' });
27
+ steps.push({ type: 'ship-keys' }, { type: 'validate-certs', strict: true }, { type: 'gulp', task: 'publish' });
21
28
 
22
29
  return {
23
30
  env: { OMEGA_BUILD_MODE: 'true', OMEGA_IS_PUBLISH: 'true' },