@serfab/cadre-host 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +296 -101
- package/dist/auth/trust-circle.d.ts +44 -6
- package/dist/auth/trust-circle.js +115 -58
- package/dist/auth/trust-circle.js.map +1 -1
- package/dist/auth/types.d.ts +4 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/authority/authority-node-client.d.ts +77 -0
- package/dist/authority/authority-node-client.js +143 -0
- package/dist/authority/authority-node-client.js.map +1 -0
- package/dist/authority/index.d.ts +11 -0
- package/dist/authority/index.js +11 -0
- package/dist/authority/index.js.map +1 -0
- package/dist/bin/host.js +210 -97
- package/dist/bin/host.js.map +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/installer/browser.js +16 -17
- package/dist/installer/browser.js.map +1 -1
- package/dist/installer/config.d.ts +25 -0
- package/dist/installer/config.js +1 -1
- package/dist/installer/config.js.map +1 -1
- package/dist/installer/index.d.ts +5 -2
- package/dist/installer/index.js +14 -10
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/service-host/launchd.js +1 -1
- package/dist/installer/service-host/launchd.js.map +1 -1
- package/dist/installer/service-host/systemd.js +1 -1
- package/dist/installer/service-host/systemd.js.map +1 -1
- package/dist/nat/index.d.ts +1 -1
- package/dist/nat/nat-service.d.ts +45 -3
- package/dist/nat/nat-service.js +116 -3
- package/dist/nat/nat-service.js.map +1 -1
- package/dist/nat/secrets/index.d.ts +7 -0
- package/dist/nat/secrets/index.js +28 -2
- package/dist/nat/secrets/index.js.map +1 -1
- package/dist/nat/types.d.ts +3 -1
- package/dist/nat/types.js.map +1 -1
- package/dist/orchestrator/host-process-orchestrator.d.ts +60 -1
- package/dist/orchestrator/host-process-orchestrator.js +246 -39
- package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
- package/dist/orchestrator/index.d.ts +3 -2
- package/dist/orchestrator/index.js +1 -1
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/state-store.d.ts +6 -5
- package/dist/orchestrator/state-store.js +10 -2
- package/dist/orchestrator/state-store.js.map +1 -1
- package/dist/orchestrator/types.d.ts +45 -10
- package/dist/orchestrator/types.js.map +1 -1
- package/dist/push/index.d.ts +67 -0
- package/dist/push/index.js +101 -0
- package/dist/push/index.js.map +1 -0
- package/dist/server/error-handler.d.ts +2 -0
- package/dist/server/error-handler.js +4 -0
- package/dist/server/error-handler.js.map +1 -1
- package/dist/server/routes/nodes.d.ts +4 -3
- package/dist/server/routes/nodes.js +38 -24
- package/dist/server/routes/nodes.js.map +1 -1
- package/dist/server/static.d.ts +12 -0
- package/dist/server/static.js +24 -7
- package/dist/server/static.js.map +1 -1
- package/dist/ui/assets/index-BlMXQPSw.js +14 -0
- package/dist/ui/assets/{index-C9uChk2P.js.map → index-BlMXQPSw.js.map} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/update/apply.d.ts +23 -1
- package/dist/update/apply.js +46 -4
- package/dist/update/apply.js.map +1 -1
- package/dist/update/index.d.ts +14 -3
- package/dist/update/index.js +35 -2
- package/dist/update/index.js.map +1 -1
- package/dist/update/manifest.d.ts +28 -9
- package/dist/update/manifest.js +56 -29
- package/dist/update/manifest.js.map +1 -1
- package/dist/update/release-key.d.ts +18 -7
- package/dist/update/release-key.js +28 -15
- package/dist/update/release-key.js.map +1 -1
- package/dist/update/sign.d.ts +46 -0
- package/dist/update/sign.js +53 -0
- package/dist/update/sign.js.map +1 -0
- package/package.json +9 -4
- package/service/README.md +95 -86
- package/src/__tests__/cli-invite.smoke.test.ts +6 -1
- package/src/__tests__/cli-nat.smoke.test.ts +6 -1
- package/src/__tests__/cli.smoke.test.ts +6 -1
- package/src/__tests__/host-authority.smoke.test.ts +123 -0
- package/src/__tests__/orchestrator-authority.test.ts +198 -0
- package/src/__tests__/orchestrator-push.test.ts +145 -0
- package/src/auth/__tests__/trust-circle-integration.test.ts +40 -21
- package/src/auth/__tests__/trust-circle.test.ts +90 -23
- package/src/auth/trust-circle.ts +363 -304
- package/src/auth/types.ts +4 -1
- package/src/authority/__tests__/authority-node-client.test.ts +166 -0
- package/src/authority/authority-node-client.ts +199 -0
- package/src/authority/index.ts +12 -0
- package/src/bin/host.ts +1038 -905
- package/src/index.ts +34 -3
- package/src/installer/__tests__/installer.smoke.test.ts +64 -0
- package/src/installer/browser.ts +40 -42
- package/src/installer/config.ts +27 -1
- package/src/installer/index.ts +18 -12
- package/src/installer/service-host/launchd.ts +1 -1
- package/src/installer/service-host/systemd.ts +1 -1
- package/src/nat/__tests__/ddns-updater.test.ts +1 -1
- package/src/nat/__tests__/nat-service.test.ts +192 -0
- package/src/nat/__tests__/port-mapper.test.ts +1 -1
- package/src/nat/__tests__/secrets.test.ts +23 -1
- package/src/nat/index.ts +1 -1
- package/src/nat/nat-service.ts +131 -5
- package/src/nat/secrets/index.ts +32 -2
- package/src/nat/types.ts +3 -1
- package/src/orchestrator/host-process-orchestrator.ts +294 -54
- package/src/orchestrator/index.ts +9 -2
- package/src/orchestrator/state-store.ts +21 -3
- package/src/orchestrator/types.ts +48 -2
- package/src/push/__tests__/push.test.ts +90 -0
- package/src/push/index.ts +146 -0
- package/src/server/__tests__/error-handler.test.ts +4 -4
- package/src/server/__tests__/nodes-route.test.ts +90 -10
- package/src/server/__tests__/publishers.test.ts +1 -1
- package/src/server/__tests__/static.test.ts +145 -0
- package/src/server/__tests__/status-route.test.ts +2 -2
- package/src/server/error-handler.ts +4 -0
- package/src/server/routes/nodes.ts +48 -26
- package/src/server/static.ts +24 -8
- package/src/update/__tests__/apply.test.ts +58 -1
- package/src/update/__tests__/manifest.test.ts +41 -6
- package/src/update/__tests__/release-key.test.ts +29 -0
- package/src/update/__tests__/sign.test.ts +78 -0
- package/src/update/__tests__/update-service.integration.test.ts +44 -9
- package/src/update/apply.ts +46 -4
- package/src/update/index.ts +41 -3
- package/src/update/manifest.ts +214 -172
- package/src/update/release-key.ts +30 -16
- package/src/update/sign.ts +74 -0
- package/dist/ui/assets/index-C9uChk2P.js +0 -14
package/dist/ui/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="color-scheme" content="light dark" />
|
|
7
7
|
<title>cadre-host</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BlMXQPSw.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-BwU5mJGF.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/update/apply.d.ts
CHANGED
|
@@ -33,5 +33,27 @@ export interface ApplyOptions {
|
|
|
33
33
|
* success but restart failure, returns a result with the restart error set.
|
|
34
34
|
*/
|
|
35
35
|
export declare function applyUpdate(opts: ApplyOptions): Promise<UpdateApplyResult>;
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Default executor: spawn `npm` with the given args. Adds a hard timeout.
|
|
38
|
+
*
|
|
39
|
+
* On Windows, npm ships as `npm.cmd` (a batch file). CreateProcess can't run
|
|
40
|
+
* batch files directly, so a shell is required — but Node's DEP0190 warns
|
|
41
|
+
* against `spawn(cmd, args, { shell: true })` because args are concatenated
|
|
42
|
+
* (not escaped) into the resulting command line. To dodge the deprecation we
|
|
43
|
+
* pre-quote each arg ourselves and pass the result as a single command string
|
|
44
|
+
* with an empty args array. Inputs come from a signed manifest after
|
|
45
|
+
* regex-validated package + semver checks, so injection surface is minimal;
|
|
46
|
+
* quoting is defense in depth.
|
|
47
|
+
*/
|
|
37
48
|
export declare function defaultNpmExecutor(timeoutMs: number): NpmExecutor;
|
|
49
|
+
/**
|
|
50
|
+
* Build the `(command, args, shell)` triple passed to `spawn`. Exported for
|
|
51
|
+
* tests — the spawn shape differs per platform and the quoting matters.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildNpmSpawnSpec(args: string[]): {
|
|
54
|
+
command: string;
|
|
55
|
+
args: string[];
|
|
56
|
+
shell: boolean;
|
|
57
|
+
};
|
|
58
|
+
/** cmd.exe quoting — wrap args containing whitespace or shell metachars. */
|
|
59
|
+
export declare function quoteWindowsArg(arg: string): string;
|
package/dist/update/apply.js
CHANGED
|
@@ -72,12 +72,25 @@ async function tryRollback(pkg, fromVersion, executor) {
|
|
|
72
72
|
return `npm install threw: ${err.message}`;
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Default executor: spawn `npm` with the given args. Adds a hard timeout.
|
|
77
|
+
*
|
|
78
|
+
* On Windows, npm ships as `npm.cmd` (a batch file). CreateProcess can't run
|
|
79
|
+
* batch files directly, so a shell is required — but Node's DEP0190 warns
|
|
80
|
+
* against `spawn(cmd, args, { shell: true })` because args are concatenated
|
|
81
|
+
* (not escaped) into the resulting command line. To dodge the deprecation we
|
|
82
|
+
* pre-quote each arg ourselves and pass the result as a single command string
|
|
83
|
+
* with an empty args array. Inputs come from a signed manifest after
|
|
84
|
+
* regex-validated package + semver checks, so injection surface is minimal;
|
|
85
|
+
* quoting is defense in depth.
|
|
86
|
+
*/
|
|
76
87
|
export function defaultNpmExecutor(timeoutMs) {
|
|
77
88
|
return (args) => new Promise((resolveExec) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
const spawnSpec = buildNpmSpawnSpec(args);
|
|
90
|
+
const child = spawn(spawnSpec.command, spawnSpec.args, {
|
|
91
|
+
shell: spawnSpec.shell,
|
|
92
|
+
windowsHide: true,
|
|
93
|
+
});
|
|
81
94
|
let stdout = '';
|
|
82
95
|
let stderr = '';
|
|
83
96
|
child.stdout?.on('data', (chunk) => { stdout += String(chunk); });
|
|
@@ -96,6 +109,35 @@ export function defaultNpmExecutor(timeoutMs) {
|
|
|
96
109
|
});
|
|
97
110
|
});
|
|
98
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Build the `(command, args, shell)` triple passed to `spawn`. Exported for
|
|
114
|
+
* tests — the spawn shape differs per platform and the quoting matters.
|
|
115
|
+
*/
|
|
116
|
+
export function buildNpmSpawnSpec(args) {
|
|
117
|
+
if (process.platform === 'win32') {
|
|
118
|
+
const commandLine = ['npm', ...args.map(quoteWindowsArg)].join(' ');
|
|
119
|
+
return { command: commandLine, args: [], shell: true };
|
|
120
|
+
}
|
|
121
|
+
return { command: 'npm', args, shell: false };
|
|
122
|
+
}
|
|
123
|
+
/** cmd.exe quoting — wrap args containing whitespace or shell metachars. */
|
|
124
|
+
export function quoteWindowsArg(arg) {
|
|
125
|
+
// \x00 is an intentional security guard: reject NUL/CR/LF in args before they
|
|
126
|
+
// reach the cmd.exe command line. The control char is the point of the check.
|
|
127
|
+
// eslint-disable-next-line no-control-regex
|
|
128
|
+
if (/[\x00\r\n]/.test(arg)) {
|
|
129
|
+
throw new Error('refusing to spawn npm with control character in argument');
|
|
130
|
+
}
|
|
131
|
+
if (arg.length === 0)
|
|
132
|
+
return '""';
|
|
133
|
+
if (!/[\s"&|<>^()%!]/.test(arg))
|
|
134
|
+
return arg;
|
|
135
|
+
// Escape backslashes preceding a quote per MSVCRT/cmd rules, then double the
|
|
136
|
+
// quote itself (the cmd-friendly form rather than backslash-quote).
|
|
137
|
+
const escaped = arg.replace(/(\\*)"/g, (_m, slashes) => slashes + slashes + '\\"');
|
|
138
|
+
const trailing = escaped.replace(/(\\*)$/, (_m, slashes) => slashes + slashes);
|
|
139
|
+
return `"${trailing}"`;
|
|
140
|
+
}
|
|
99
141
|
function tail(s, n) {
|
|
100
142
|
return s.length <= n ? s : '…' + s.slice(-n);
|
|
101
143
|
}
|
package/dist/update/apply.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/update/apply.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/update/apply.ts"],"names":[],"mappings":"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"}
|
package/dist/update/index.d.ts
CHANGED
|
@@ -57,6 +57,16 @@ export declare class UpdateService {
|
|
|
57
57
|
/** Persisted settings changes are bubbled out via this callback (wired in cadre-host start). */
|
|
58
58
|
private onSettingsChange?;
|
|
59
59
|
constructor(opts: UpdateServiceOptions);
|
|
60
|
+
/**
|
|
61
|
+
* If `update-state.json` still records an in-flight apply at construction
|
|
62
|
+
* time, the previous cadre-host process died mid-apply (OOM, power loss,
|
|
63
|
+
* sigkill). Without intervention, every subsequent `apply()` would short-
|
|
64
|
+
* circuit on `apply_in_progress` forever. We clear the marker and surface a
|
|
65
|
+
* `lastError` so the UI banner can flag that an apply was interrupted —
|
|
66
|
+
* the npm install may or may not have completed, so the operator should
|
|
67
|
+
* verify with `npm ls -g`.
|
|
68
|
+
*/
|
|
69
|
+
private recoverInterruptedApply;
|
|
60
70
|
/** Read the persisted state for UI consumption. */
|
|
61
71
|
getState(): Promise<UpdateState>;
|
|
62
72
|
/** Current settings (in-memory). */
|
|
@@ -92,10 +102,11 @@ export declare class UpdateService {
|
|
|
92
102
|
* `createNatHandlers`. The local-UI ticket consumes these.
|
|
93
103
|
*/
|
|
94
104
|
export declare function createUpdateHandlers(service: UpdateService): UpdateHandlers;
|
|
95
|
-
export type { UpdateState, UpdateApplyResult, UpdateSettings, UpdateManifest } from './types.js';
|
|
105
|
+
export type { UpdateState, UpdateApplyResult, UpdateSettings, UpdateManifest, SignedManifest } from './types.js';
|
|
96
106
|
export { UpdateErrorException, type UpdateErrorCode } from './types.js';
|
|
97
107
|
export { compareVersions, parseVersion } from './version.js';
|
|
98
|
-
export { fetchManifest, verifyManifest, canonicalJson,
|
|
108
|
+
export { fetchManifest, verifyManifest, canonicalJson, signManifest, validateManifestFields } from './manifest.js';
|
|
99
109
|
export { UpdateStateStore } from './store.js';
|
|
100
110
|
export { applyUpdate, defaultNpmExecutor, type NpmExecutor, type ServiceRestarter } from './apply.js';
|
|
101
|
-
export { getReleasePublicKey, getReleasePublicKeyBase64, ed25519FromRaw } from './release-key.js';
|
|
111
|
+
export { getReleasePublicKey, getReleasePublicKeyBase64, ed25519FromRaw, isPlaceholderReleaseKey, } from './release-key.js';
|
|
112
|
+
export { buildManifest, derivePublicKeyBase64, signAndSelfVerify, type ManifestFields } from './sign.js';
|
package/dist/update/index.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import debug from 'debug';
|
|
14
14
|
import { applyUpdate, defaultNpmExecutor, } from './apply.js';
|
|
15
15
|
import { DEFAULT_MANIFEST_URL, fetchManifest, } from './manifest.js';
|
|
16
|
+
import { isPlaceholderReleaseKey } from './release-key.js';
|
|
16
17
|
import { UpdateStateStore } from './store.js';
|
|
17
18
|
import { UpdateErrorException, } from './types.js';
|
|
18
19
|
import { compareVersions } from './version.js';
|
|
@@ -32,6 +33,31 @@ export class UpdateService {
|
|
|
32
33
|
this.checkIntervalMs = opts.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
|
|
33
34
|
this.settings = opts.settings ?? { autoApply: false };
|
|
34
35
|
this.manifestUrl = resolveManifestUrl(opts.manifestUrl, this.settings.manifestUrl);
|
|
36
|
+
this.recoverInterruptedApply();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* If `update-state.json` still records an in-flight apply at construction
|
|
40
|
+
* time, the previous cadre-host process died mid-apply (OOM, power loss,
|
|
41
|
+
* sigkill). Without intervention, every subsequent `apply()` would short-
|
|
42
|
+
* circuit on `apply_in_progress` forever. We clear the marker and surface a
|
|
43
|
+
* `lastError` so the UI banner can flag that an apply was interrupted —
|
|
44
|
+
* the npm install may or may not have completed, so the operator should
|
|
45
|
+
* verify with `npm ls -g`.
|
|
46
|
+
*/
|
|
47
|
+
recoverInterruptedApply() {
|
|
48
|
+
const state = this.store.load();
|
|
49
|
+
if (!state.applyInProgress)
|
|
50
|
+
return;
|
|
51
|
+
const { fromVersion, toVersion } = state.applyInProgress;
|
|
52
|
+
log('clearing stale applyInProgress (%s → %s); previous apply was interrupted', fromVersion, toVersion);
|
|
53
|
+
this.store.update({
|
|
54
|
+
applyInProgress: undefined,
|
|
55
|
+
lastError: {
|
|
56
|
+
code: 'apply_failed',
|
|
57
|
+
message: `previous apply (${fromVersion} → ${toVersion}) was interrupted (cadre-host restarted before it completed); the install may or may not have succeeded — verify with 'npm ls -g'`,
|
|
58
|
+
at: new Date().toISOString(),
|
|
59
|
+
},
|
|
60
|
+
});
|
|
35
61
|
}
|
|
36
62
|
/** Read the persisted state for UI consumption. */
|
|
37
63
|
async getState() {
|
|
@@ -64,6 +90,12 @@ export class UpdateService {
|
|
|
64
90
|
* debug; signature failures are recorded as `lastError` so the UI can warn.
|
|
65
91
|
*/
|
|
66
92
|
async check() {
|
|
93
|
+
if (isPlaceholderReleaseKey()) {
|
|
94
|
+
// A build that shipped the all-zeros placeholder rejects every authentic
|
|
95
|
+
// manifest as signature_invalid; surface that here so it's diagnosable
|
|
96
|
+
// from logs rather than only as an opaque verification failure.
|
|
97
|
+
log('release verification key is the all-zeros placeholder; production manifests will fail signature_invalid (set CADRE_HOST_UPDATE_DEV_KEY for dev/CI only)');
|
|
98
|
+
}
|
|
67
99
|
let manifest;
|
|
68
100
|
try {
|
|
69
101
|
manifest = await fetchManifest({
|
|
@@ -221,8 +253,9 @@ function resolveManifestUrl(explicit, fromSettings) {
|
|
|
221
253
|
}
|
|
222
254
|
export { UpdateErrorException } from './types.js';
|
|
223
255
|
export { compareVersions, parseVersion } from './version.js';
|
|
224
|
-
export { fetchManifest, verifyManifest, canonicalJson,
|
|
256
|
+
export { fetchManifest, verifyManifest, canonicalJson, signManifest, validateManifestFields } from './manifest.js';
|
|
225
257
|
export { UpdateStateStore } from './store.js';
|
|
226
258
|
export { applyUpdate, defaultNpmExecutor } from './apply.js';
|
|
227
|
-
export { getReleasePublicKey, getReleasePublicKeyBase64, ed25519FromRaw } from './release-key.js';
|
|
259
|
+
export { getReleasePublicKey, getReleasePublicKeyBase64, ed25519FromRaw, isPlaceholderReleaseKey, } from './release-key.js';
|
|
260
|
+
export { buildManifest, derivePublicKeyBase64, signAndSelfVerify } from './sign.js';
|
|
228
261
|
//# sourceMappingURL=index.js.map
|
package/dist/update/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/update/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,WAAW,EACX,kBAAkB,GAGnB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,oBAAoB,GAKrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,GAAG,GAAG,KAAK,CAAC,2BAA2B,CAAC,CAAC;AAE/C,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACtD,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AA+B7C,MAAM,OAAO,aAAa;IAiBxB,YAAY,IAA0B;QAN9B,UAAK,GAA0C,IAAI,CAAC;QACpD,aAAQ,GAAG,KAAK,CAAC;QAMvB,IAAI,CAAC,KAAK,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,sBAAsB,CAAC;QAChE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7E,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,yBAAyB,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACtD,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/update/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* detached Ed25519 signature of `canonicalJson(manifest)`. cadre-host only
|
|
6
6
|
* trusts manifests whose signature matches the embedded release public key.
|
|
7
7
|
*
|
|
8
|
-
* Canonical serialization is
|
|
9
|
-
*
|
|
10
|
-
* the shape is fixed (`UpdateManifest`).
|
|
8
|
+
* Canonical serialization (`canonicalJson`) is shared from `@serfab/cadre-core`
|
|
9
|
+
* so the seed-signing path and this manifest-signing path agree on the signed
|
|
10
|
+
* byte representation; the shape we sign here is fixed (`UpdateManifest`).
|
|
11
11
|
*/
|
|
12
12
|
import { type KeyObject } from 'node:crypto';
|
|
13
13
|
import { ed25519FromRaw } from './release-key.js';
|
|
@@ -34,15 +34,34 @@ export declare function fetchManifest(opts: FetchManifestOptions): Promise<Updat
|
|
|
34
34
|
* exercise this directly.
|
|
35
35
|
*/
|
|
36
36
|
export declare function verifyManifest(body: unknown, env?: NodeJS.ProcessEnv): UpdateManifest;
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Sign a manifest with the release private key, producing the `{ manifest, sig }`
|
|
39
|
+
* envelope published as `latest.json`. This is the production signing operation:
|
|
40
|
+
* it canonicalizes with the same `canonicalJson` that `verifyManifest` consumes
|
|
41
|
+
* and emits a detached `ed25519:<base64>` signature. The private key never ships
|
|
42
|
+
* in the binary — signing runs offline on the release operator's machine (see
|
|
43
|
+
* `scripts/sign-manifest.mjs`).
|
|
44
|
+
*/
|
|
45
|
+
export declare function signManifest(manifest: UpdateManifest, privateKey: KeyObject): SignedManifest;
|
|
39
46
|
/** Used by `apply.ts` to detect which key the signer matches. */
|
|
40
47
|
export declare function publicKeyMatchesEmbedded(rawBase64: string, env?: NodeJS.ProcessEnv): boolean;
|
|
41
48
|
/** Wrapper for `getReleasePublicKey`, re-exported for parity with `ed25519FromRaw`. */
|
|
42
49
|
export { ed25519FromRaw };
|
|
43
50
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
51
|
+
* Field-level validation that goes beyond the structural `isUpdateManifest`
|
|
52
|
+
* type guard: enforces semver on version strings, ISO-8601 round-tripping on
|
|
53
|
+
* the publish timestamp, and the npm naming regex on the package name. A
|
|
54
|
+
* signed-but-malformed manifest would otherwise surface as a confusing
|
|
55
|
+
* `compareVersions` throw further downstream.
|
|
56
|
+
*
|
|
57
|
+
* Exported so the offline signing tool (`sign.ts` / `sign-manifest.mjs`) runs
|
|
58
|
+
* the *exact same* rules before it signs — the signer can never emit a
|
|
59
|
+
* manifest that `verifyManifest` would later reject as `manifest_invalid`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateManifestFields(m: UpdateManifest): void;
|
|
62
|
+
/**
|
|
63
|
+
* Canonical JSON serializer used to define the signed byte representation.
|
|
64
|
+
* The implementation lives in `@serfab/cadre-core` (cadre-host depends on
|
|
65
|
+
* cadre-core); re-exported here so existing import sites stay stable.
|
|
47
66
|
*/
|
|
48
|
-
export
|
|
67
|
+
export { canonicalJson } from '@serfab/cadre-core';
|
package/dist/update/manifest.js
CHANGED
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
* detached Ed25519 signature of `canonicalJson(manifest)`. cadre-host only
|
|
6
6
|
* trusts manifests whose signature matches the embedded release public key.
|
|
7
7
|
*
|
|
8
|
-
* Canonical serialization is
|
|
9
|
-
*
|
|
10
|
-
* the shape is fixed (`UpdateManifest`).
|
|
8
|
+
* Canonical serialization (`canonicalJson`) is shared from `@serfab/cadre-core`
|
|
9
|
+
* so the seed-signing path and this manifest-signing path agree on the signed
|
|
10
|
+
* byte representation; the shape we sign here is fixed (`UpdateManifest`).
|
|
11
11
|
*/
|
|
12
12
|
import { sign as cryptoSign, verify as cryptoVerify } from 'node:crypto';
|
|
13
|
+
import { canonicalJson } from '@serfab/cadre-core';
|
|
13
14
|
import { ed25519FromRaw, getReleasePublicKey, getReleasePublicKeyBase64 } from './release-key.js';
|
|
14
15
|
import { UpdateErrorException, } from './types.js';
|
|
16
|
+
import { parseVersion } from './version.js';
|
|
17
|
+
/** npm package naming rule — slightly looser than the official one (we don't enforce length here other than the 214-char total). */
|
|
18
|
+
const NPM_PACKAGE_NAME_RE = /^(?:@[a-z0-9-_.]+\/)?[a-z0-9-_.]+$/;
|
|
15
19
|
/** Default release-manifest URL. Overridable via env var on the caller. */
|
|
16
20
|
export const DEFAULT_MANIFEST_URL = 'https://releases.serfab.io/cadre-host/latest.json';
|
|
17
21
|
/**
|
|
@@ -57,6 +61,7 @@ export function verifyManifest(body, env = process.env) {
|
|
|
57
61
|
if (!isUpdateManifest(body.manifest)) {
|
|
58
62
|
throw new UpdateErrorException('manifest_invalid', 'manifest payload is missing required fields');
|
|
59
63
|
}
|
|
64
|
+
validateManifestFields(body.manifest);
|
|
60
65
|
const sig = parseSignature(body.sig);
|
|
61
66
|
const canonical = Buffer.from(canonicalJson(body.manifest), 'utf8');
|
|
62
67
|
const key = getReleasePublicKey(env);
|
|
@@ -72,8 +77,15 @@ export function verifyManifest(body, env = process.env) {
|
|
|
72
77
|
}
|
|
73
78
|
return body.manifest;
|
|
74
79
|
}
|
|
75
|
-
/**
|
|
76
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Sign a manifest with the release private key, producing the `{ manifest, sig }`
|
|
82
|
+
* envelope published as `latest.json`. This is the production signing operation:
|
|
83
|
+
* it canonicalizes with the same `canonicalJson` that `verifyManifest` consumes
|
|
84
|
+
* and emits a detached `ed25519:<base64>` signature. The private key never ships
|
|
85
|
+
* in the binary — signing runs offline on the release operator's machine (see
|
|
86
|
+
* `scripts/sign-manifest.mjs`).
|
|
87
|
+
*/
|
|
88
|
+
export function signManifest(manifest, privateKey) {
|
|
77
89
|
const canonical = Buffer.from(canonicalJson(manifest), 'utf8');
|
|
78
90
|
const sig = cryptoSign(null, canonical, privateKey).toString('base64');
|
|
79
91
|
return { manifest, sig: `ed25519:${sig}` };
|
|
@@ -102,6 +114,41 @@ function isSignedManifest(v) {
|
|
|
102
114
|
const obj = v;
|
|
103
115
|
return typeof obj.sig === 'string' && obj.manifest !== undefined && typeof obj.manifest === 'object';
|
|
104
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Field-level validation that goes beyond the structural `isUpdateManifest`
|
|
119
|
+
* type guard: enforces semver on version strings, ISO-8601 round-tripping on
|
|
120
|
+
* the publish timestamp, and the npm naming regex on the package name. A
|
|
121
|
+
* signed-but-malformed manifest would otherwise surface as a confusing
|
|
122
|
+
* `compareVersions` throw further downstream.
|
|
123
|
+
*
|
|
124
|
+
* Exported so the offline signing tool (`sign.ts` / `sign-manifest.mjs`) runs
|
|
125
|
+
* the *exact same* rules before it signs — the signer can never emit a
|
|
126
|
+
* manifest that `verifyManifest` would later reject as `manifest_invalid`.
|
|
127
|
+
*/
|
|
128
|
+
export function validateManifestFields(m) {
|
|
129
|
+
try {
|
|
130
|
+
parseVersion(m.version);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
throw new UpdateErrorException('manifest_invalid', `manifest version "${m.version}" is not a valid semver: ${err.message}`);
|
|
134
|
+
}
|
|
135
|
+
if (m.minPreviousVersion !== undefined) {
|
|
136
|
+
try {
|
|
137
|
+
parseVersion(m.minPreviousVersion);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
throw new UpdateErrorException('manifest_invalid', `manifest minPreviousVersion "${m.minPreviousVersion}" is not a valid semver: ${err.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const parsed = new Date(m.publishedAt);
|
|
144
|
+
if (Number.isNaN(parsed.getTime()) || parsed.toISOString() !== m.publishedAt) {
|
|
145
|
+
throw new UpdateErrorException('manifest_invalid', `manifest publishedAt "${m.publishedAt}" is not a round-trippable ISO-8601 string`);
|
|
146
|
+
}
|
|
147
|
+
const pkg = m.channels.npm.package;
|
|
148
|
+
if (!NPM_PACKAGE_NAME_RE.test(pkg) || pkg.length > 214) {
|
|
149
|
+
throw new UpdateErrorException('manifest_invalid', `manifest channels.npm.package "${pkg}" is not a valid npm package name`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
105
152
|
function isUpdateManifest(v) {
|
|
106
153
|
if (!v || typeof v !== 'object')
|
|
107
154
|
return false;
|
|
@@ -124,29 +171,9 @@ function isUpdateManifest(v) {
|
|
|
124
171
|
return true;
|
|
125
172
|
}
|
|
126
173
|
/**
|
|
127
|
-
* Canonical JSON
|
|
128
|
-
*
|
|
129
|
-
*
|
|
174
|
+
* Canonical JSON serializer used to define the signed byte representation.
|
|
175
|
+
* The implementation lives in `@serfab/cadre-core` (cadre-host depends on
|
|
176
|
+
* cadre-core); re-exported here so existing import sites stay stable.
|
|
130
177
|
*/
|
|
131
|
-
export
|
|
132
|
-
if (value === null)
|
|
133
|
-
return 'null';
|
|
134
|
-
if (typeof value === 'number') {
|
|
135
|
-
if (!Number.isFinite(value))
|
|
136
|
-
throw new Error('cannot serialize non-finite number');
|
|
137
|
-
return JSON.stringify(value);
|
|
138
|
-
}
|
|
139
|
-
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
140
|
-
return JSON.stringify(value);
|
|
141
|
-
}
|
|
142
|
-
if (Array.isArray(value)) {
|
|
143
|
-
return '[' + value.map((v) => canonicalJson(v)).join(',') + ']';
|
|
144
|
-
}
|
|
145
|
-
if (typeof value === 'object') {
|
|
146
|
-
const obj = value;
|
|
147
|
-
const keys = Object.keys(obj).filter((k) => obj[k] !== undefined).sort();
|
|
148
|
-
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(obj[k])).join(',') + '}';
|
|
149
|
-
}
|
|
150
|
-
throw new Error(`cannot serialize value of type ${typeof value}`);
|
|
151
|
-
}
|
|
178
|
+
export { canonicalJson } from '@serfab/cadre-core';
|
|
152
179
|
//# sourceMappingURL=manifest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/update/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,IAAI,YAAY,EAAkB,MAAM,aAAa,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EACL,oBAAoB,GAGrB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/update/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
* Production Ed25519 public key used to verify the update manifest.
|
|
3
3
|
*
|
|
4
4
|
* The signing key lives offline with the release operator; only the public
|
|
5
|
-
* half ever ships in the binary.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* by the release build. CI keys differ from prod keys; for dev/CI overrides
|
|
10
|
-
* see `CADRE_HOST_UPDATE_DEV_KEY`.
|
|
5
|
+
* half ever ships in the binary. The release operator generates the keypair
|
|
6
|
+
* and embeds the public half with `scripts/release-keygen.mjs --write-source`;
|
|
7
|
+
* see the "Release signing & key management" runbook in `docs/cadre-host.md`.
|
|
8
|
+
* For dev/CI/staging overrides see `CADRE_HOST_UPDATE_DEV_KEY`.
|
|
11
9
|
*/
|
|
12
|
-
import { KeyObject } from 'node:crypto';
|
|
10
|
+
import type { KeyObject } from 'node:crypto';
|
|
13
11
|
/**
|
|
14
12
|
* Public key (32 raw bytes, base64) — env override beats the embedded one.
|
|
15
13
|
* Used by both production and CI smoke tests.
|
|
@@ -17,6 +15,19 @@ import { KeyObject } from 'node:crypto';
|
|
|
17
15
|
export declare function getReleasePublicKeyBase64(env?: NodeJS.ProcessEnv): string;
|
|
18
16
|
/** Lazily build the KeyObject used by `crypto.verify`. */
|
|
19
17
|
export declare function getReleasePublicKey(env?: NodeJS.ProcessEnv): KeyObject;
|
|
18
|
+
/**
|
|
19
|
+
* True when the *effective* release key (after the `CADRE_HOST_UPDATE_DEV_KEY`
|
|
20
|
+
* override) decodes to 32 zero bytes — i.e. the all-zeros placeholder that
|
|
21
|
+
* ships in source until the release operator embeds a real public key.
|
|
22
|
+
*
|
|
23
|
+
* Consumers:
|
|
24
|
+
* - the publish guard (`scripts/publish-package.js`) refuses to ship a build
|
|
25
|
+
* whose embedded key is still the placeholder, so a real release can never
|
|
26
|
+
* silently ship the dead key;
|
|
27
|
+
* - `UpdateService.check()` logs a diagnostic breadcrumb so a misbuilt binary
|
|
28
|
+
* is recognizable from logs rather than only as opaque `signature_invalid`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isPlaceholderReleaseKey(env?: NodeJS.ProcessEnv): boolean;
|
|
20
31
|
/**
|
|
21
32
|
* Build an Ed25519 KeyObject from a raw 32-byte base64 public key by wrapping
|
|
22
33
|
* it in the SubjectPublicKeyInfo DER prefix Node expects.
|
|
@@ -2,25 +2,20 @@
|
|
|
2
2
|
* Production Ed25519 public key used to verify the update manifest.
|
|
3
3
|
*
|
|
4
4
|
* The signing key lives offline with the release operator; only the public
|
|
5
|
-
* half ever ships in the binary.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* by the release build. CI keys differ from prod keys; for dev/CI overrides
|
|
10
|
-
* see `CADRE_HOST_UPDATE_DEV_KEY`.
|
|
5
|
+
* half ever ships in the binary. The release operator generates the keypair
|
|
6
|
+
* and embeds the public half with `scripts/release-keygen.mjs --write-source`;
|
|
7
|
+
* see the "Release signing & key management" runbook in `docs/cadre-host.md`.
|
|
8
|
+
* For dev/CI/staging overrides see `CADRE_HOST_UPDATE_DEV_KEY`.
|
|
11
9
|
*/
|
|
12
10
|
import { createPublicKey } from 'node:crypto';
|
|
13
11
|
/**
|
|
14
|
-
* Raw 32-byte Ed25519 public key, base64-encoded.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* The real key generation/publication procedure is tracked in the
|
|
20
|
-
* release-tooling backlog; until then, the dev override below is the only
|
|
21
|
-
* supported path for CI + local manifest testing.
|
|
12
|
+
* Raw 32-byte Ed25519 public key, base64-encoded. The all-zeros value below is
|
|
13
|
+
* the placeholder that ships in source until the release operator embeds a real
|
|
14
|
+
* key (`isPlaceholderReleaseKey` reports it; the publish guard refuses to ship
|
|
15
|
+
* it). Mismatch with the real signer surfaces as `signature_invalid`, which the
|
|
16
|
+
* UI treats as "update available but unverifiable" rather than auto-applying.
|
|
22
17
|
*/
|
|
23
|
-
const PROD_KEY_BASE64 = '
|
|
18
|
+
const PROD_KEY_BASE64 = 'XyRVnOY9DVgU6xdMgJIguOsc9B2L1o2KoU9626Nk+OE=';
|
|
24
19
|
/**
|
|
25
20
|
* Public key (32 raw bytes, base64) — env override beats the embedded one.
|
|
26
21
|
* Used by both production and CI smoke tests.
|
|
@@ -35,6 +30,24 @@ export function getReleasePublicKeyBase64(env = process.env) {
|
|
|
35
30
|
export function getReleasePublicKey(env = process.env) {
|
|
36
31
|
return ed25519FromRaw(getReleasePublicKeyBase64(env));
|
|
37
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* True when the *effective* release key (after the `CADRE_HOST_UPDATE_DEV_KEY`
|
|
35
|
+
* override) decodes to 32 zero bytes — i.e. the all-zeros placeholder that
|
|
36
|
+
* ships in source until the release operator embeds a real public key.
|
|
37
|
+
*
|
|
38
|
+
* Consumers:
|
|
39
|
+
* - the publish guard (`scripts/publish-package.js`) refuses to ship a build
|
|
40
|
+
* whose embedded key is still the placeholder, so a real release can never
|
|
41
|
+
* silently ship the dead key;
|
|
42
|
+
* - `UpdateService.check()` logs a diagnostic breadcrumb so a misbuilt binary
|
|
43
|
+
* is recognizable from logs rather than only as opaque `signature_invalid`.
|
|
44
|
+
*/
|
|
45
|
+
export function isPlaceholderReleaseKey(env = process.env) {
|
|
46
|
+
const raw = Buffer.from(getReleasePublicKeyBase64(env), 'base64');
|
|
47
|
+
if (raw.length !== 32)
|
|
48
|
+
return false;
|
|
49
|
+
return raw.every((b) => b === 0);
|
|
50
|
+
}
|
|
38
51
|
/**
|
|
39
52
|
* Build an Ed25519 KeyObject from a raw 32-byte base64 public key by wrapping
|
|
40
53
|
* it in the SubjectPublicKeyInfo DER prefix Node expects.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-key.js","sourceRoot":"","sources":["../../src/update/release-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"release-key.js","sourceRoot":"","sources":["../../src/update/release-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,eAAe,GAAG,8CAA8C,CAAC;AAEvE;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC5E,MAAM,QAAQ,GAAG,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,CAAC;IACvD,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACrD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,OAAO,cAAc,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,4CAA4C,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,0DAA0D;IAC1D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1C,OAAO,eAAe,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACrE,CAAC"}
|