@alexberardi/jarvis-admin 0.1.65 → 0.1.67
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-CPK3ZbaB.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 +13 -6
- 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 +35 -8
- package/server/dist/routes/install.js.map +1 -1
- package/server/dist/routes/nodes.d.ts.map +1 -1
- package/server/dist/routes/nodes.js +5 -1
- package/server/dist/routes/nodes.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/routes/traces.d.ts.map +1 -1
- package/server/dist/routes/traces.js +9 -2
- package/server/dist/routes/traces.js.map +1 -1
- package/server/dist/services/commandCenter.d.ts +11 -0
- package/server/dist/services/commandCenter.d.ts.map +1 -0
- package/server/dist/services/commandCenter.js +20 -0
- package/server/dist/services/commandCenter.js.map +1 -0
- package/server/dist/services/generators/compose-generator.d.ts +11 -1
- package/server/dist/services/generators/compose-generator.d.ts.map +1 -1
- package/server/dist/services/generators/compose-generator.js +151 -39
- 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 +47 -0
- package/server/dist/services/upgrade/compose-upgrader.d.ts.map +1 -1
- package/server/dist/services/upgrade/compose-upgrader.js +122 -33
- package/server/dist/services/upgrade/compose-upgrader.js.map +1 -1
- package/server/dist/services/upgrade/image-digest-resolver.d.ts +16 -0
- package/server/dist/services/upgrade/image-digest-resolver.d.ts.map +1 -0
- package/server/dist/services/upgrade/image-digest-resolver.js +80 -0
- package/server/dist/services/upgrade/image-digest-resolver.js.map +1 -0
- 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 +13 -6
- package/public/assets/index-DeByHCh9.css +0 -1
- package/public/assets/index-DeCnqmbD.js +0 -18
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getCoreServices, getRecommendedServices, getOptionalServices, getRequiredInfrastructure, } from './service-registry.js';
|
|
2
2
|
import { serviceIdToPortVar } from './port-utils.js';
|
|
3
|
-
import { SECRET_KEYS } from './secret-generator.js';
|
|
3
|
+
import { SECRET_KEYS, generateHexSecret } from './secret-generator.js';
|
|
4
4
|
export function generateEnv(state, registry) {
|
|
5
5
|
const lines = [];
|
|
6
6
|
lines.push('# Jarvis Configuration');
|
|
@@ -9,7 +9,11 @@ export function generateEnv(state, registry) {
|
|
|
9
9
|
// Secrets
|
|
10
10
|
lines.push('# --- Secrets ---');
|
|
11
11
|
for (const key of SECRET_KEYS) {
|
|
12
|
-
|
|
12
|
+
// Never emit an empty secret: with JARVIS_ENV=production the boot-time secret
|
|
13
|
+
// guard would refuse to start. A reconstructed install carries its existing
|
|
14
|
+
// value through; a genuinely missing one gets a fresh strong secret (passwords
|
|
15
|
+
// 16 bytes, tokens/keys 32 — matching generateAllSecrets).
|
|
16
|
+
const value = state.secrets[key] || generateHexSecret(key.includes('PASSWORD') ? 16 : 32);
|
|
13
17
|
lines.push(`${key}=${value}`);
|
|
14
18
|
}
|
|
15
19
|
lines.push('');
|
|
@@ -106,6 +110,17 @@ export function generateEnv(state, registry) {
|
|
|
106
110
|
lines.push('# --- Release Track ---');
|
|
107
111
|
lines.push(`JARVIS_IMAGE_TAG=${state.releaseTrack === 'dev' ? 'dev' : 'latest'}`);
|
|
108
112
|
lines.push('');
|
|
113
|
+
// MQTT broker lock. Fresh installs lock the broker from the first boot
|
|
114
|
+
// (allow_anonymous=false): the command-center reads MQTT_PASSWORD from its
|
|
115
|
+
// env and every node fetches broker creds over authenticated HTTP *before* it
|
|
116
|
+
// ever opens an MQTT connection, so there's no anonymous client to strand.
|
|
117
|
+
// The transition window (true) is reserved for in-place UPGRADES of fleets
|
|
118
|
+
// whose nodes predate credential auto-fetch — handled in the compose-upgrader,
|
|
119
|
+
// not here. Compose still defaults `${MQTT_ALLOW_ANON:-true}` as a safety
|
|
120
|
+
// fallback if this line is ever missing.
|
|
121
|
+
lines.push('# --- MQTT Broker ---');
|
|
122
|
+
lines.push('MQTT_ALLOW_ANON=false');
|
|
123
|
+
lines.push('');
|
|
109
124
|
// Native services (macOS only). Comma-separated list of service IDs the user
|
|
110
125
|
// opted to run as LaunchAgents instead of in Docker. Read back by
|
|
111
126
|
// state-reconstructor so reconcile flows keep them out of compose.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-generator.js","sourceRoot":"","sources":["../../../src/services/generators/env-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"env-generator.js","sourceRoot":"","sources":["../../../src/services/generators/env-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Generates a cryptographically secure hex string using Node.js crypto.
|
|
3
3
|
*/
|
|
4
4
|
export declare function generateHexSecret(byteLength?: number): string;
|
|
5
|
-
export declare const SECRET_KEYS: readonly ["AUTH_SECRET_KEY", "JARVIS_CONFIG_ADMIN_TOKEN", "JARVIS_AUTH_ADMIN_TOKEN", "POSTGRES_PASSWORD", "REDIS_PASSWORD", "ADMIN_API_KEY"];
|
|
5
|
+
export declare const SECRET_KEYS: readonly ["AUTH_SECRET_KEY", "JARVIS_CONFIG_ADMIN_TOKEN", "JARVIS_AUTH_ADMIN_TOKEN", "POSTGRES_PASSWORD", "REDIS_PASSWORD", "ADMIN_API_KEY", "MODEL_SERVICE_TOKEN", "MQTT_PASSWORD", "GRAFANA_ADMIN_PASSWORD"];
|
|
6
6
|
export type SecretKey = (typeof SECRET_KEYS)[number];
|
|
7
7
|
/**
|
|
8
8
|
* Generates all required secrets.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-generator.d.ts","sourceRoot":"","sources":["../../../src/services/generators/secret-generator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,GAAE,MAAW,GAAG,MAAM,CAEjE;AAED,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"secret-generator.d.ts","sourceRoot":"","sources":["../../../src/services/generators/secret-generator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,GAAE,MAAW,GAAG,MAAM,CAEjE;AAED,eAAO,MAAM,WAAW,gNAsBd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAO9D"}
|
|
@@ -12,6 +12,21 @@ export const SECRET_KEYS = [
|
|
|
12
12
|
'POSTGRES_PASSWORD',
|
|
13
13
|
'REDIS_PASSWORD',
|
|
14
14
|
'ADMIN_API_KEY',
|
|
15
|
+
// Internal auth between the llm-proxy API/worker and its model service (:7705).
|
|
16
|
+
// The model service 503s ALL inference when this is unset (while /health stays
|
|
17
|
+
// green), so it must be generated + injected on every install. No 'PASSWORD' in
|
|
18
|
+
// the name -> 32 bytes / 64 hex, matching the installer.
|
|
19
|
+
'MODEL_SERVICE_TOKEN',
|
|
20
|
+
// Shared MQTT broker credential (username is the literal 'jarvis'). The
|
|
21
|
+
// mosquitto container hashes this into a password_file at startup; every MQTT
|
|
22
|
+
// client (command-center, nodes) authenticates with it. 'PASSWORD' in the name
|
|
23
|
+
// -> 16 bytes / 32 hex. Preserved across regen so nodes keep authenticating.
|
|
24
|
+
'MQTT_PASSWORD',
|
|
25
|
+
// Grafana admin password. Without this the registry default was the well-known
|
|
26
|
+
// literal 'jarvis' on a 0.0.0.0:3000 bind — any LAN client could log in and read
|
|
27
|
+
// all Loki logs (voice transcripts / PII) + SSRF-pivot via the datasource proxy.
|
|
28
|
+
// 'PASSWORD' in the name -> 16 bytes / 32 hex.
|
|
29
|
+
'GRAFANA_ADMIN_PASSWORD',
|
|
15
30
|
];
|
|
16
31
|
/**
|
|
17
32
|
* Generates all required secrets.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-generator.js","sourceRoot":"","sources":["../../../src/services/generators/secret-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,aAAqB,EAAE;IACvD,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,2BAA2B;IAC3B,yBAAyB;IACzB,mBAAmB;IACnB,gBAAgB;IAChB,eAAe;
|
|
1
|
+
{"version":3,"file":"secret-generator.js","sourceRoot":"","sources":["../../../src/services/generators/secret-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,aAAqB,EAAE;IACvD,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,2BAA2B;IAC3B,yBAAyB;IACzB,mBAAmB;IACnB,gBAAgB;IAChB,eAAe;IACf,gFAAgF;IAChF,+EAA+E;IAC/E,gFAAgF;IAChF,yDAAyD;IACzD,qBAAqB;IACrB,wEAAwE;IACxE,8EAA8E;IAC9E,+EAA+E;IAC/E,6EAA6E;IAC7E,eAAe;IACf,+EAA+E;IAC/E,iFAAiF;IACjF,iFAAiF;IACjF,+CAA+C;IAC/C,wBAAwB;CAChB,CAAA;AAIV;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,OAAO,GAA2B,EAAE,CAAA;IAC1C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACrD,OAAO,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,OAAoC,CAAA;AAC7C,CAAC"}
|
|
@@ -1,4 +1,43 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { ServiceRegistry } from '../../types/service-registry.js';
|
|
3
|
+
import type { WhisperBackend } from '../../types/wizard.js';
|
|
4
|
+
import { type ImageDigestMap } from '../generators/compose-generator.js';
|
|
5
|
+
export declare function loadEnvFile(composePath: string): Record<string, string>;
|
|
6
|
+
export interface UpgradedComposeFiles {
|
|
7
|
+
compose: string;
|
|
8
|
+
env: string;
|
|
9
|
+
initDb: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* PURE regeneration core: reconstruct the wizard state from an existing install's
|
|
13
|
+
* env and produce the upgraded compose / .env / init-db.sh as STRINGS. Writes
|
|
14
|
+
* nothing. Both the in-place upgrader and the download/CLI path build on this so
|
|
15
|
+
* they can never diverge.
|
|
16
|
+
*
|
|
17
|
+
* Secrets and user config are preserved because they're recovered from
|
|
18
|
+
* ``existingEnv`` (via reconstructWizardState + mergeEnv); named data volumes are
|
|
19
|
+
* matched by Docker on ``up`` since the generator emits stable names, and
|
|
20
|
+
* bind-mount host paths come from env too. A regenerated file is CANONICAL — any
|
|
21
|
+
* hand-edits to the original compose are intentionally not carried over.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildUpgradedComposeFiles(existingEnv: Record<string, string>, registry: ServiceRegistry, overrides?: UpgradeOverrides, hostComposePath?: string, digests?: ImageDigestMap): UpgradedComposeFiles;
|
|
24
|
+
/**
|
|
25
|
+
* Non-destructive regeneration for the "download / hand it to the user" flow:
|
|
26
|
+
* read the existing install's env from ``composePath`` and return the upgraded
|
|
27
|
+
* files as strings WITHOUT touching anything on disk. Used by the compose-mode
|
|
28
|
+
* migrator (installer CLI) and the admin download endpoint.
|
|
29
|
+
*/
|
|
30
|
+
export declare function regenerateComposeFiles(composePath: string, overrides?: UpgradeOverrides, hostComposePath?: string): UpgradedComposeFiles;
|
|
31
|
+
/**
|
|
32
|
+
* Like {@link regenerateComposeFiles}, but first refreshes the pinned image
|
|
33
|
+
* digests from GHCR so the downloaded compose points at the NEWEST published
|
|
34
|
+
* build (the bundled map is frozen at admin-build time). Async — the refresh is
|
|
35
|
+
* a network round-trip; a resolver failure degrades to the bundled map and never
|
|
36
|
+
* throws. Backs the "Update stack to latest" download: the operator applies it
|
|
37
|
+
* themselves with `docker compose pull && docker compose up -d` (so it can also
|
|
38
|
+
* update jarvis-admin, which the in-place reconcile can't recreate from itself).
|
|
39
|
+
*/
|
|
40
|
+
export declare function regenerateComposeFilesLatest(composePath: string, overrides?: UpgradeOverrides, hostComposePath?: string): Promise<UpgradedComposeFiles>;
|
|
2
41
|
/**
|
|
3
42
|
* Upgrade the compose + env files in place, preserving secrets and user config.
|
|
4
43
|
*
|
|
@@ -15,7 +54,15 @@ export interface UpgradeOverrides {
|
|
|
15
54
|
relayEnabled?: boolean;
|
|
16
55
|
relayUrl?: string;
|
|
17
56
|
whisperModelPath?: string;
|
|
57
|
+
whisperBackend?: WhisperBackend;
|
|
18
58
|
releaseTrack?: 'stable' | 'dev';
|
|
59
|
+
/**
|
|
60
|
+
* Flip the MQTT broker's ``allow_anonymous`` (the transition→lockdown control).
|
|
61
|
+
* ``false`` locks the broker to authenticated clients only; ``true`` re-opens
|
|
62
|
+
* it. Undefined leaves the current state untouched. This is an operational
|
|
63
|
+
* flag, not user config, so an explicit value wins over env preservation.
|
|
64
|
+
*/
|
|
65
|
+
mqttAllowAnon?: boolean;
|
|
19
66
|
}
|
|
20
67
|
export declare function upgradeCompose(_app: FastifyInstance, overrides?: UpgradeOverrides): Promise<void>;
|
|
21
68
|
//# sourceMappingURL=compose-upgrader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-upgrader.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/compose-upgrader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"compose-upgrader.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/compose-upgrader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,oCAAoC,CAAA;AAyBhH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYvE;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,QAAQ,EAAE,eAAe,EACzB,SAAS,CAAC,EAAE,gBAAgB,EAC5B,eAAe,CAAC,EAAE,MAAM,EACxB,OAAO,CAAC,EAAE,cAAc,GACvB,oBAAoB,CAkDtB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,gBAAgB,EAC5B,eAAe,CAAC,EAAE,MAAM,GACvB,oBAAoB,CAItB;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,gBAAgB,EAC5B,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,oBAAoB,CAAC,CAW/B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,YAAY,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC/B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,eAAe,EACrB,SAAS,CAAC,EAAE,gBAAgB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
|
@@ -5,12 +5,26 @@ import { generateEnv } from '../generators/env-generator.js';
|
|
|
5
5
|
import { generateInitDbScript } from '../generators/init-db-generator.js';
|
|
6
6
|
import { parseRegistry } from '../generators/service-registry.js';
|
|
7
7
|
import { reconstructWizardState } from './state-reconstructor.js';
|
|
8
|
+
import { refreshDigestsForTrack } from './image-digest-resolver.js';
|
|
8
9
|
import { mergeEnv } from './env-merger.js';
|
|
9
10
|
import { VERSION } from '../../version.js';
|
|
10
11
|
import { getComposePath } from '../compose-path.js';
|
|
11
12
|
import { getHostComposePath } from '../host-paths.js';
|
|
12
13
|
import registryData from '../../data/service-registry.json' with { type: 'json' };
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Set ``key=value`` in a .env string: replace the line in place if the key
|
|
16
|
+
* exists, otherwise append it. Used for operational flags (e.g. the broker lock)
|
|
17
|
+
* that must win over the merge preservation rule.
|
|
18
|
+
*/
|
|
19
|
+
function upsertEnvVar(env, key, value) {
|
|
20
|
+
const line = `${key}=${value}`;
|
|
21
|
+
const pattern = new RegExp(`^${key}=.*$`, 'm');
|
|
22
|
+
if (pattern.test(env))
|
|
23
|
+
return env.replace(pattern, line);
|
|
24
|
+
const base = env.endsWith('\n') ? env : env + '\n';
|
|
25
|
+
return base + line + '\n';
|
|
26
|
+
}
|
|
27
|
+
export function loadEnvFile(composePath) {
|
|
14
28
|
const envFile = join(composePath, '.env');
|
|
15
29
|
if (!existsSync(envFile))
|
|
16
30
|
return {};
|
|
@@ -26,23 +40,19 @@ function loadEnvFile(composePath) {
|
|
|
26
40
|
}
|
|
27
41
|
return vars;
|
|
28
42
|
}
|
|
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
|
|
43
|
+
/**
|
|
44
|
+
* PURE regeneration core: reconstruct the wizard state from an existing install's
|
|
45
|
+
* env and produce the upgraded compose / .env / init-db.sh as STRINGS. Writes
|
|
46
|
+
* nothing. Both the in-place upgrader and the download/CLI path build on this so
|
|
47
|
+
* they can never diverge.
|
|
48
|
+
*
|
|
49
|
+
* Secrets and user config are preserved because they're recovered from
|
|
50
|
+
* ``existingEnv`` (via reconstructWizardState + mergeEnv); named data volumes are
|
|
51
|
+
* matched by Docker on ``up`` since the generator emits stable names, and
|
|
52
|
+
* bind-mount host paths come from env too. A regenerated file is CANONICAL — any
|
|
53
|
+
* hand-edits to the original compose are intentionally not carried over.
|
|
54
|
+
*/
|
|
55
|
+
export function buildUpgradedComposeFiles(existingEnv, registry, overrides, hostComposePath, digests) {
|
|
46
56
|
const state = reconstructWizardState(existingEnv, registry);
|
|
47
57
|
if (overrides?.enabledModules) {
|
|
48
58
|
state.enabledModules = overrides.enabledModules;
|
|
@@ -56,30 +66,109 @@ export async function upgradeCompose(_app, overrides) {
|
|
|
56
66
|
if (overrides?.whisperModelPath) {
|
|
57
67
|
state.whisperModelPath = overrides.whisperModelPath;
|
|
58
68
|
}
|
|
69
|
+
if (overrides?.whisperBackend) {
|
|
70
|
+
state.whisperBackend = overrides.whisperBackend;
|
|
71
|
+
}
|
|
59
72
|
if (overrides?.releaseTrack) {
|
|
60
73
|
state.releaseTrack = overrides.releaseTrack;
|
|
61
74
|
}
|
|
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;
|
|
75
|
+
if (hostComposePath) {
|
|
76
|
+
state.hostComposePath = hostComposePath;
|
|
70
77
|
}
|
|
71
|
-
|
|
72
|
-
const newCompose = generateCompose(state, registry);
|
|
73
|
-
writeFileSync(join(composePath, 'docker-compose.yml'), newCompose);
|
|
74
|
-
// Step 5: Generate new env template, merge
|
|
78
|
+
const compose = generateCompose(state, registry, digests);
|
|
75
79
|
const newEnvTemplate = generateEnv(state, registry);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
//
|
|
80
|
+
let env = mergeEnv(existingEnv, newEnvTemplate);
|
|
81
|
+
// Broker lock flag is operational, not user config.
|
|
82
|
+
// - An explicit override always wins over mergeEnv's "existing value wins".
|
|
83
|
+
// - A previously-written MQTT_ALLOW_ANON is preserved by mergeEnv, so a lock
|
|
84
|
+
// stays locked (and an open transition stays open) across routine regens.
|
|
85
|
+
// - The fresh-install template now sets MQTT_ALLOW_ANON=false, but an UPGRADE
|
|
86
|
+
// of an install that predates that change (no MQTT_ALLOW_ANON in its .env)
|
|
87
|
+
// must NOT inherit the locked default — its nodes may not have fetched
|
|
88
|
+
// broker creds yet, and locking would drop the whole fleet. Force the
|
|
89
|
+
// transition window (true) in that case; the operator locks explicitly from
|
|
90
|
+
// the admin UI once nodes have migrated.
|
|
91
|
+
if (overrides?.mqttAllowAnon !== undefined) {
|
|
92
|
+
env = upsertEnvVar(env, 'MQTT_ALLOW_ANON', String(overrides.mqttAllowAnon));
|
|
93
|
+
}
|
|
94
|
+
else if (existingEnv['MQTT_ALLOW_ANON'] === undefined) {
|
|
95
|
+
env = upsertEnvVar(env, 'MQTT_ALLOW_ANON', 'true');
|
|
96
|
+
}
|
|
79
97
|
const enabledServices = getAllEnabledServices(state, registry);
|
|
80
98
|
const primaryDb = registry.infrastructure.find((i) => i.id === 'postgres')
|
|
81
99
|
?.envVars.find((e) => e.name === 'POSTGRES_DB')?.default ?? 'jarvis_config';
|
|
82
100
|
const initDb = generateInitDbScript(enabledServices, primaryDb);
|
|
101
|
+
return { compose, env, initDb };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Non-destructive regeneration for the "download / hand it to the user" flow:
|
|
105
|
+
* read the existing install's env from ``composePath`` and return the upgraded
|
|
106
|
+
* files as strings WITHOUT touching anything on disk. Used by the compose-mode
|
|
107
|
+
* migrator (installer CLI) and the admin download endpoint.
|
|
108
|
+
*/
|
|
109
|
+
export function regenerateComposeFiles(composePath, overrides, hostComposePath) {
|
|
110
|
+
const registry = parseRegistry(registryData);
|
|
111
|
+
const existingEnv = loadEnvFile(composePath);
|
|
112
|
+
return buildUpgradedComposeFiles(existingEnv, registry, overrides, hostComposePath);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Like {@link regenerateComposeFiles}, but first refreshes the pinned image
|
|
116
|
+
* digests from GHCR so the downloaded compose points at the NEWEST published
|
|
117
|
+
* build (the bundled map is frozen at admin-build time). Async — the refresh is
|
|
118
|
+
* a network round-trip; a resolver failure degrades to the bundled map and never
|
|
119
|
+
* throws. Backs the "Update stack to latest" download: the operator applies it
|
|
120
|
+
* themselves with `docker compose pull && docker compose up -d` (so it can also
|
|
121
|
+
* update jarvis-admin, which the in-place reconcile can't recreate from itself).
|
|
122
|
+
*/
|
|
123
|
+
export async function regenerateComposeFilesLatest(composePath, overrides, hostComposePath) {
|
|
124
|
+
const registry = parseRegistry(registryData);
|
|
125
|
+
const existingEnv = loadEnvFile(composePath);
|
|
126
|
+
// dev floats (no digest pins), so only the stable track needs a refresh.
|
|
127
|
+
const track = overrides?.releaseTrack === 'dev' ||
|
|
128
|
+
(overrides?.releaseTrack === undefined && existingEnv.JARVIS_IMAGE_TAG === 'dev')
|
|
129
|
+
? 'dev'
|
|
130
|
+
: 'latest';
|
|
131
|
+
const digests = track === 'latest' ? await refreshDigestsForTrack('latest') : undefined;
|
|
132
|
+
return buildUpgradedComposeFiles(existingEnv, registry, overrides, hostComposePath, digests);
|
|
133
|
+
}
|
|
134
|
+
export async function upgradeCompose(_app, overrides) {
|
|
135
|
+
const composePath = getComposePath();
|
|
136
|
+
const registry = parseRegistry(registryData);
|
|
137
|
+
// Step 1: Backup
|
|
138
|
+
const backupDir = join(composePath, `backup-${VERSION}`);
|
|
139
|
+
if (!existsSync(backupDir)) {
|
|
140
|
+
mkdirSync(backupDir, { recursive: true });
|
|
141
|
+
for (const file of ['docker-compose.yml', '.env', 'init-db.sh']) {
|
|
142
|
+
const src = join(composePath, file);
|
|
143
|
+
if (existsSync(src)) {
|
|
144
|
+
cpSync(src, join(backupDir, file));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Step 2: Load existing env
|
|
149
|
+
const existingEnv = loadEnvFile(composePath);
|
|
150
|
+
// Refresh the pinned image digests from GHCR so the regenerated compose points
|
|
151
|
+
// at the newest published build and `docker compose pull` actually fetches it
|
|
152
|
+
// (the bundled digest map is frozen at admin-build time, which otherwise makes
|
|
153
|
+
// pull a no-op and deadlocks updates). Only the stable track pins — dev floats
|
|
154
|
+
// — and a resolver failure degrades to the bundled map, so this never blocks
|
|
155
|
+
// an upgrade.
|
|
156
|
+
const track = overrides?.releaseTrack === 'dev' ||
|
|
157
|
+
(overrides?.releaseTrack === undefined && existingEnv.JARVIS_IMAGE_TAG === 'dev')
|
|
158
|
+
? 'dev'
|
|
159
|
+
: 'latest';
|
|
160
|
+
const digests = track === 'latest' ? await refreshDigestsForTrack('latest') : undefined;
|
|
161
|
+
// Step 3-6: Reconstruct + regenerate via the shared pure core.
|
|
162
|
+
//
|
|
163
|
+
// When admin runs in docker, fetch the absolute host path of the compose
|
|
164
|
+
// dir we were mounted at. env-generator uses it to write MODELS_DIR so
|
|
165
|
+
// bind mounts in the regenerated compose resolve on the host (otherwise
|
|
166
|
+
// they resolve to /host/compose/.models — a path that exists in the admin
|
|
167
|
+
// container but not on the host, so the daemon binds an empty directory).
|
|
168
|
+
const hostPath = await getHostComposePath();
|
|
169
|
+
const { compose, env, initDb } = buildUpgradedComposeFiles(existingEnv, registry, overrides, hostPath || undefined, digests);
|
|
170
|
+
writeFileSync(join(composePath, 'docker-compose.yml'), compose);
|
|
171
|
+
writeFileSync(join(composePath, '.env'), env);
|
|
83
172
|
writeFileSync(join(composePath, 'init-db.sh'), initDb, { mode: 0o755 });
|
|
84
173
|
}
|
|
85
174
|
//# 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":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAIhC,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAuB,MAAM,oCAAoC,CAAA;AAChH,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,YAAY,MAAM,kCAAkC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAEjF;;;;GAIG;AACH,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW,EAAE,KAAa;IAC3D,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9C,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACxD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAA;IAClD,OAAO,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IACzC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAA;IACnC,MAAM,IAAI,GAA2B,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACjD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,SAAQ;QAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;IAC1D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAQD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAmC,EACnC,QAAyB,EACzB,SAA4B,EAC5B,eAAwB,EACxB,OAAwB;IAExB,MAAM,KAAK,GAAG,sBAAsB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IAC3D,IAAI,SAAS,EAAE,cAAc,EAAE,CAAC;QAC9B,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC,cAAc,CAAA;IACjD,CAAC;IACD,IAAI,SAAS,EAAE,YAAY,KAAK,SAAS,EAAE,CAAC;QAC1C,KAAK,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY,CAAA;IAC7C,CAAC;IACD,IAAI,SAAS,EAAE,QAAQ,EAAE,CAAC;QACxB,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAA;IACrC,CAAC;IACD,IAAI,SAAS,EAAE,gBAAgB,EAAE,CAAC;QAChC,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAA;IACrD,CAAC;IACD,IAAI,SAAS,EAAE,cAAc,EAAE,CAAC;QAC9B,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC,cAAc,CAAA;IACjD,CAAC;IACD,IAAI,SAAS,EAAE,YAAY,EAAE,CAAC;QAC5B,KAAK,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY,CAAA;IAC7C,CAAC;IACD,IAAI,eAAe,EAAE,CAAC;QACpB,KAAK,CAAC,eAAe,GAAG,eAAe,CAAA;IACzC,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IACzD,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACnD,IAAI,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;IAE/C,oDAAoD;IACpD,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,+EAA+E;IAC/E,8EAA8E;IAC9E,0EAA0E;IAC1E,yEAAyE;IACzE,+EAA+E;IAC/E,4CAA4C;IAC5C,IAAI,SAAS,EAAE,aAAa,KAAK,SAAS,EAAE,CAAC;QAC3C,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAA;IAC7E,CAAC;SAAM,IAAI,WAAW,CAAC,iBAAiB,CAAC,KAAK,SAAS,EAAE,CAAC;QACxD,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAA;IACpD,CAAC;IAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC;QACxE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,EAAE,OAAO,IAAI,eAAe,CAAA;IAC7E,MAAM,MAAM,GAAG,oBAAoB,CAAC,eAAe,EAAE,SAAS,CAAC,CAAA;IAE/D,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAA;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAAmB,EACnB,SAA4B,EAC5B,eAAwB;IAExB,MAAM,QAAQ,GAAoB,aAAa,CAAC,YAAY,CAAC,CAAA;IAC7D,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAC5C,OAAO,yBAAyB,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC,CAAA;AACrF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,WAAmB,EACnB,SAA4B,EAC5B,eAAwB;IAExB,MAAM,QAAQ,GAAoB,aAAa,CAAC,YAAY,CAAC,CAAA;IAC7D,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAC5C,yEAAyE;IACzE,MAAM,KAAK,GACT,SAAS,EAAE,YAAY,KAAK,KAAK;QACjC,CAAC,SAAS,EAAE,YAAY,KAAK,SAAS,IAAI,WAAW,CAAC,gBAAgB,KAAK,KAAK,CAAC;QAC/E,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,QAAQ,CAAA;IACd,MAAM,OAAO,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACvF,OAAO,yBAAyB,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,CAAA;AAC9F,CAAC;AA6BD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAqB,EACrB,SAA4B;IAE5B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,QAAQ,GAAoB,aAAa,CAAC,YAAY,CAAC,CAAA;IAE7D,iBAAiB;IACjB,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,OAAO,EAAE,CAAC,CAAA;IACxD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzC,KAAK,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC;YAChE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;YACnC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAE5C,+EAA+E;IAC/E,8EAA8E;IAC9E,+EAA+E;IAC/E,+EAA+E;IAC/E,6EAA6E;IAC7E,cAAc;IACd,MAAM,KAAK,GACT,SAAS,EAAE,YAAY,KAAK,KAAK;QACjC,CAAC,SAAS,EAAE,YAAY,KAAK,SAAS,IAAI,WAAW,CAAC,gBAAgB,KAAK,KAAK,CAAC;QAC/E,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,QAAQ,CAAA;IACd,MAAM,OAAO,GACX,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEzE,+DAA+D;IAC/D,EAAE;IACF,yEAAyE;IACzE,uEAAuE;IACvE,wEAAwE;IACxE,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAA;IAC3C,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,yBAAyB,CACxD,WAAW,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,IAAI,SAAS,EACrB,OAAO,CACR,CAAA;IAED,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAA;IAC/D,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImageDigestMap } from '../generators/compose-generator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve one `repo:tag` to its manifest digest via the GHCR HTTP API. Returns
|
|
4
|
+
* null on any failure (unpublished tag, rate limit, network error, malformed
|
|
5
|
+
* digest) — the caller falls back to the bundled digest, so a refresh is never
|
|
6
|
+
* worse than today's frozen map.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveManifestDigest(repo: string, tag: string, fetchImpl?: typeof fetch): Promise<string | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Return a fresh digest map for the active `track`: every bundled `(repo, tag)`
|
|
11
|
+
* whose tag belongs to that track is re-resolved against GHCR; any that fails to
|
|
12
|
+
* resolve keeps its bundled digest. Other tracks' entries are copied through
|
|
13
|
+
* untouched. Never throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function refreshDigestsForTrack(track: 'latest' | 'dev', base?: ImageDigestMap, fetchImpl?: typeof fetch): Promise<ImageDigestMap>;
|
|
16
|
+
//# sourceMappingURL=image-digest-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-digest-resolver.d.ts","sourceRoot":"","sources":["../../../src/services/upgrade/image-digest-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AA2BxE;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,QAAQ,GAAG,KAAK,EACvB,IAAI,GAAE,cAAiD,EACvD,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,cAAc,CAAC,CAsBzB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import bundledDigests from '../../data/image-digests.json' with { type: 'json' };
|
|
2
|
+
// The compose generator pins first-party images to a `@sha256` digest from the
|
|
3
|
+
// bundled image-digests.json, which is frozen at admin-build time. That makes
|
|
4
|
+
// `docker compose pull` a no-op — it re-pulls the exact digest already running,
|
|
5
|
+
// so services (including admin itself) can never update. This resolver refreshes
|
|
6
|
+
// those digests from GHCR at update time so a regenerated compose points at the
|
|
7
|
+
// newest published image and `docker compose pull` actually fetches it.
|
|
8
|
+
//
|
|
9
|
+
// Resolution uses the plain GHCR HTTP registry API (anonymous pull token, then
|
|
10
|
+
// the manifest's Docker-Content-Digest header) — no docker CLI dependency, and
|
|
11
|
+
// fully mockable in tests. Multi-arch repos publish a manifest LIST whose
|
|
12
|
+
// top-level digest covers every arch, so one pinned digest works cross-arch.
|
|
13
|
+
const REGISTRY_HOST = 'ghcr.io';
|
|
14
|
+
const REGISTRY_NAMESPACE = 'alexberardi';
|
|
15
|
+
const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
16
|
+
const TIMEOUT_MS = 15_000;
|
|
17
|
+
const MANIFEST_ACCEPT = [
|
|
18
|
+
'application/vnd.oci.image.index.v1+json',
|
|
19
|
+
'application/vnd.docker.distribution.manifest.list.v2+json',
|
|
20
|
+
'application/vnd.oci.image.manifest.v1+json',
|
|
21
|
+
'application/vnd.docker.distribution.manifest.v2+json',
|
|
22
|
+
].join(', ');
|
|
23
|
+
/**
|
|
24
|
+
* Resolve one `repo:tag` to its manifest digest via the GHCR HTTP API. Returns
|
|
25
|
+
* null on any failure (unpublished tag, rate limit, network error, malformed
|
|
26
|
+
* digest) — the caller falls back to the bundled digest, so a refresh is never
|
|
27
|
+
* worse than today's frozen map.
|
|
28
|
+
*/
|
|
29
|
+
export async function resolveManifestDigest(repo, tag, fetchImpl = fetch) {
|
|
30
|
+
try {
|
|
31
|
+
const tokenRes = await fetchImpl(`https://${REGISTRY_HOST}/token?service=${REGISTRY_HOST}&scope=repository:${REGISTRY_NAMESPACE}/${repo}:pull`, { signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
32
|
+
if (!tokenRes.ok)
|
|
33
|
+
return null;
|
|
34
|
+
const token = (await tokenRes.json()).token;
|
|
35
|
+
if (!token)
|
|
36
|
+
return null;
|
|
37
|
+
const manifestRes = await fetchImpl(`https://${REGISTRY_HOST}/v2/${REGISTRY_NAMESPACE}/${repo}/manifests/${tag}`, {
|
|
38
|
+
method: 'HEAD',
|
|
39
|
+
headers: { Authorization: `Bearer ${token}`, Accept: MANIFEST_ACCEPT },
|
|
40
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
41
|
+
});
|
|
42
|
+
if (!manifestRes.ok)
|
|
43
|
+
return null;
|
|
44
|
+
const digest = manifestRes.headers.get('docker-content-digest');
|
|
45
|
+
return digest && DIGEST_RE.test(digest) ? digest : null;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Return a fresh digest map for the active `track`: every bundled `(repo, tag)`
|
|
53
|
+
* whose tag belongs to that track is re-resolved against GHCR; any that fails to
|
|
54
|
+
* resolve keeps its bundled digest. Other tracks' entries are copied through
|
|
55
|
+
* untouched. Never throws.
|
|
56
|
+
*/
|
|
57
|
+
export async function refreshDigestsForTrack(track, base = bundledDigests, fetchImpl = fetch) {
|
|
58
|
+
const result = {};
|
|
59
|
+
const jobs = [];
|
|
60
|
+
for (const [repo, tags] of Object.entries(base)) {
|
|
61
|
+
result[repo] = { ...tags };
|
|
62
|
+
for (const tag of Object.keys(tags)) {
|
|
63
|
+
// Only the active track is used by the generator (the other track's pins
|
|
64
|
+
// are dead weight), so don't spend network calls resolving it.
|
|
65
|
+
if (tag !== track && !tag.startsWith(`${track}-`))
|
|
66
|
+
continue;
|
|
67
|
+
// Resolve concurrently. Sequential await-per-tag made a refresh cost the
|
|
68
|
+
// SUM of ~17 round-trips — seconds per upgrade, and it blew unit-test
|
|
69
|
+
// timeouts under load. resolveManifestDigest self-contains its errors +
|
|
70
|
+
// timeout (returns null), so Promise.all never rejects.
|
|
71
|
+
jobs.push(resolveManifestDigest(repo, tag, fetchImpl).then((fresh) => {
|
|
72
|
+
if (fresh)
|
|
73
|
+
result[repo][tag] = fresh;
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
await Promise.all(jobs);
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=image-digest-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-digest-resolver.js","sourceRoot":"","sources":["../../../src/services/upgrade/image-digest-resolver.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"}
|