@andrian.yablonskyy/thub-coordinator 1.0.3 → 1.0.4

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 CHANGED
@@ -33,6 +33,8 @@ The Coordinator loads a plain **JSON** config file (no YAML support). Resolution
33
33
 
34
34
  `sessionSecret` signs the dashboard's session cookie and the HMAC on artifact download links; `clientJoinKey` is the shared secret Clients self-register with — omit or leave `null` to disable auto-registration entirely. Individual `THUB_LISTEN` / `THUB_PUBLIC_URL` / `THUB_DATA_DIR` / `THUB_SESSION_SECRET` / `THUB_CLIENT_JOIN_KEY` env vars override whatever the file set.
35
35
 
36
+ `npm install -g` creates `~/.config/thub/coordinator.json` for you if it doesn't already exist, with a home-anchored `dataDir` and a freshly generated random `sessionSecret` (not the placeholder above) — a re-install never overwrites it or regenerates the secret. Set `publicUrl` and `clientJoinKey` yourself before relying on auto-registration.
37
+
36
38
  ## Running it
37
39
 
38
40
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrian.yablonskyy/thub-coordinator",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "TestHub Coordinator — job queue, resource registry, scheduler, heartbeat monitor, log/artifact store and web dashboard",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -11,6 +11,7 @@
11
11
  "start": "node src/server.js",
12
12
  "dev": "node --watch src/server.js",
13
13
  "test": "node --test test/*.test.js",
14
+ "postinstall": "node scripts/install-default-config.js",
14
15
  "lint": "eslint .",
15
16
  "lint:fix": "eslint . --fix"
16
17
  },
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @file scripts/install-default-config.js
3
+ * @description npm postinstall: creates ~/.config/thub/coordinator.json on a real global install,
4
+ * if it doesn't already exist, with a freshly generated sessionSecret rather than a
5
+ * shared placeholder — so every real installation isn't using the same known secret
6
+ * for its session cookies and artifact-download HMACs (README §12, §13)
7
+ *
8
+ * @author Andrian Yablonskyy
9
+ * @copyright Copyright (c) 2026 Andrian Yablonskyy. All rights reserved.
10
+ *
11
+ * This file is part of TestHub and is proprietary and confidential.
12
+ * Unauthorized copying, modification, distribution, or use of this file,
13
+ * via any medium, is strictly prohibited without prior written permission
14
+ * from AdSystem.PRO.
15
+ */
16
+
17
+ 'use strict';
18
+
19
+ const fs = require('node:fs'),
20
+ os = require('node:os'),
21
+ path = require('node:path'),
22
+ crypto = require('node:crypto'),
23
+
24
+ CONFIG_PATH = path.join(os.homedir(), '.config', 'thub', 'coordinator.json');
25
+
26
+ // npm only sets this for an actual `npm install -g` — absent for a plain
27
+ // local/workspace install (e.g. this monorepo's own `npm install`).
28
+ function isGlobalInstall(){
29
+ return process.env.npm_config_global === 'true';
30
+ }
31
+
32
+ // Deliberately minimal, not a copy of the bundled config.json (which uses
33
+ // a relative dataDir and a fixed sessionSecret for zero-setup `npm run
34
+ // coordinator` in the monorepo — fine there since it's never a real
35
+ // deployment). loadConfig()'s own DEFAULTS already cover everything else
36
+ // (listen, publicUrl, heartbeat/scheduler/jobs/retention/artifacts), so
37
+ // only what genuinely needs to differ for a real standalone install goes
38
+ // here:
39
+ // - dataDir: home-anchored, not cwd-relative — a real install shouldn't
40
+ // silently get a different data directory depending on which
41
+ // directory you happened to launch thub-coordinator from.
42
+ // - sessionSecret: freshly random per install. The code's own default
43
+ // ("dev-only-change-me") is fine for local dev but would otherwise
44
+ // mean every real installation nobody got around to changing shares
45
+ // the exact same session-signing key.
46
+ // - clientJoinKey stays unset (null, the code's own default) — auto-
47
+ // registration is opt-in, and there's nothing sensible to
48
+ // auto-generate here since it also has to be copied to every Client.
49
+ function defaultContent(){
50
+ return {
51
+ dataDir: path.join(os.homedir(), '.local', 'share', 'thub'),
52
+ sessionSecret: crypto.randomBytes(32).toString('hex')
53
+ };
54
+ }
55
+
56
+ // Best-effort and never fails the `npm install` itself. Never overwrites
57
+ // an existing file — a re-install/upgrade must not clobber whatever the
58
+ // user already configured, and must never regenerate sessionSecret out
59
+ // from under a running deployment (that would invalidate every session).
60
+ function main(){
61
+ if (!isGlobalInstall() || fs.existsSync(CONFIG_PATH)){
62
+ return;
63
+ }
64
+ try {
65
+ fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true });
66
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(defaultContent(), null, 2) + '\n', { mode: 0o600 });
67
+ console.log(`thub-coordinator: created ${CONFIG_PATH} with a freshly generated sessionSecret`);
68
+ }
69
+ catch (err){
70
+ console.warn(`thub-coordinator: could not create ${CONFIG_PATH} automatically (${err.message}).`);
71
+ }
72
+ }
73
+
74
+ main();