@omega.js/desktop 0.50.0 → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/assets/css/tokens/_index.scss +1 -1
- package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
- package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
- package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
- package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
- package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
- package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
- package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
- package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
- package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
- package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
- package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
- package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
- package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
- package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
- package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
- package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
- package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
- package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
- package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
- package/dist/build.js +69 -28
- package/dist/cli-run.js +20 -13
- package/dist/cli.js +12 -7
- package/dist/commands/build.js +0 -2
- package/dist/commands/deploy.js +116 -44
- package/dist/commands/finalize-release.js +5 -4
- package/dist/commands/launch.js +12 -7
- package/dist/commands/lib/deploy-precheck.js +66 -34
- package/dist/commands/lib/ensure-target.js +71 -11
- package/dist/commands/package.js +0 -1
- package/dist/commands/publish.js +11 -4
- package/dist/commands/release.js +99 -252
- package/dist/commands/runner.js +176 -42
- package/dist/commands/sign-windows.js +46 -15
- package/dist/commands/test.js +4 -3
- package/dist/commands/validate-certs.js +291 -115
- package/dist/config/page-template.html +4 -0
- package/dist/defaults/.github/workflows/build.yml +146 -64
- package/dist/defaults/AGENTS.md +3 -2
- package/dist/defaults/_.gitignore +4 -2
- package/dist/defaults/config/certs/README.md +25 -45
- package/dist/defaults/config/omega.json5 +66 -32
- package/dist/defaults/hooks/deploy/pre.js +10 -0
- package/dist/defaults/src/assets/scss/main.scss +12 -2
- package/dist/defaults/src/integrations/tray/index.js +1 -1
- package/dist/gulp/main.js +13 -25
- package/dist/gulp/tasks/audit.js +18 -6
- package/dist/gulp/tasks/build-config.js +181 -60
- package/dist/gulp/tasks/bundle.js +108 -36
- package/dist/gulp/tasks/release.js +86 -4
- package/dist/gulp/tasks/sass.js +11 -0
- package/dist/hooks/lib/notarize-tools.js +137 -0
- package/dist/hooks/notarize-artifacts.js +57 -0
- package/dist/hooks/notarize.js +59 -8
- package/dist/lib/auth-persistence.js +25 -0
- package/dist/lib/client-bridge.js +11 -8
- package/dist/lib/deep-link.js +15 -8
- package/dist/lib/protocol.js +7 -1
- package/dist/lib/restart-manager/install.js +6 -3
- package/dist/lib/sign-helpers/auto-unlock.js +65 -27
- package/dist/lib/sign-helpers/console-lock.js +34 -0
- package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
- package/dist/lib/sign-helpers/resolve-icons.js +6 -4
- package/dist/lib/tray.js +7 -6
- package/dist/main.js +16 -0
- package/dist/preload.js +8 -0
- package/dist/renderer.js +16 -4
- package/dist/runner/job-started.js +104 -0
- package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
- package/dist/test/fixtures/consumer-app/package.json +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
- package/dist/test/harness/main-entry.js +2 -1
- package/dist/test/harness/renderer-preload.js +12 -3
- package/dist/test/runners/boot.js +101 -11
- package/dist/test/runners/electron.js +1 -1
- package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
- package/dist/test/suites/build/audit.test.js +45 -6
- package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
- package/dist/test/suites/build/auto-unlock.test.js +105 -0
- package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
- package/dist/test/suites/build/brand-scss.test.js +106 -0
- package/dist/test/suites/build/build-config.test.js +146 -36
- package/dist/test/suites/build/build-json-bake.test.js +245 -0
- package/dist/test/suites/build/build-verbs.test.js +48 -15
- package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
- package/dist/test/suites/build/cli.test.js +32 -10
- package/dist/test/suites/build/config-schema.test.js +4 -4
- package/dist/test/suites/build/console-lock.test.js +51 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
- package/dist/test/suites/build/deploy-direct.test.js +241 -0
- package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
- package/dist/test/suites/build/deploy-hook.test.js +169 -0
- package/dist/test/suites/build/ensure-target.test.js +14 -2
- package/dist/test/suites/build/env-delivery.test.js +19 -10
- package/dist/test/suites/build/env-watch.test.js +18 -7
- package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
- package/dist/test/suites/build/exec-with-limit.test.js +53 -0
- package/dist/test/suites/build/finalize-release.test.js +2 -2
- package/dist/test/suites/build/get-config.test.js +120 -8
- package/dist/test/suites/build/github-utils.test.js +12 -6
- package/dist/test/suites/build/license-stamp.test.js +6 -4
- package/dist/test/suites/build/manager.test.js +88 -68
- package/dist/test/suites/build/manifest-deps.test.js +116 -0
- package/dist/test/suites/build/merge-line-files.test.js +27 -4
- package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
- package/dist/test/suites/build/notarize-tools.test.js +38 -0
- package/dist/test/suites/build/notarize.test.js +207 -0
- package/dist/test/suites/build/release-pipeline.test.js +38 -60
- package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
- package/dist/test/suites/build/resolve-icons.test.js +35 -35
- package/dist/test/suites/build/runner-job-guard.test.js +182 -0
- package/dist/test/suites/build/runner.test.js +635 -5
- package/dist/test/suites/build/sentry.test.js +8 -3
- package/dist/test/suites/build/setup-scripts.test.js +3 -0
- package/dist/test/suites/build/sign-windows.test.js +92 -8
- package/dist/test/suites/build/test-stealth.test.js +17 -11
- package/dist/test/suites/build/url-helpers.test.js +37 -17
- package/dist/test/suites/build/validate-certs.test.js +428 -55
- package/dist/test/suites/build/validate-config.test.js +3 -3
- package/dist/test/suites/main/auth-flow.test.js +12 -0
- package/dist/test/suites/main/auth-persistence.test.js +14 -17
- package/dist/test/suites/main/auto-updater.test.js +2 -2
- package/dist/test/suites/main/boot-sequence.test.js +1 -1
- package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
- package/dist/test/suites/main/client-bridge.test.js +19 -6
- package/dist/test/suites/main/deep-link.test.js +54 -0
- package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
- package/dist/test/suites/main/url-helpers.test.js +81 -72
- package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
- package/dist/utils/build-pipeline.js +10 -10
- package/dist/utils/github.js +12 -51
- package/dist/utils/load-env.js +66 -0
- package/dist/utils/mode-helpers.js +43 -111
- package/dist/utils/platform.js +37 -0
- package/dist/utils/runner-env.js +2 -1
- package/dist/utils/runner-job-guard.js +149 -0
- package/dist/utils/ship-keys.js +52 -0
- package/dist/utils/test-stealth.js +5 -3
- package/dist/utils/url-helpers.js +33 -17
- package/dist/vendor/config/bundle-id.js +53 -0
- package/dist/vendor/config/client-config.js +141 -0
- package/dist/vendor/config/company.js +334 -15
- package/dist/vendor/config/dev-facts.js +48 -0
- package/dist/vendor/config/env-delivery.js +231 -9
- package/dist/vendor/config/env-retired.js +137 -0
- package/dist/vendor/config/env-rules.js +22 -3
- package/dist/vendor/config/env-schema.js +234 -117
- package/dist/vendor/config/env.js +55 -26
- package/dist/vendor/config/environment.js +189 -0
- package/dist/vendor/config/hooks.js +13 -11
- package/dist/vendor/config/index.js +125 -44
- package/dist/vendor/config/load.js +366 -115
- package/dist/vendor/config/merge.js +2 -2
- package/dist/vendor/config/order.js +3 -3
- package/dist/vendor/config/platforms.js +276 -0
- package/dist/vendor/config/repo.js +249 -103
- package/dist/vendor/config/retired-keys.js +232 -27
- package/dist/vendor/config/schema.js +525 -99
- package/dist/vendor/config/site-global.js +63 -53
- package/dist/vendor/config/targets.js +187 -0
- package/dist/vendor/config/validate.js +119 -59
- package/dist/vendor/devkit/argv.js +118 -0
- package/dist/vendor/devkit/attach-log-file.js +21 -13
- package/dist/vendor/devkit/brand-tokens.js +278 -0
- package/dist/vendor/devkit/brand-version.js +425 -0
- package/dist/vendor/devkit/build-json.js +91 -0
- package/dist/vendor/devkit/bundle.js +48 -0
- package/dist/vendor/devkit/certificate-expiry.js +108 -0
- package/dist/vendor/devkit/certs.js +16 -194
- package/dist/vendor/devkit/ci-workflows.js +124 -8
- package/dist/vendor/devkit/cli-router.js +3 -3
- package/dist/vendor/devkit/defaults-engine.js +69 -7
- package/dist/vendor/devkit/deploy-follow.js +297 -0
- package/dist/vendor/devkit/deploy-precheck.js +23 -8
- package/dist/vendor/devkit/deploy-record.js +11 -27
- package/dist/vendor/devkit/deploy-snapshot.js +661 -0
- package/dist/vendor/devkit/deploy.js +505 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +172 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +98 -3
- package/dist/vendor/devkit/lockfile.js +127 -0
- package/dist/vendor/devkit/merge-line-files.js +23 -16
- package/dist/vendor/devkit/omega-bin.js +18 -3
- package/dist/vendor/devkit/pack-local.js +388 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +142 -0
- package/dist/vendor/devkit/service-account.js +43 -0
- package/dist/vendor/devkit/ship-plan.js +112 -0
- package/dist/vendor/devkit/signing-env.js +180 -0
- package/dist/vendor/devkit/signing-tree.js +92 -0
- package/dist/vendor/devkit/target-seams.js +142 -0
- package/dist/vendor/devkit/target-secrets.js +231 -57
- package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
- package/dist/vendor/monitoring/env.js +20 -10
- package/dist/vendor/monitoring/main.js +1 -1
- package/dist/vendor/monitoring/preload.js +1 -1
- package/dist/vendor/monitoring/renderer.js +1 -1
- package/docs/analytics.md +1 -1
- package/docs/auto-updater.md +5 -5
- package/docs/boot-sequence.md +1 -1
- package/docs/build-system.md +15 -7
- package/docs/client-bridge.md +9 -7
- package/docs/config-schema.md +4 -4
- package/docs/css.md +8 -2
- package/docs/deep-link.md +12 -4
- package/docs/environment-detection.md +32 -24
- package/docs/hooks.md +3 -1
- package/docs/icons.md +7 -7
- package/docs/index.md +61 -23
- package/docs/installer-options.md +24 -21
- package/docs/logging.md +5 -5
- package/docs/releasing.md +29 -19
- package/docs/runner.md +51 -14
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +764 -199
- package/docs/shared/deploys.md +217 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +28 -8
- package/docs/shared/logging.md +9 -6
- package/docs/shared/monitoring.md +27 -13
- package/docs/shared/publishing.md +3 -3
- package/docs/shared/rulings.md +2 -2
- package/docs/shared/testing.md +1 -1
- package/docs/shared/theming.md +26 -1
- package/docs/shared/translation.md +49 -7
- package/docs/shared/updates.md +1 -1
- package/docs/signing.md +60 -34
- package/docs/test-framework.md +10 -5
- package/docs/themes.md +15 -1
- package/package.json +18 -12
- package/bin/omega-desktop +0 -2
- package/dist/commands/push-secrets.js +0 -141
- package/dist/test/suites/build/deliver-certs.test.js +0 -95
- package/dist/test/suites/build/derive-signing-env.test.js +0 -122
- package/dist/test/suites/build/push-secrets.test.js +0 -226
- package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
- package/dist/utils/deliver-certs.js +0 -69
- package/dist/utils/derive-signing-env.js +0 -56
- package/dist/utils/resolve-signing-cert.js +0 -175
- package/dist/vendor/config/desktop-artifacts.js +0 -110
- package/dist/vendor/config/instances.js +0 -208
- /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
package/dist/commands/runner.js
CHANGED
|
@@ -14,18 +14,20 @@
|
|
|
14
14
|
// the defaults — and the orgs it serves. How a value that
|
|
15
15
|
// is already there gets changed.
|
|
16
16
|
// register-org <org> Register the runner against one specific GH org.
|
|
17
|
-
// start
|
|
18
|
-
//
|
|
19
|
-
//
|
|
17
|
+
// start The one command: installs a bare box, refreshes a stale
|
|
18
|
+
// actions/runner download in place, registers any admin
|
|
19
|
+
// org the box does not serve yet, then brings EVERY
|
|
20
|
+
// registered org online, detached, in Startup-shortcut
|
|
21
|
+
// order. An org already alive is named and skipped; the
|
|
22
|
+
// terminal is never taken over.
|
|
20
23
|
// restart stop, wait for every listener to go, then start.
|
|
21
24
|
// stop Kill every Runner.Listener.exe under RUNNER_HOME.
|
|
22
25
|
// status Registered orgs, Startup shortcuts, live listeners.
|
|
23
26
|
// uninstall Remove everything — legacy services and tasks, and the
|
|
24
27
|
// electron-manager era's em-runner install, included.
|
|
25
|
-
// self-update Force an immediate self-update of @omega.js/desktop (npm i -g @omega.js/desktop@latest).
|
|
26
28
|
// monitor Tail the JSONL signing event log, pretty-printed.
|
|
27
29
|
//
|
|
28
|
-
// Every subcommand except `
|
|
30
|
+
// Every subcommand except `monitor` refuses on non-Windows
|
|
29
31
|
// (set OMEGA_RUNNER_FORCE=1 to override — testing only).
|
|
30
32
|
|
|
31
33
|
const path = require('path');
|
|
@@ -35,7 +37,6 @@ const jetpack = require('fs-jetpack');
|
|
|
35
37
|
|
|
36
38
|
const Manager = new (require('../build.js'));
|
|
37
39
|
const logger = Manager.logger('runner');
|
|
38
|
-
const { safeInstall } = require('../utils/safe-install');
|
|
39
40
|
|
|
40
41
|
const RUNNER_LABELS = ['self-hosted', 'windows', 'ev-token'];
|
|
41
42
|
|
|
@@ -57,6 +58,7 @@ function ghRunnerName(org) {
|
|
|
57
58
|
// — is `<home>\.env`, read here before anything looks at process.env, so every
|
|
58
59
|
// subcommand works from any directory (utils/runner-env.js).
|
|
59
60
|
const { defaultRunnerHome, runnerEnvFile, runnerLogFile, loadRunnerEnv, ensureRunnerConfig, reconfigureRunnerEnv, runnerEnvReport, parseRunnerOrgs, sameRunnerOrgs, isTestRun, isScratchRunnerHome, assertTestSafeRunnerHome, runnerPrivateHome, ensureRunnerPrivateHome, ensureRunnerDirEnv } = require('../utils/runner-env.js');
|
|
61
|
+
const { ensureRunnerJobGuard, jobGuardListFiles } = require('../utils/runner-job-guard.js');
|
|
60
62
|
const attachLogFile = require('../utils/attach-log-file.js');
|
|
61
63
|
const RUNNER_HOME = process.env.OMEGA_RUNNER_HOME || defaultRunnerHome();
|
|
62
64
|
loadRunnerEnv({ home: RUNNER_HOME });
|
|
@@ -102,8 +104,8 @@ function orgRunnerDir(org, home) {
|
|
|
102
104
|
}
|
|
103
105
|
const ACTIONS_RUNNER_VERSION = '2.319.1'; // pinned; bump intentionally
|
|
104
106
|
|
|
105
|
-
// The subcommands, and the
|
|
106
|
-
//
|
|
107
|
+
// The subcommands, and the one of them that runs on any platform: monitor only
|
|
108
|
+
// reads a log file. Every other one is the box's.
|
|
107
109
|
const SUBCOMMANDS = {
|
|
108
110
|
'install': install,
|
|
109
111
|
'config': configureRunner,
|
|
@@ -113,17 +115,16 @@ const SUBCOMMANDS = {
|
|
|
113
115
|
'stop': stopServices,
|
|
114
116
|
'status': statusServices,
|
|
115
117
|
'uninstall': uninstall,
|
|
116
|
-
'self-update': selfUpdate,
|
|
117
118
|
'monitor': monitor,
|
|
118
119
|
};
|
|
119
|
-
const ANY_PLATFORM_SUBCOMMANDS = new Set(['
|
|
120
|
+
const ANY_PLATFORM_SUBCOMMANDS = new Set(['monitor']);
|
|
120
121
|
|
|
121
122
|
// The ones that CHANGE the machine: they register, deregister, download, delete,
|
|
122
|
-
// kill listeners, rewrite the box's own configuration
|
|
123
|
-
//
|
|
123
|
+
// kill listeners, or rewrite the box's own configuration. A test process may
|
|
124
|
+
// only point these at a scratch home
|
|
124
125
|
// ([#337](https://github.com/Omega-JS-Stack/omega/issues/337) — the suite once
|
|
125
126
|
// ran a real install against the box). `status` and `monitor` only read.
|
|
126
|
-
const MUTATING_SUBCOMMANDS = new Set(['install', 'config', 'register-org', 'start', 'restart', 'stop', 'uninstall'
|
|
127
|
+
const MUTATING_SUBCOMMANDS = new Set(['install', 'config', 'register-org', 'start', 'restart', 'stop', 'uninstall']);
|
|
127
128
|
|
|
128
129
|
module.exports = async function (options) {
|
|
129
130
|
options = options || {};
|
|
@@ -260,7 +261,7 @@ async function install(options) {
|
|
|
260
261
|
// admin orgs on a tick ran as NT AUTHORITY\NETWORK SERVICE in Session 0, so
|
|
261
262
|
// the runners it spawned could not see the user's cert store and the Startup
|
|
262
263
|
// shortcuts it wrote landed in the wrong profile. Adding a new org is a
|
|
263
|
-
// `
|
|
264
|
+
// `npx omega runner start` away; uninstall() still tears down any leftover
|
|
264
265
|
// watcher service from an older install.
|
|
265
266
|
|
|
266
267
|
// 5. Save install metadata.
|
|
@@ -303,7 +304,7 @@ async function install(options) {
|
|
|
303
304
|
logger.log('');
|
|
304
305
|
logger.log(`Bringing every registered runner (${succeeded.length}) online in the background. 'npx omega runner status' shows them, 'npx omega runner monitor' tails the log.`);
|
|
305
306
|
logger.log('');
|
|
306
|
-
await startServices({ ...options, _home: home });
|
|
307
|
+
await startServices({ ...options, _home: home, _reconcileDone: true });
|
|
307
308
|
}
|
|
308
309
|
}
|
|
309
310
|
|
|
@@ -415,7 +416,7 @@ async function registerOrg(options) {
|
|
|
415
416
|
const runnerDir = orgRunnerDir(org, home);
|
|
416
417
|
const templateDir = options._templateDir || path.join(home, '_template');
|
|
417
418
|
if (!jetpack.exists(path.join(templateDir, 'config.cmd'))) {
|
|
418
|
-
throw new Error(`actions/runner template not found at ${templateDir}. Run 'npx omega runner
|
|
419
|
+
throw new Error(`actions/runner template not found at ${templateDir}. Run 'npx omega runner start' first.`);
|
|
419
420
|
}
|
|
420
421
|
if (jetpack.exists(runnerDir)) {
|
|
421
422
|
logger.log(` Removing stale actions-runner-${org.toLowerCase()}/ before re-clone…`);
|
|
@@ -480,9 +481,27 @@ async function registerOrg(options) {
|
|
|
480
481
|
// runner's `<runner dir>\.env`, which the listener reads at startup and
|
|
481
482
|
// applies to every job, so the detached spawn and the Startup shortcut both
|
|
482
483
|
// get it from one write.
|
|
484
|
+
//
|
|
485
|
+
// The job guard travels the same way
|
|
486
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): the hook the
|
|
487
|
+
// listener runs before a job's first step, refusing anything that is not a
|
|
488
|
+
// dispatch from a listed repo by a listed actor. The actor list starts as the
|
|
489
|
+
// `GH_TOKEN` user, which is this box owner's account and the account a
|
|
490
|
+
// `workflow_dispatch` from the deploy token carries (Ian 2026-09-13); a
|
|
491
|
+
// lookup that does not answer leaves the file for the operator rather than
|
|
492
|
+
// failing a registration over it.
|
|
483
493
|
const privateHome = ensureRunnerPrivateHome(home, { logger });
|
|
484
|
-
|
|
494
|
+
let actor;
|
|
495
|
+
try {
|
|
496
|
+
const { data } = await octokit.rest.users.getAuthenticated();
|
|
497
|
+
actor = data.login;
|
|
498
|
+
} catch (e) {
|
|
499
|
+
logger.warn(` Could not read the GH_TOKEN user for the job guard's actor list: ${e.message}`);
|
|
500
|
+
}
|
|
501
|
+
const guard = ensureRunnerJobGuard(home, { orgs: [org], actor, logger });
|
|
502
|
+
ensureRunnerDirEnv(runnerDir, { HOME: privateHome.home, ACTIONS_RUNNER_HOOK_JOB_STARTED: guard.hook });
|
|
485
503
|
logger.log(` HOME for ${org}: ${privateHome.home}`);
|
|
504
|
+
logger.log(` Job guard for ${org}: ${guard.hook}`);
|
|
486
505
|
|
|
487
506
|
// Write the .cmd shortcut in the user's Startup folder so Explorer auto-runs
|
|
488
507
|
// it at every interactive logon (Session 1). No Task Scheduler, no admin
|
|
@@ -509,7 +528,8 @@ async function registerOrg(options) {
|
|
|
509
528
|
// What `start` settles before it touches a listener: the box's required keys —
|
|
510
529
|
// asked in a terminal and refused without one, exactly like install — and then
|
|
511
530
|
// the orgs the .env names against the orgs this install actually registered.
|
|
512
|
-
// start
|
|
531
|
+
// start only ever ADDS a named admin org (reconcileRunnerInstall); reshaping the
|
|
532
|
+
// box to the list is install's, so the mismatch names it.
|
|
513
533
|
async function startPreflight(options) {
|
|
514
534
|
const { home, env = process.env, logger: log = logger, prompt, interactive } = options || {};
|
|
515
535
|
await ensureRunnerConfig({ home, env, logger: log, prompt, interactive });
|
|
@@ -518,16 +538,27 @@ async function startPreflight(options) {
|
|
|
518
538
|
// an install that predates it, or a runner dir whose `.env` was replaced, has
|
|
519
539
|
// no HOME line, and the job it picks up then dies inside `actions/checkout`.
|
|
520
540
|
// Every registered dir gets it here, before a single listener comes up.
|
|
541
|
+
//
|
|
542
|
+
// And the job guard with it
|
|
543
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): a box that
|
|
544
|
+
// installed before the guard existed, or a runner dir whose `.env` lost the
|
|
545
|
+
// line, would otherwise come online signing for anything. The hook script is
|
|
546
|
+
// rewritten from this package, so a framework update reaches the box on the
|
|
547
|
+
// next start; the allow lists are the operator's and are only appended to,
|
|
548
|
+
// and this path asks GitHub nothing, so `start` still works offline.
|
|
521
549
|
const privateHome = ensureRunnerPrivateHome(home, { logger: log });
|
|
522
|
-
|
|
523
|
-
|
|
550
|
+
const dirs = listOrgRunnerDirs(home);
|
|
551
|
+
const guard = ensureRunnerJobGuard(home, { orgs: dirs.map(({ org }) => org), logger: log });
|
|
552
|
+
for (const { org, dir } of dirs) {
|
|
553
|
+
ensureRunnerDirEnv(dir, { HOME: privateHome.home, ACTIONS_RUNNER_HOOK_JOB_STARTED: guard.hook });
|
|
524
554
|
log.log(`HOME for ${org}: ${privateHome.home}`);
|
|
555
|
+
log.log(`Job guard for ${org}: ${guard.hook}`);
|
|
525
556
|
}
|
|
526
557
|
|
|
527
558
|
const named = parseRunnerOrgs(env.OMEGA_RUNNER_ORGS);
|
|
528
559
|
const registered = readConfig(home).registeredOrgs || [];
|
|
529
560
|
if (named.length > 0 && !sameRunnerOrgs(named, registered)) {
|
|
530
|
-
log.warn(`OMEGA_RUNNER_ORGS names ${named.join(', ')} but this install registered ${registered.join(', ') || '(none)'}.
|
|
561
|
+
log.warn(`OMEGA_RUNNER_ORGS names ${named.join(', ')} but this install registered ${registered.join(', ') || '(none)'}. \`start\` registers a named admin org it does not serve yet and keeps the rest; \`npx omega runner install\` reshapes the box to the list.`);
|
|
531
562
|
}
|
|
532
563
|
}
|
|
533
564
|
|
|
@@ -544,6 +575,92 @@ function runnerStartupTargets(home) {
|
|
|
544
575
|
});
|
|
545
576
|
}
|
|
546
577
|
|
|
578
|
+
// What `start` settles between the preflight and the spawns
|
|
579
|
+
// ([#937](https://github.com/Omega-JS-Stack/omega/issues/937)), so a box never
|
|
580
|
+
// needs a second verb to catch up:
|
|
581
|
+
// 1. a stale actions/runner download is refreshed IN PLACE: the template is
|
|
582
|
+
// re-downloaded and laid over each org dir whose listener is down. The
|
|
583
|
+
// registration (`.runner`, `.credentials`, `.env`) is never in the
|
|
584
|
+
// template, so it survives the copy. A live listener holds its binaries
|
|
585
|
+
// open, so that org is skipped and named with `restart`, and the new
|
|
586
|
+
// version is recorded only once every org dir took it. No teardown. A
|
|
587
|
+
// download or a copy that fails is one warn and a skipped refresh, never
|
|
588
|
+
// a failed start: the next start tries again.
|
|
589
|
+
// 2. an admin org the box does not serve yet (OMEGA_RUNNER_ORGS honoured) is
|
|
590
|
+
// registered, Startup shortcut and all. The only step that needs GitHub,
|
|
591
|
+
// so discovery that fails is one line and the box still comes online.
|
|
592
|
+
// GH_TOKEN is never missing here: it is a required key, and the preflight
|
|
593
|
+
// refuses a box without one. Orgs registered outside the filter stay;
|
|
594
|
+
// reshaping the box to the list is install's.
|
|
595
|
+
//
|
|
596
|
+
// `_download`, `_discoverOrgs` and `_registerOrg` are the tests' seams, the way
|
|
597
|
+
// `_spawn` is. Registration is not home-scoped (it acts on GitHub with the real
|
|
598
|
+
// token, whatever scratch home a case made), so a test run that has not
|
|
599
|
+
// injected both GitHub seams skips the org check instead of reaching it.
|
|
600
|
+
async function reconcileRunnerInstall(options) {
|
|
601
|
+
const home = options._home;
|
|
602
|
+
const env = options._env;
|
|
603
|
+
const log = options._logger;
|
|
604
|
+
const listen = options._listeners;
|
|
605
|
+
const download = options._download || downloadActionsRunner;
|
|
606
|
+
const templateDir = path.join(home, '_template');
|
|
607
|
+
|
|
608
|
+
const installed = readConfig(home).actionsRunnerVersion;
|
|
609
|
+
if (installed !== ACTIONS_RUNNER_VERSION) {
|
|
610
|
+
log.log(`actions/runner ${installed || '(unrecorded)'} is installed and ${ACTIONS_RUNNER_VERSION} is pinned: refreshing in place.`);
|
|
611
|
+
let downloaded = true;
|
|
612
|
+
try {
|
|
613
|
+
await download(templateDir, home);
|
|
614
|
+
} catch (e) {
|
|
615
|
+
log.warn(`✗ actions/runner ${ACTIONS_RUNNER_VERSION} download failed (${e.message}): refresh skipped until the next start.`);
|
|
616
|
+
downloaded = false;
|
|
617
|
+
}
|
|
618
|
+
if (downloaded) {
|
|
619
|
+
let skipped = 0;
|
|
620
|
+
for (const { org, dir } of listOrgRunnerDirs(home)) {
|
|
621
|
+
if (listen(dir).length > 0) {
|
|
622
|
+
log.warn(`· ${org} is running, so its actions/runner files are locked and were not refreshed. Run \`npx omega runner restart\` to refresh it.`);
|
|
623
|
+
skipped++;
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
try {
|
|
627
|
+
jetpack.copy(templateDir, dir, { overwrite: true });
|
|
628
|
+
log.log(`✓ ${org} refreshed to actions/runner ${ACTIONS_RUNNER_VERSION}`);
|
|
629
|
+
} catch (e) {
|
|
630
|
+
log.warn(`✗ ${org} was not refreshed (${e.message}): the next start tries again.`);
|
|
631
|
+
skipped++;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (skipped === 0) saveConfig({ actionsRunnerVersion: ACTIONS_RUNNER_VERSION }, home);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (isTestRun() && !(options._discoverOrgs && options._registerOrg)) {
|
|
639
|
+
log.log('Org check skipped: a test run never asks GitHub unless both _discoverOrgs and _registerOrg are injected.');
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
const discover = options._discoverOrgs || discoverAdminOrgs;
|
|
643
|
+
const register = options._registerOrg || registerOrg;
|
|
644
|
+
let adminOrgs;
|
|
645
|
+
try {
|
|
646
|
+
adminOrgs = await discover();
|
|
647
|
+
} catch (e) {
|
|
648
|
+
log.warn(`Org check skipped: could not list your admin orgs (${e.message}).`);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const { orgs } = selectRunnerOrgs(adminOrgs, env.OMEGA_RUNNER_ORGS);
|
|
652
|
+
const served = new Set((readConfig(home).registeredOrgs || []).map((org) => org.toLowerCase()));
|
|
653
|
+
for (const org of orgs.filter((o) => !served.has(o.toLowerCase()))) {
|
|
654
|
+
log.log(`Registering ${org}: an admin org this box does not serve yet.`);
|
|
655
|
+
try {
|
|
656
|
+
await register({ ...options, _: ['runner', 'register-org', org], _templateDir: templateDir });
|
|
657
|
+
} catch (e) {
|
|
658
|
+
log.warn(`✗ register ${org}: ${e.message}`);
|
|
659
|
+
process.exitCode = 1;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
547
664
|
// Every registered org, brought online detached, in Startup-shortcut order.
|
|
548
665
|
//
|
|
549
666
|
// A box registers one runner per org, and `start` used to bring up exactly ONE
|
|
@@ -559,7 +676,15 @@ function runnerStartupTargets(home) {
|
|
|
559
676
|
// `_spawn` and `_listeners` are injected by the tests, the same way `_home` and
|
|
560
677
|
// `_logger` are: neither cmd.exe nor the process scan exists off Windows.
|
|
561
678
|
// `_preflightDone` is `restart`'s: it settles the box config BEFORE it kills
|
|
562
|
-
// anything, so the walk must not run a second time here.
|
|
679
|
+
// anything, so the walk must not run a second time here. The reconcile is NOT
|
|
680
|
+
// gated on it: after restart's stop is exactly when nothing is locked.
|
|
681
|
+
// `_reconcileDone` is install's alone: it just downloaded and registered, so the
|
|
682
|
+
// reconcile is skipped there.
|
|
683
|
+
//
|
|
684
|
+
// A bare box (no template to clone from) is handed to install, `_install` in
|
|
685
|
+
// the tests, which ends by calling this function again with the template in
|
|
686
|
+
// place. A test run without `_install` refuses: the real install downloads,
|
|
687
|
+
// discovers and registers against GitHub, and no scratch home scopes that.
|
|
563
688
|
async function startServices(options) {
|
|
564
689
|
options = options || {};
|
|
565
690
|
ensureWindows();
|
|
@@ -567,8 +692,23 @@ async function startServices(options) {
|
|
|
567
692
|
const log = options._logger || logger;
|
|
568
693
|
const spawnIt = options._spawn || spawnRunnerDetached;
|
|
569
694
|
const listen = options._listeners || listRunnerListenerProcessesUnder;
|
|
695
|
+
if (!jetpack.exists(path.join(home, '_template', 'config.cmd'))) {
|
|
696
|
+
if (isTestRun() && !options._install) {
|
|
697
|
+
throw new Error(
|
|
698
|
+
`Refusing to install onto the bare runner home ${home}: this is a test run `
|
|
699
|
+
+ '(OMEGA_TEST_RUNNER / OMEGA_TEST_MODE) and the call did not inject `_install`. The real install '
|
|
700
|
+
+ 'downloads actions/runner and registers every admin org against GitHub with GH_TOKEN.',
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
log.log(`No runner install under ${home}: running the full install.`);
|
|
704
|
+
return (options._install || install)(options);
|
|
705
|
+
}
|
|
706
|
+
const env = options._env || process.env;
|
|
570
707
|
if (!options._preflightDone) {
|
|
571
|
-
await startPreflight({ home, env
|
|
708
|
+
await startPreflight({ home, env, logger: log, prompt: options._prompt, interactive: options._interactive });
|
|
709
|
+
}
|
|
710
|
+
if (!options._reconcileDone) {
|
|
711
|
+
await reconcileRunnerInstall({ ...options, _home: home, _env: env, _logger: log, _listeners: listen });
|
|
572
712
|
}
|
|
573
713
|
const targets = runnerStartupTargets(home);
|
|
574
714
|
if (targets.length === 0) {
|
|
@@ -732,7 +872,7 @@ async function statusServices(options) {
|
|
|
732
872
|
logger.log('');
|
|
733
873
|
const report = orgRunnerReport({ home });
|
|
734
874
|
if (report.length === 0) {
|
|
735
|
-
logger.warn('No orgs registered. Run `npx omega runner
|
|
875
|
+
logger.warn('No orgs registered. Run `npx omega runner start`.');
|
|
736
876
|
} else {
|
|
737
877
|
logger.log(`Per-org runner state (${report.length}):`);
|
|
738
878
|
for (const { state, lines } of report) {
|
|
@@ -966,7 +1106,13 @@ async function removeRunnerHomeWithRetry(keepDirs, home) {
|
|
|
966
1106
|
// open by the tee while the removal runs.
|
|
967
1107
|
const envFile = runnerEnvFile(root);
|
|
968
1108
|
const logsDir = path.dirname(runnerLogFile(root));
|
|
969
|
-
|
|
1109
|
+
// The job guard's two allow lists are configuration too
|
|
1110
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): a list an
|
|
1111
|
+
// operator narrowed by hand outlives an uninstall exactly as the `.env` does.
|
|
1112
|
+
// The hook SCRIPT is install state and goes with the rest; the next install
|
|
1113
|
+
// writes it back from the package.
|
|
1114
|
+
const guardLists = jobGuardListFiles(root);
|
|
1115
|
+
const keep = new Set([...(keepDirs || []), envFile, logsDir, ...guardLists]);
|
|
970
1116
|
const targets = (jetpack.list(root) || [])
|
|
971
1117
|
.map((name) => path.join(root, name))
|
|
972
1118
|
.filter((entry) => !keep.has(entry));
|
|
@@ -974,7 +1120,8 @@ async function removeRunnerHomeWithRetry(keepDirs, home) {
|
|
|
974
1120
|
// Nothing kept survives on disk: the home itself goes too.
|
|
975
1121
|
const kept = [...(keepDirs || [])].length > 0
|
|
976
1122
|
|| jetpack.exists(envFile) === 'file'
|
|
977
|
-
|| jetpack.exists(logsDir) === 'dir'
|
|
1123
|
+
|| jetpack.exists(logsDir) === 'dir'
|
|
1124
|
+
|| guardLists.some((file) => jetpack.exists(file) === 'file');
|
|
978
1125
|
if (!kept) targets.push(root);
|
|
979
1126
|
|
|
980
1127
|
for (const target of targets) {
|
|
@@ -1124,19 +1271,6 @@ function identifyHandleHolders(targetPath) {
|
|
|
1124
1271
|
}
|
|
1125
1272
|
}
|
|
1126
1273
|
|
|
1127
|
-
// ─── self-update ────────────────────────────────────────────────────────────────
|
|
1128
|
-
async function selfUpdate() {
|
|
1129
|
-
const { execute } = require('node-powertools');
|
|
1130
|
-
logger.log('Updating @omega.js/desktop to latest…');
|
|
1131
|
-
try {
|
|
1132
|
-
const out = await safeInstall('npm i -g @omega.js/desktop@latest');
|
|
1133
|
-
logger.log(out);
|
|
1134
|
-
logger.log('✓ @omega.js/desktop updated.');
|
|
1135
|
-
} catch (e) {
|
|
1136
|
-
logger.warn(`Self-update failed: ${e.message}`);
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
1274
|
// ─── helpers ────────────────────────────────────────────────────────────────────
|
|
1141
1275
|
|
|
1142
1276
|
const WATCHER_SERVICE_NAME = 'omega-runner-watcher';
|
|
@@ -1534,8 +1668,8 @@ function listLegacyRunnerStartupShortcuts(startupDir) {
|
|
|
1534
1668
|
// wrapper that blocks for the lifetime of the listener with cwd = runnerDir;
|
|
1535
1669
|
// a long-lived cmd.exe holding cwd inside RUNNER_HOME blocks every later
|
|
1536
1670
|
// uninstall with EPERM. Bypassing run.cmd loses its self-update relaunch
|
|
1537
|
-
// path, but `
|
|
1538
|
-
//
|
|
1671
|
+
// path, but `npx omega runner start` refreshing the runner binary in place
|
|
1672
|
+
// is the update mechanism in @omega.js/desktop anyway.
|
|
1539
1673
|
//
|
|
1540
1674
|
// Detached + windowsHide + ignored stdio = no console window flashes during
|
|
1541
1675
|
// install and the listener survives the install command's exit. UAC-
|
|
@@ -1696,7 +1830,7 @@ async function monitor(options) {
|
|
|
1696
1830
|
// exactly which orgs the monitor will pick up signing events from.
|
|
1697
1831
|
const report = orgRunnerReport({ home });
|
|
1698
1832
|
if (report.length === 0) {
|
|
1699
|
-
logger.log('(no orgs registered yet
|
|
1833
|
+
logger.log('(no orgs registered yet: run `npx omega runner start` first)');
|
|
1700
1834
|
} else {
|
|
1701
1835
|
logger.log(`Monitoring signing requests across ${report.length} org(s):`);
|
|
1702
1836
|
for (const { state, lines } of report) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Strategy-aware Windows code signer.
|
|
2
2
|
//
|
|
3
|
-
// Reads strategy from config platforms.
|
|
3
|
+
// Reads strategy from config platforms.windows.signing.strategy:
|
|
4
4
|
// self-hosted — sign with signtool against an EV USB token (typically on a self-hosted runner)
|
|
5
5
|
// cloud — shell out to a cloud signing provider's CLI (Azure / SSL.com / DigiCert)
|
|
6
6
|
// local — no-op (developer signs manually on their own Windows box)
|
|
@@ -33,6 +33,8 @@ runnerEnv.loadRunnerEnv();
|
|
|
33
33
|
const attachLogFile = require('../utils/attach-log-file.js');
|
|
34
34
|
|
|
35
35
|
const { startAutoUnlock } = require('../lib/sign-helpers/auto-unlock.js');
|
|
36
|
+
const { assertConsoleUnlocked } = require('../lib/sign-helpers/console-lock.js');
|
|
37
|
+
const { execWithLimit } = require('../lib/sign-helpers/exec-with-limit.js');
|
|
36
38
|
const { writeUpdateInfo } = require('../lib/sign-helpers/update-info.js');
|
|
37
39
|
const signEvents = require('../lib/sign-helpers/sign-events.js');
|
|
38
40
|
|
|
@@ -140,9 +142,9 @@ async function runSignCommand(options) {
|
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
if (strategy === 'cloud') {
|
|
143
|
-
const provider = config.platforms?.
|
|
145
|
+
const provider = config.platforms?.windows?.signing?.cloud?.provider;
|
|
144
146
|
if (!provider) {
|
|
145
|
-
throw new Error('strategy=cloud but no provider set (config platforms.
|
|
147
|
+
throw new Error('strategy=cloud but no provider set (config platforms.windows.signing.cloud.provider).');
|
|
146
148
|
}
|
|
147
149
|
await signWithCloudProvider(provider, targets, inDir, outDir);
|
|
148
150
|
return;
|
|
@@ -261,9 +263,17 @@ function buildVerifyCommand({ signtool, outPath }) {
|
|
|
261
263
|
const SIGN_ATTEMPTS = 3;
|
|
262
264
|
const SIGN_RETRY_DELAY_MS = 5000;
|
|
263
265
|
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
266
|
+
// A healthy sign takes ~18s (the timestamp round trip is most of it). One that
|
|
267
|
+
// is still running minutes later is waiting on something that will never come:
|
|
268
|
+
// a PIN typed at a locked console, a dialog nobody can see. Every attempt gets
|
|
269
|
+
// this hard limit, after which the signtool process tree is terminated and the
|
|
270
|
+
// attempt fails with a message that says so, instead of holding the job until
|
|
271
|
+
// GitHub's six-hour default cancels it ([#864](https://github.com/Omega-JS-Stack/omega/issues/864)).
|
|
272
|
+
const SIGN_TIME_LIMIT_MS = 3 * 60 * 1000;
|
|
273
|
+
|
|
274
|
+
// node-powertools' `execute` with `log: false` — what execWithLimit passes —
|
|
275
|
+
// rejects with `new Error(stderr || 'Command failed with exit code N')`, and the
|
|
276
|
+
// sign command ends in `2>&1` (it runs through a shell), so BOTH of signtool's
|
|
267
277
|
// streams reach `e.message` and this is classifying on signtool's own words.
|
|
268
278
|
//
|
|
269
279
|
// Failures signtool NAMES as permanent. Retrying a wrong PIN walks the EV token
|
|
@@ -298,7 +308,7 @@ async function signWithRetry(cmd, options) {
|
|
|
298
308
|
file,
|
|
299
309
|
attempts = SIGN_ATTEMPTS,
|
|
300
310
|
delayMs = SIGN_RETRY_DELAY_MS,
|
|
301
|
-
exec = (c) =>
|
|
311
|
+
exec = (c) => execWithLimit(c, { limitMs: SIGN_TIME_LIMIT_MS, label: 'signtool' }),
|
|
302
312
|
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
303
313
|
emit = signEvents.emit,
|
|
304
314
|
startUnlock = () => ({ stop: () => {} }),
|
|
@@ -334,7 +344,17 @@ async function signWithRetry(cmd, options) {
|
|
|
334
344
|
throw new Error(`signWithRetry exhausted ${attempts} attempts without a verdict`);
|
|
335
345
|
}
|
|
336
346
|
|
|
337
|
-
|
|
347
|
+
// The signing loop. Both of its shell-outs and every line it prints sit behind
|
|
348
|
+
// one seam (`deps.exec` runs signtool, `deps.logger` prints), so the ORDER that
|
|
349
|
+
// makes the proof line true (sign, verify, THEN the line) is provable without a
|
|
350
|
+
// Windows box. Production passes neither: the real signtool and the real logger
|
|
351
|
+
// are the defaults, and the deliberate end-to-end sign is sign-windows-e2e.
|
|
352
|
+
async function signWithSigntool(targets, inDir, outDir, deps) {
|
|
353
|
+
deps = deps || {};
|
|
354
|
+
const exec = deps.exec;
|
|
355
|
+
const runVerify = exec || ((command) => execute(command, { log: false }));
|
|
356
|
+
const log = deps.logger || logger;
|
|
357
|
+
|
|
338
358
|
const projectRoot = process.cwd();
|
|
339
359
|
const { tokenRef, password, useThumbprint, signtool, timestampUrl } = resolveSigntoolEnv();
|
|
340
360
|
|
|
@@ -343,6 +363,11 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
343
363
|
// update mechanism (not electron-updater) and don't need a yml.
|
|
344
364
|
const signedExes = [];
|
|
345
365
|
|
|
366
|
+
// The PIN is typed into the Token Logon dialog on the interactive desktop.
|
|
367
|
+
// Behind a lock screen it never arrives and signtool waits forever, so a
|
|
368
|
+
// locked console is refused before the first call (console-lock.js).
|
|
369
|
+
if (useThumbprint && password) await assertConsoleUnlocked();
|
|
370
|
+
|
|
346
371
|
for (const target of targets) {
|
|
347
372
|
const rel = path.relative(inDir, target);
|
|
348
373
|
const outPath = path.join(outDir, rel);
|
|
@@ -353,7 +378,7 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
353
378
|
|
|
354
379
|
const cmd = buildSignCommand({ signtool, tokenRef, password, timestampUrl, outPath });
|
|
355
380
|
|
|
356
|
-
|
|
381
|
+
log.log(`Signing ${path.relative(projectRoot, outPath)}${useThumbprint ? ' (thumbprint mode)' : ''}...`);
|
|
357
382
|
|
|
358
383
|
const fileBytes = (() => { try { return fs.statSync(outPath).size; } catch (_) { return null; } })();
|
|
359
384
|
signEvents.emit('sign-start', {
|
|
@@ -370,6 +395,7 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
370
395
|
try {
|
|
371
396
|
await signWithRetry(cmd, {
|
|
372
397
|
file: path.basename(outPath),
|
|
398
|
+
exec,
|
|
373
399
|
startUnlock: () => (useThumbprint ? startAutoUnlock({ password, logger }) : { stop: () => {} }),
|
|
374
400
|
});
|
|
375
401
|
} catch (e) {
|
|
@@ -385,7 +411,7 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
385
411
|
// Verify is a local check with no third party in it — one shot.
|
|
386
412
|
const verifyCmd = buildVerifyCommand({ signtool, outPath });
|
|
387
413
|
try {
|
|
388
|
-
await
|
|
414
|
+
await runVerify(verifyCmd);
|
|
389
415
|
} catch (e) {
|
|
390
416
|
signEvents.emit('sign-fail', {
|
|
391
417
|
file: path.basename(outPath),
|
|
@@ -399,7 +425,11 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
399
425
|
file: path.basename(outPath),
|
|
400
426
|
duration_ms: Date.now() - fileStart,
|
|
401
427
|
});
|
|
402
|
-
|
|
428
|
+
// The proof line, in the mac lane's shape (hooks/notarize.js): the verify
|
|
429
|
+
// above aborts the job on a failure, so this line names the check that ran
|
|
430
|
+
// rather than claiming a signature nobody checked
|
|
431
|
+
// ([#918](https://github.com/Omega-JS-Stack/omega/issues/918)).
|
|
432
|
+
log.log(`Signed and verified: signtool verify /pa accepts ${path.basename(outPath)}.`);
|
|
403
433
|
|
|
404
434
|
if (outPath.toLowerCase().endsWith('.exe')) {
|
|
405
435
|
signedExes.push({ filePath: outPath, urlName: path.basename(outPath) });
|
|
@@ -414,9 +444,9 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
414
444
|
const pkg = Manager.getPackage('project') || {};
|
|
415
445
|
const version = pkg.version;
|
|
416
446
|
if (!version) {
|
|
417
|
-
|
|
447
|
+
log.warn('Could not determine version from package.json; skipping latest.yml generation.');
|
|
418
448
|
} else {
|
|
419
|
-
|
|
449
|
+
log.log(`Generating Windows auto-updater feed (latest.yml) for ${signedExes.length} installer(s)...`);
|
|
420
450
|
try {
|
|
421
451
|
await writeUpdateInfo({
|
|
422
452
|
signedExes,
|
|
@@ -428,8 +458,8 @@ async function signWithSigntool(targets, inDir, outDir) {
|
|
|
428
458
|
// Don't fail the whole sign step if yml generation hits something unexpected —
|
|
429
459
|
// the signed exe is still valid + uploadable. But this IS a real problem
|
|
430
460
|
// because auto-updates won't work, so log loudly.
|
|
431
|
-
|
|
432
|
-
|
|
461
|
+
log.error(`latest.yml generation failed: ${e.message}`);
|
|
462
|
+
log.error(' Signed binary is OK but Windows auto-updater will not see this release.');
|
|
433
463
|
}
|
|
434
464
|
}
|
|
435
465
|
}
|
|
@@ -554,6 +584,7 @@ module.exports.signWithRetry = signWithRetry;
|
|
|
554
584
|
module.exports.isTransientSignFailure = isTransientSignFailure;
|
|
555
585
|
module.exports.SIGN_ATTEMPTS = SIGN_ATTEMPTS;
|
|
556
586
|
module.exports.SIGN_RETRY_DELAY_MS = SIGN_RETRY_DELAY_MS;
|
|
587
|
+
module.exports.SIGN_TIME_LIMIT_MS = SIGN_TIME_LIMIT_MS;
|
|
557
588
|
|
|
558
589
|
// Exports for the Windows-gated end-to-end suite — the halves that shell out to
|
|
559
590
|
// signtool for real. They only run where signtool and the EV token are
|
package/dist/commands/test.js
CHANGED
|
@@ -13,9 +13,10 @@ module.exports = async function (options) {
|
|
|
13
13
|
// This process is a TEST RUN, and everything it spawns inherits that. The box's
|
|
14
14
|
// mutating verbs read it and refuse to touch a real runner home
|
|
15
15
|
// ([#337](https://github.com/Omega-JS-Stack/omega/issues/337): a suite once ran
|
|
16
|
-
// a real `runner install` on the signing box). Deliberately
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// a real `runner install` on the signing box). Deliberately a marker about THIS
|
|
17
|
+
// process, never a word about the app under test: the environment the thing
|
|
18
|
+
// being tested RUNS in is `OMEGA_ENVIRONMENT`, and the runners name it on their
|
|
19
|
+
// own children alone (#925).
|
|
19
20
|
process.env.OMEGA_TEST_RUNNER = '1';
|
|
20
21
|
|
|
21
22
|
// Tee all test output to <projectRoot>/logs/test.log (ANSI-stripped) — mirrors
|