@alexberardi/jarvis-admin 0.1.64 → 0.1.66

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 (46) hide show
  1. package/package.json +1 -1
  2. package/public/assets/index-CAv1RM9y.css +1 -0
  3. package/public/assets/index-DBEZIFbZ.js +18 -0
  4. package/public/index.html +2 -2
  5. package/server/dist/app.d.ts.map +1 -1
  6. package/server/dist/app.js +24 -0
  7. package/server/dist/app.js.map +1 -1
  8. package/server/dist/data/image-digests.json +58 -0
  9. package/server/dist/data/service-registry.json +16 -6
  10. package/server/dist/middleware/auth.d.ts +14 -0
  11. package/server/dist/middleware/auth.d.ts.map +1 -1
  12. package/server/dist/middleware/auth.js +19 -0
  13. package/server/dist/middleware/auth.js.map +1 -1
  14. package/server/dist/routes/install.d.ts.map +1 -1
  15. package/server/dist/routes/install.js +29 -8
  16. package/server/dist/routes/install.js.map +1 -1
  17. package/server/dist/routes/setup.d.ts.map +1 -1
  18. package/server/dist/routes/setup.js +2 -1
  19. package/server/dist/routes/setup.js.map +1 -1
  20. package/server/dist/services/generators/compose-generator.d.ts +11 -0
  21. package/server/dist/services/generators/compose-generator.d.ts.map +1 -1
  22. package/server/dist/services/generators/compose-generator.js +137 -29
  23. package/server/dist/services/generators/compose-generator.js.map +1 -1
  24. package/server/dist/services/generators/env-generator.d.ts.map +1 -1
  25. package/server/dist/services/generators/env-generator.js +17 -2
  26. package/server/dist/services/generators/env-generator.js.map +1 -1
  27. package/server/dist/services/generators/secret-generator.d.ts +1 -1
  28. package/server/dist/services/generators/secret-generator.d.ts.map +1 -1
  29. package/server/dist/services/generators/secret-generator.js +15 -0
  30. package/server/dist/services/generators/secret-generator.js.map +1 -1
  31. package/server/dist/services/upgrade/compose-upgrader.d.ts +36 -0
  32. package/server/dist/services/upgrade/compose-upgrader.d.ts.map +1 -1
  33. package/server/dist/services/upgrade/compose-upgrader.js +90 -33
  34. package/server/dist/services/upgrade/compose-upgrader.js.map +1 -1
  35. package/server/dist/services/upgrade/minisign.d.ts +53 -0
  36. package/server/dist/services/upgrade/minisign.d.ts.map +1 -0
  37. package/server/dist/services/upgrade/minisign.js +126 -0
  38. package/server/dist/services/upgrade/minisign.js.map +1 -0
  39. package/server/dist/services/upgrade/self-updater.d.ts.map +1 -1
  40. package/server/dist/services/upgrade/self-updater.js +61 -1
  41. package/server/dist/services/upgrade/self-updater.js.map +1 -1
  42. package/server/dist/types/wizard.d.ts +8 -0
  43. package/server/dist/types/wizard.d.ts.map +1 -1
  44. package/server/src/data/service-registry.json +16 -6
  45. package/public/assets/index-DeByHCh9.css +0 -1
  46. package/public/assets/index-DeCnqmbD.js +0 -18
@@ -10,7 +10,20 @@ import { VERSION } from '../../version.js';
10
10
  import { getComposePath } from '../compose-path.js';
11
11
  import { getHostComposePath } from '../host-paths.js';
12
12
  import registryData from '../../data/service-registry.json' with { type: 'json' };
13
- function loadEnvFile(composePath) {
13
+ /**
14
+ * Set ``key=value`` in a .env string: replace the line in place if the key
15
+ * exists, otherwise append it. Used for operational flags (e.g. the broker lock)
16
+ * that must win over the merge preservation rule.
17
+ */
18
+ function upsertEnvVar(env, key, value) {
19
+ const line = `${key}=${value}`;
20
+ const pattern = new RegExp(`^${key}=.*$`, 'm');
21
+ if (pattern.test(env))
22
+ return env.replace(pattern, line);
23
+ const base = env.endsWith('\n') ? env : env + '\n';
24
+ return base + line + '\n';
25
+ }
26
+ export function loadEnvFile(composePath) {
14
27
  const envFile = join(composePath, '.env');
15
28
  if (!existsSync(envFile))
16
29
  return {};
@@ -26,23 +39,19 @@ function loadEnvFile(composePath) {
26
39
  }
27
40
  return vars;
28
41
  }
29
- export async function upgradeCompose(_app, overrides) {
30
- const composePath = getComposePath();
31
- const registry = parseRegistry(registryData);
32
- // Step 1: Backup
33
- const backupDir = join(composePath, `backup-${VERSION}`);
34
- if (!existsSync(backupDir)) {
35
- mkdirSync(backupDir, { recursive: true });
36
- for (const file of ['docker-compose.yml', '.env', 'init-db.sh']) {
37
- const src = join(composePath, file);
38
- if (existsSync(src)) {
39
- cpSync(src, join(backupDir, file));
40
- }
41
- }
42
- }
43
- // Step 2: Load existing env
44
- const existingEnv = loadEnvFile(composePath);
45
- // Step 3: Reconstruct state, apply overrides from reconcile options
42
+ /**
43
+ * PURE regeneration core: reconstruct the wizard state from an existing install's
44
+ * env and produce the upgraded compose / .env / init-db.sh as STRINGS. Writes
45
+ * nothing. Both the in-place upgrader and the download/CLI path build on this so
46
+ * they can never diverge.
47
+ *
48
+ * Secrets and user config are preserved because they're recovered from
49
+ * ``existingEnv`` (via reconstructWizardState + mergeEnv); named data volumes are
50
+ * matched by Docker on ``up`` since the generator emits stable names, and
51
+ * bind-mount host paths come from env too. A regenerated file is CANONICAL — any
52
+ * hand-edits to the original compose are intentionally not carried over.
53
+ */
54
+ export function buildUpgradedComposeFiles(existingEnv, registry, overrides, hostComposePath) {
46
55
  const state = reconstructWizardState(existingEnv, registry);
47
56
  if (overrides?.enabledModules) {
48
57
  state.enabledModules = overrides.enabledModules;
@@ -56,30 +65,78 @@ export async function upgradeCompose(_app, overrides) {
56
65
  if (overrides?.whisperModelPath) {
57
66
  state.whisperModelPath = overrides.whisperModelPath;
58
67
  }
68
+ if (overrides?.whisperBackend) {
69
+ state.whisperBackend = overrides.whisperBackend;
70
+ }
59
71
  if (overrides?.releaseTrack) {
60
72
  state.releaseTrack = overrides.releaseTrack;
61
73
  }
62
- // When admin runs in docker, fetch the absolute host path of the compose
63
- // dir we were mounted at. env-generator uses it to write MODELS_DIR so
64
- // bind mounts in the regenerated compose resolve on the host (otherwise
65
- // they resolve to /host/compose/.models — a path that exists in the admin
66
- // container but not on the host, so the daemon binds an empty directory).
67
- const hostPath = await getHostComposePath();
68
- if (hostPath) {
69
- state.hostComposePath = hostPath;
74
+ if (hostComposePath) {
75
+ state.hostComposePath = hostComposePath;
70
76
  }
71
- // Step 4: Generate new compose
72
- const newCompose = generateCompose(state, registry);
73
- writeFileSync(join(composePath, 'docker-compose.yml'), newCompose);
74
- // Step 5: Generate new env template, merge
77
+ const compose = generateCompose(state, registry);
75
78
  const newEnvTemplate = generateEnv(state, registry);
76
- const mergedEnv = mergeEnv(existingEnv, newEnvTemplate);
77
- writeFileSync(join(composePath, '.env'), mergedEnv);
78
- // Step 6: Regenerate init-db.sh
79
+ let env = mergeEnv(existingEnv, newEnvTemplate);
80
+ // Broker lock flag is operational, not user config.
81
+ // - An explicit override always wins over mergeEnv's "existing value wins".
82
+ // - A previously-written MQTT_ALLOW_ANON is preserved by mergeEnv, so a lock
83
+ // stays locked (and an open transition stays open) across routine regens.
84
+ // - The fresh-install template now sets MQTT_ALLOW_ANON=false, but an UPGRADE
85
+ // of an install that predates that change (no MQTT_ALLOW_ANON in its .env)
86
+ // must NOT inherit the locked default — its nodes may not have fetched
87
+ // broker creds yet, and locking would drop the whole fleet. Force the
88
+ // transition window (true) in that case; the operator locks explicitly from
89
+ // the admin UI once nodes have migrated.
90
+ if (overrides?.mqttAllowAnon !== undefined) {
91
+ env = upsertEnvVar(env, 'MQTT_ALLOW_ANON', String(overrides.mqttAllowAnon));
92
+ }
93
+ else if (existingEnv['MQTT_ALLOW_ANON'] === undefined) {
94
+ env = upsertEnvVar(env, 'MQTT_ALLOW_ANON', 'true');
95
+ }
79
96
  const enabledServices = getAllEnabledServices(state, registry);
80
97
  const primaryDb = registry.infrastructure.find((i) => i.id === 'postgres')
81
98
  ?.envVars.find((e) => e.name === 'POSTGRES_DB')?.default ?? 'jarvis_config';
82
99
  const initDb = generateInitDbScript(enabledServices, primaryDb);
100
+ return { compose, env, initDb };
101
+ }
102
+ /**
103
+ * Non-destructive regeneration for the "download / hand it to the user" flow:
104
+ * read the existing install's env from ``composePath`` and return the upgraded
105
+ * files as strings WITHOUT touching anything on disk. Used by the compose-mode
106
+ * migrator (installer CLI) and the admin download endpoint.
107
+ */
108
+ export function regenerateComposeFiles(composePath, overrides, hostComposePath) {
109
+ const registry = parseRegistry(registryData);
110
+ const existingEnv = loadEnvFile(composePath);
111
+ return buildUpgradedComposeFiles(existingEnv, registry, overrides, hostComposePath);
112
+ }
113
+ export async function upgradeCompose(_app, overrides) {
114
+ const composePath = getComposePath();
115
+ const registry = parseRegistry(registryData);
116
+ // Step 1: Backup
117
+ const backupDir = join(composePath, `backup-${VERSION}`);
118
+ if (!existsSync(backupDir)) {
119
+ mkdirSync(backupDir, { recursive: true });
120
+ for (const file of ['docker-compose.yml', '.env', 'init-db.sh']) {
121
+ const src = join(composePath, file);
122
+ if (existsSync(src)) {
123
+ cpSync(src, join(backupDir, file));
124
+ }
125
+ }
126
+ }
127
+ // Step 2: Load existing env
128
+ const existingEnv = loadEnvFile(composePath);
129
+ // Step 3-6: Reconstruct + regenerate via the shared pure core.
130
+ //
131
+ // When admin runs in docker, fetch the absolute host path of the compose
132
+ // dir we were mounted at. env-generator uses it to write MODELS_DIR so
133
+ // bind mounts in the regenerated compose resolve on the host (otherwise
134
+ // they resolve to /host/compose/.models — a path that exists in the admin
135
+ // container but not on the host, so the daemon binds an empty directory).
136
+ const hostPath = await getHostComposePath();
137
+ const { compose, env, initDb } = buildUpgradedComposeFiles(existingEnv, registry, overrides, hostPath || undefined);
138
+ writeFileSync(join(composePath, 'docker-compose.yml'), compose);
139
+ writeFileSync(join(composePath, '.env'), env);
83
140
  writeFileSync(join(composePath, 'init-db.sh'), initDb, { mode: 0o755 });
84
141
  }
85
142
  //# sourceMappingURL=compose-upgrader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compose-upgrader.js","sourceRoot":"","sources":["../../../src/services/upgrade/compose-upgrader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compose-upgrader.js","sourceRoot":"","sources":["../../../src/services/upgrade/compose-upgrader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Verify a minisign signature over `artifact` against `publicKeyB64` (the base64
3
+ * line of a minisign public key). Returns true ONLY for a valid signature by
4
+ * that key. Supports minisign's prehashed (BLAKE2b-512) and legacy modes.
5
+ * In-language (Node crypto) — no `minisign` binary dependency.
6
+ */
7
+ export declare function verifyMinisign(publicKeyB64: string, minisigContent: string, artifact: Buffer): boolean;
8
+ /**
9
+ * Parse a `sha256sum`-format checksums file into filename → lowercase-hex-digest.
10
+ * Handles both text (`hash␠␠name`) and binary (`hash␠*name`) lines; ignores any
11
+ * malformed line. Only 64-hex digests are accepted, so a truncated/garbage line
12
+ * can never masquerade as a valid checksum.
13
+ */
14
+ export declare function parseChecksums(content: string): Map<string, string>;
15
+ export type UpdateVerificationInput = {
16
+ /** The trusted minisign public key (base64 line) baked into the client. */
17
+ publicKeyB64: string;
18
+ /** Raw bytes of the release's `checksums.txt`, or null if it couldn't be fetched. */
19
+ checksums: Buffer | null;
20
+ /** Contents of the release's `checksums.txt.minisig`, or null if absent. */
21
+ minisigContent: string | null;
22
+ /** Each downloaded artifact + its bytes, keyed by the filename in checksums.txt. */
23
+ artifacts: {
24
+ filename: string;
25
+ data: Buffer;
26
+ }[];
27
+ /** Operator opt-in (JARVIS_ALLOW_UNSIGNED_UPDATE) to accept an UNSIGNED release. */
28
+ allowUnsigned: boolean;
29
+ };
30
+ export type UpdateVerificationResult = {
31
+ allow: true;
32
+ signed: boolean;
33
+ note?: string;
34
+ } | {
35
+ allow: false;
36
+ reason: string;
37
+ };
38
+ /**
39
+ * The self-update trust policy — pure, so it can be exhaustively tested without
40
+ * touching the network or the filesystem.
41
+ *
42
+ * - No signature material → UNSIGNED. Allowed only if the operator opted in
43
+ * via `allowUnsigned`; we never fabricate trust.
44
+ * - Signature present but invalid for our key → refuse. This is a tampering /
45
+ * wrong-signer signal and is **not** overridable by `allowUnsigned` (the
46
+ * escape hatch covers "no signature", never "bad signature").
47
+ * - Signature valid → every artifact must be listed in checksums.txt AND match
48
+ * its SHA-256. Any missing/mismatched artifact → refuse (also not
49
+ * overridable — a validly-signed manifest that doesn't match the bytes we
50
+ * downloaded means the download was tampered).
51
+ */
52
+ export declare function decideUpdateVerification(input: UpdateVerificationInput): UpdateVerificationResult;
53
+ //# sourceMappingURL=minisign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minisign.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/minisign.ts"],"names":[],"mappings":"AA6CA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAmBtG;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOnE;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,4EAA4E;IAC5E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,oFAAoF;IACpF,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC/C,oFAAoF;IACpF,aAAa,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,uBAAuB,GAAG,wBAAwB,CA0BjG"}
@@ -0,0 +1,126 @@
1
+ import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
2
+ // DER SubjectPublicKeyInfo prefix for an Ed25519 key — prepended to the raw
3
+ // 32-byte public key so Node's crypto can build a KeyObject from it.
4
+ const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
5
+ /**
6
+ * Raw 32-byte Ed25519 key from a minisign public key (the base64 second line of
7
+ * a `.pub`, or the bare base64). `null` if malformed.
8
+ *
9
+ * Layout: `[2-byte algo 'Ed'][8-byte key id][32-byte ed25519 pubkey]` = 42 bytes.
10
+ */
11
+ function parsePublicKey(publicKeyB64) {
12
+ let raw;
13
+ try {
14
+ raw = Buffer.from(publicKeyB64.trim(), 'base64');
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ if (raw.length !== 42 || raw[0] !== 0x45 || raw[1] !== 0x64)
20
+ return null; // 'Ed'
21
+ return raw.subarray(10, 42);
22
+ }
23
+ /**
24
+ * Parse a `.minisig` file's signature line → `{ prehashed, sig }`, or `null`.
25
+ *
26
+ * Layout of the (base64) 2nd line: `[2-byte algo][8-byte key id][64-byte sig]`.
27
+ * algo `ED` (0x45,0x44) = prehashed (Ed25519 over BLAKE2b-512 of the file);
28
+ * `Ed` (0x45,0x64) = legacy (Ed25519 over the file bytes).
29
+ */
30
+ function parseSignature(minisigContent) {
31
+ const lines = minisigContent.split('\n').map((l) => l.trim()).filter(Boolean);
32
+ if (lines.length < 2)
33
+ return null;
34
+ let raw;
35
+ try {
36
+ raw = Buffer.from(lines[1], 'base64');
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ if (raw.length !== 74 || raw[0] !== 0x45)
42
+ return null;
43
+ const mode = raw[1];
44
+ if (mode !== 0x44 && mode !== 0x64)
45
+ return null;
46
+ return { prehashed: mode === 0x44, sig: raw.subarray(10, 74) };
47
+ }
48
+ /**
49
+ * Verify a minisign signature over `artifact` against `publicKeyB64` (the base64
50
+ * line of a minisign public key). Returns true ONLY for a valid signature by
51
+ * that key. Supports minisign's prehashed (BLAKE2b-512) and legacy modes.
52
+ * In-language (Node crypto) — no `minisign` binary dependency.
53
+ */
54
+ export function verifyMinisign(publicKeyB64, minisigContent, artifact) {
55
+ const pub = parsePublicKey(publicKeyB64);
56
+ const parsed = parseSignature(minisigContent);
57
+ if (!pub || !parsed)
58
+ return false;
59
+ const message = parsed.prehashed
60
+ ? createHash('blake2b512').update(artifact).digest()
61
+ : artifact;
62
+ try {
63
+ const key = createPublicKey({
64
+ key: Buffer.concat([ED25519_SPKI_PREFIX, pub]),
65
+ format: 'der',
66
+ type: 'spki',
67
+ });
68
+ return cryptoVerify(null, message, key, parsed.sig);
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * Parse a `sha256sum`-format checksums file into filename → lowercase-hex-digest.
76
+ * Handles both text (`hash␠␠name`) and binary (`hash␠*name`) lines; ignores any
77
+ * malformed line. Only 64-hex digests are accepted, so a truncated/garbage line
78
+ * can never masquerade as a valid checksum.
79
+ */
80
+ export function parseChecksums(content) {
81
+ const map = new Map();
82
+ for (const line of content.split('\n')) {
83
+ const m = line.trim().match(/^([0-9a-fA-F]{64})\s+\*?(.+)$/);
84
+ if (m)
85
+ map.set(m[2].trim(), m[1].toLowerCase());
86
+ }
87
+ return map;
88
+ }
89
+ /**
90
+ * The self-update trust policy — pure, so it can be exhaustively tested without
91
+ * touching the network or the filesystem.
92
+ *
93
+ * - No signature material → UNSIGNED. Allowed only if the operator opted in
94
+ * via `allowUnsigned`; we never fabricate trust.
95
+ * - Signature present but invalid for our key → refuse. This is a tampering /
96
+ * wrong-signer signal and is **not** overridable by `allowUnsigned` (the
97
+ * escape hatch covers "no signature", never "bad signature").
98
+ * - Signature valid → every artifact must be listed in checksums.txt AND match
99
+ * its SHA-256. Any missing/mismatched artifact → refuse (also not
100
+ * overridable — a validly-signed manifest that doesn't match the bytes we
101
+ * downloaded means the download was tampered).
102
+ */
103
+ export function decideUpdateVerification(input) {
104
+ const { publicKeyB64, checksums, minisigContent, artifacts, allowUnsigned } = input;
105
+ if (!checksums || !minisigContent) {
106
+ return allowUnsigned
107
+ ? { allow: true, signed: false, note: 'release is unsigned; proceeding under JARVIS_ALLOW_UNSIGNED_UPDATE' }
108
+ : { allow: false, reason: 'release is not signed (checksums.txt.minisig missing)' };
109
+ }
110
+ if (!verifyMinisign(publicKeyB64, minisigContent, checksums)) {
111
+ return { allow: false, reason: 'checksums.txt signature is invalid for the trusted key' };
112
+ }
113
+ const hashes = parseChecksums(checksums.toString('utf-8'));
114
+ for (const { filename, data } of artifacts) {
115
+ const want = hashes.get(filename);
116
+ if (!want) {
117
+ return { allow: false, reason: `${filename} is not listed in the signed checksums.txt` };
118
+ }
119
+ const got = createHash('sha256').update(data).digest('hex');
120
+ if (got !== want) {
121
+ return { allow: false, reason: `${filename} does not match the signed checksums.txt (sha256 mismatch)` };
122
+ }
123
+ }
124
+ return { allow: true, signed: true };
125
+ }
126
+ //# sourceMappingURL=minisign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minisign.js","sourceRoot":"","sources":["../../../src/services/upgrade/minisign.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"self-updater.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/self-updater.ts"],"names":[],"mappings":"AASA,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;AAmBnD;;GAEG;AACH,wBAAsB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDjF;AAoDD,+DAA+D;AAC/D,wBAAgB,gBAAgB,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQ/F;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
1
+ {"version":3,"file":"self-updater.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/self-updater.ts"],"names":[],"mappings":"AAgBA,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;AAyBnD;;GAEG;AACH,wBAAsB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAkEjF;AAoGD,+DAA+D;AAC/D,wBAAgB,gBAAgB,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQ/F;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
@@ -4,7 +4,18 @@ import { homedir, platform, arch } from 'node:os';
4
4
  import { execSync, spawn } from 'node:child_process';
5
5
  import { pipeline } from 'node:stream/promises';
6
6
  import { Readable } from 'node:stream';
7
+ import { decideUpdateVerification } from './minisign.js';
7
8
  const REPO = 'alexberardi/jarvis-admin';
9
+ // Trusted minisign public key for release artifacts (key id 725ba202b54fa2c9).
10
+ // Releases sign checksums.txt -> checksums.txt.minisig in CI; the self-updater
11
+ // verifies that signature and the artifacts' SHA-256 against it before applying
12
+ // an update. Rotating the signing key means updating this constant.
13
+ const RELEASE_SIGNING_PUBKEY = 'RWRyW6ICtU+iyX4p4RnS24ju0gRsWpxvv6B8pI9G+ZS01q8t8oupAQ8L';
14
+ /** Operator opt-in to accept an UNSIGNED release (never overrides a bad signature). */
15
+ function allowUnsignedUpdate() {
16
+ const v = (process.env.JARVIS_ALLOW_UNSIGNED_UPDATE ?? '').trim().toLowerCase();
17
+ return v === '1' || v === 'true' || v === 'yes';
18
+ }
8
19
  function detectBinaryName() {
9
20
  const os = platform();
10
21
  const a = arch();
@@ -34,12 +45,21 @@ export async function selfUpdate(targetVersion, emit) {
34
45
  const binaryUrl = `https://github.com/${REPO}/releases/download/${tag}/${binaryName}`;
35
46
  const newBinaryPath = join(binDir, 'jarvis-admin.new');
36
47
  await downloadFile(binaryUrl, newBinaryPath);
37
- chmodSync(newBinaryPath, 0o755);
38
48
  // Download new frontend assets
39
49
  emit({ phase: 'download', message: 'Downloading frontend assets...' });
40
50
  const publicUrl = `https://github.com/${REPO}/releases/download/${tag}/public.tar.gz`;
41
51
  const tarPath = join(binDir, 'public.tar.gz');
42
52
  await downloadFile(publicUrl, tarPath);
53
+ // Verify the release signature BEFORE we make the binary executable, extract
54
+ // the (untrusted) tarball, or swap anything in. A tampered or unsigned update
55
+ // is refused here (unless the operator opted into JARVIS_ALLOW_UNSIGNED_UPDATE
56
+ // for an unsigned release — which never overrides a bad signature).
57
+ emit({ phase: 'verify', message: 'Verifying release signature...' });
58
+ await verifyReleaseArtifacts(tag, [
59
+ { path: newBinaryPath, filename: binaryName },
60
+ { path: tarPath, filename: 'public.tar.gz' },
61
+ ], emit);
62
+ chmodSync(newBinaryPath, 0o755);
43
63
  // Extract to public.new/
44
64
  const publicNewDir = join(binDir, 'public.new');
45
65
  mkdirSync(publicNewDir, { recursive: true });
@@ -121,6 +141,46 @@ async function downloadFile(url, destPath) {
121
141
  const fileStream = createWriteStream(destPath);
122
142
  await pipeline(Readable.fromWeb(res.body), fileStream);
123
143
  }
144
+ /** Fetch a small release asset into memory; null on any 404/error (asset absent). */
145
+ async function downloadOptional(url) {
146
+ try {
147
+ const res = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(60_000) });
148
+ if (!res.ok)
149
+ return null;
150
+ return Buffer.from(await res.arrayBuffer());
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ /**
157
+ * Fetch checksums.txt + its minisign signature for `tag` and enforce the update
158
+ * trust policy against the already-downloaded artifacts. Throws (aborting the
159
+ * update, before any swap) if the release is unsigned without opt-in, the
160
+ * signature is invalid, or an artifact's hash doesn't match the signed manifest.
161
+ */
162
+ async function verifyReleaseArtifacts(tag, artifacts, emit) {
163
+ const base = `https://github.com/${REPO}/releases/download/${tag}`;
164
+ const checksums = await downloadOptional(`${base}/checksums.txt`);
165
+ const minisig = await downloadOptional(`${base}/checksums.txt.minisig`);
166
+ const result = decideUpdateVerification({
167
+ publicKeyB64: RELEASE_SIGNING_PUBKEY,
168
+ checksums,
169
+ minisigContent: minisig ? minisig.toString('utf-8') : null,
170
+ artifacts: artifacts.map((a) => ({ filename: a.filename, data: readFileSync(a.path) })),
171
+ allowUnsigned: allowUnsignedUpdate(),
172
+ });
173
+ if (!result.allow) {
174
+ throw new Error(`Update refused: ${result.reason}. Set JARVIS_ALLOW_UNSIGNED_UPDATE=1 to accept an ` +
175
+ `unsigned release at your own risk (this does not bypass a failed signature check).`);
176
+ }
177
+ if (result.signed) {
178
+ emit({ phase: 'verify', message: 'Release signature verified.' });
179
+ }
180
+ else {
181
+ emit({ phase: 'verify', level: 'warn', message: result.note ?? 'Proceeding with an UNSIGNED release.' });
182
+ }
183
+ }
124
184
  /** Check if an upgrade was interrupted and needs to resume. */
125
185
  export function getUpgradeMarker() {
126
186
  const path = getMarkerPath();
@@ -1 +1 @@
1
- {"version":3,"file":"self-updater.js","sourceRoot":"","sources":["../../../src/services/upgrade/self-updater.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"self-updater.js","sourceRoot":"","sources":["../../../src/services/upgrade/self-updater.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,10 @@
1
1
  export type GpuType = 'nvidia' | 'amd' | 'amd-rocm' | 'apple' | 'none';
2
+ /**
3
+ * Whisper GPU backend, chosen explicitly and independently of the LLM gpuType.
4
+ * Default "cpu" — Whisper's base.en is fast on CPU and leaves the GPU for the LLM.
5
+ * Maps to the whisper image suffix: cpu "" / cuda "-cuda" / vulkan "-vulkan" / rocm "-rocm".
6
+ */
7
+ export type WhisperBackend = 'cpu' | 'cuda' | 'vulkan' | 'rocm';
2
8
  export interface HardwareInfo {
3
9
  platform: 'darwin' | 'linux';
4
10
  arch: string;
@@ -19,6 +25,8 @@ export interface WizardState {
19
25
  dbUser: string;
20
26
  whisperModel: string;
21
27
  whisperModelPath: string;
28
+ /** Explicit Whisper GPU backend (default "cpu" when unset). Independent of hardware.gpuType. */
29
+ whisperBackend?: WhisperBackend;
22
30
  llmInterface: string;
23
31
  deploymentMode: 'local' | 'remote-llm';
24
32
  deploymentTarget: 'standard' | 'compose-export';
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../src/types/wizard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../src/types/wizard.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "3.0.0",
3
- "platformVersion": "0.1.0",
3
+ "platformVersion": "0.1.66",
4
4
  "services": [
5
5
  {
6
6
  "id": "jarvis-config-service",
@@ -81,7 +81,9 @@
81
81
  { "name": "ADMIN_API_KEY", "description": "Admin endpoint protection", "required": true, "secret": true, "secretRef": "ADMIN_API_KEY" },
82
82
  { "name": "JARVIS_AUTH_SECRET_KEY", "description": "JWT signing key (shared with jarvis-auth)", "required": true, "secret": true, "secretRef": "AUTH_SECRET_KEY" },
83
83
  { "name": "JARVIS_CONFIG_URL", "description": "Config service URL", "required": false, "default": "http://jarvis-config-service:7700" },
84
- { "name": "JARVIS_MQTT_BROKER_URL", "description": "MQTT broker URL for node communication", "required": false, "default": "mqtt://mosquitto:1884" }
84
+ { "name": "JARVIS_MQTT_BROKER_URL", "description": "MQTT broker URL for node communication", "required": false, "default": "mqtt://mosquitto:1884" },
85
+ { "name": "MQTT_USERNAME", "description": "Shared broker username", "required": false, "default": "jarvis" },
86
+ { "name": "MQTT_PASSWORD", "description": "Shared broker password (authenticates CC to mosquitto)", "required": true, "secret": true, "secretRef": "MQTT_PASSWORD" }
85
87
  ]
86
88
  },
87
89
  {
@@ -120,8 +122,12 @@
120
122
  "port": 7707,
121
123
  "image": "ghcr.io/alexberardi/jarvis-tts:latest",
122
124
  "healthCheck": "/health",
123
- "dependsOn": ["jarvis-auth", "jarvis-config-service"],
125
+ "dependsOn": ["postgres", "jarvis-auth", "jarvis-config-service"],
126
+ "database": "jarvis_tts",
127
+ "dbDriverPrefix": "postgresql+psycopg2://",
128
+ "migrate": true,
124
129
  "envVars": [
130
+ { "name": "DATABASE_URL", "description": "PostgreSQL connection string", "required": true },
125
131
  { "name": "JARVIS_CONFIG_URL", "description": "Config service URL", "required": false, "default": "http://jarvis-config-service:7700" },
126
132
  { "name": "TTS_PROVIDER", "description": "Active TTS provider (piper, kokoro)", "required": false, "default": "kokoro" },
127
133
  { "name": "HF_HOME", "description": "HuggingFace cache dir for Kokoro voice weights", "required": false, "default": "/app/models/hf_cache" }
@@ -278,9 +284,13 @@
278
284
  "id": "mosquitto",
279
285
  "name": "Mosquitto",
280
286
  "description": "MQTT message broker — node-to-service communication for TTS, commands, and settings",
281
- "image": "eclipse-mosquitto:2",
287
+ "image": "eclipse-mosquitto:2.0",
282
288
  "port": 1884,
283
- "envVars": [],
289
+ "envVars": [
290
+ { "name": "MQTT_USERNAME", "description": "Shared broker username", "required": false, "default": "jarvis" },
291
+ { "name": "MQTT_PASSWORD", "description": "Shared broker password (hashed into the password_file at startup)", "required": true, "secret": true, "secretRef": "MQTT_PASSWORD" },
292
+ { "name": "MQTT_ALLOW_ANON", "description": "Accept anonymous clients (transition window). Set false to lock the broker.", "required": false, "default": "true" }
293
+ ],
284
294
  "volumes": ["jarvis-mosquitto-data:/mosquitto/data"]
285
295
  },
286
296
  {
@@ -290,7 +300,7 @@
290
300
  "image": "grafana/grafana:latest",
291
301
  "port": 3000,
292
302
  "envVars": [
293
- { "name": "GF_SECURITY_ADMIN_PASSWORD", "description": "Grafana admin password", "required": true, "default": "jarvis" }
303
+ { "name": "GF_SECURITY_ADMIN_PASSWORD", "description": "Grafana admin password", "required": true, "secret": true, "secretRef": "GRAFANA_ADMIN_PASSWORD" }
294
304
  ],
295
305
  "volumes": ["jarvis-grafana-data:/var/lib/grafana"]
296
306
  }