@alexberardi/jarvis-admin 0.1.65 → 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.
- package/package.json +1 -1
- package/public/assets/index-CAv1RM9y.css +1 -0
- package/public/assets/index-DBEZIFbZ.js +18 -0
- package/public/index.html +2 -2
- package/server/dist/app.d.ts.map +1 -1
- package/server/dist/app.js +24 -0
- package/server/dist/app.js.map +1 -1
- package/server/dist/data/image-digests.json +58 -0
- package/server/dist/data/service-registry.json +11 -5
- package/server/dist/middleware/auth.d.ts +14 -0
- package/server/dist/middleware/auth.d.ts.map +1 -1
- package/server/dist/middleware/auth.js +19 -0
- package/server/dist/middleware/auth.js.map +1 -1
- package/server/dist/routes/install.d.ts.map +1 -1
- package/server/dist/routes/install.js +29 -8
- package/server/dist/routes/install.js.map +1 -1
- package/server/dist/routes/setup.d.ts.map +1 -1
- package/server/dist/routes/setup.js +2 -1
- package/server/dist/routes/setup.js.map +1 -1
- package/server/dist/services/generators/compose-generator.d.ts +11 -0
- package/server/dist/services/generators/compose-generator.d.ts.map +1 -1
- package/server/dist/services/generators/compose-generator.js +137 -29
- package/server/dist/services/generators/compose-generator.js.map +1 -1
- package/server/dist/services/generators/env-generator.d.ts.map +1 -1
- package/server/dist/services/generators/env-generator.js +17 -2
- package/server/dist/services/generators/env-generator.js.map +1 -1
- package/server/dist/services/generators/secret-generator.d.ts +1 -1
- package/server/dist/services/generators/secret-generator.d.ts.map +1 -1
- package/server/dist/services/generators/secret-generator.js +15 -0
- package/server/dist/services/generators/secret-generator.js.map +1 -1
- package/server/dist/services/upgrade/compose-upgrader.d.ts +36 -0
- package/server/dist/services/upgrade/compose-upgrader.d.ts.map +1 -1
- package/server/dist/services/upgrade/compose-upgrader.js +90 -33
- package/server/dist/services/upgrade/compose-upgrader.js.map +1 -1
- package/server/dist/services/upgrade/minisign.d.ts +53 -0
- package/server/dist/services/upgrade/minisign.d.ts.map +1 -0
- package/server/dist/services/upgrade/minisign.js +126 -0
- package/server/dist/services/upgrade/minisign.js.map +1 -0
- package/server/dist/services/upgrade/self-updater.d.ts.map +1 -1
- package/server/dist/services/upgrade/self-updater.js +61 -1
- package/server/dist/services/upgrade/self-updater.js.map +1 -1
- package/server/dist/types/wizard.d.ts +8 -0
- package/server/dist/types/wizard.d.ts.map +1 -1
- package/server/src/data/service-registry.json +11 -5
- package/public/assets/index-DeByHCh9.css +0 -1
- 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
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
//
|
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;
|
|
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":"
|
|
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":"AAAA,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClI,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;
|
|
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":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;AAEtE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE/D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAGlB,cAAc,EAAE,MAAM,EAAE,CAAA;IAGxB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,gGAAgG;IAChG,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,YAAY,EAAE,MAAM,CAAA;IAGpB,cAAc,EAAE,OAAO,GAAG,YAAY,CAAA;IACtC,gBAAgB,EAAE,UAAU,GAAG,gBAAgB,CAAA;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC5B,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,4FAA4F;IAC5F,YAAY,EAAE,OAAO,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kEAAkE;IAClE,YAAY,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC9B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,SAAS,EAAE,MAAM,GAAG;QACnB,OAAO,EAAE,OAAO,CAAA;QAChB,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACnD,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,wBAAwB,CAAA;IAC7F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,UAAU,CAAC,EAAE,UAAU,GAAG,gBAAgB,CAAA;CAC3C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "3.0.0",
|
|
3
|
-
"platformVersion": "0.1.
|
|
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
|
{
|
|
@@ -282,9 +284,13 @@
|
|
|
282
284
|
"id": "mosquitto",
|
|
283
285
|
"name": "Mosquitto",
|
|
284
286
|
"description": "MQTT message broker — node-to-service communication for TTS, commands, and settings",
|
|
285
|
-
"image": "eclipse-mosquitto:2",
|
|
287
|
+
"image": "eclipse-mosquitto:2.0",
|
|
286
288
|
"port": 1884,
|
|
287
|
-
"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
|
+
],
|
|
288
294
|
"volumes": ["jarvis-mosquitto-data:/mosquitto/data"]
|
|
289
295
|
},
|
|
290
296
|
{
|
|
@@ -294,7 +300,7 @@
|
|
|
294
300
|
"image": "grafana/grafana:latest",
|
|
295
301
|
"port": 3000,
|
|
296
302
|
"envVars": [
|
|
297
|
-
{ "name": "GF_SECURITY_ADMIN_PASSWORD", "description": "Grafana admin password", "required": true, "
|
|
303
|
+
{ "name": "GF_SECURITY_ADMIN_PASSWORD", "description": "Grafana admin password", "required": true, "secret": true, "secretRef": "GRAFANA_ADMIN_PASSWORD" }
|
|
298
304
|
],
|
|
299
305
|
"volumes": ["jarvis-grafana-data:/var/lib/grafana"]
|
|
300
306
|
}
|