@botbuddy/cli 1.61.4 → 1.61.5
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/daemon/bin/darwin-arm64/botbuddy-daemon +0 -0
- package/daemon/bin/linux-x64/botbuddy-daemon +0 -0
- package/daemon-release/darwin-arm64.json +4 -4
- package/daemon-release/linux-x64.json +4 -4
- package/daemon-release/manifest.json +5 -5
- package/package.json +1 -1
- package/src/daemon/bootstrap.mjs +47 -2
- package/src/daemon/commands.mjs +3 -0
- package/src/daemon/profile-delivery.mjs +29 -0
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.61.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.61.5",
|
|
3
|
+
"source_commit": "f53c37db06f6fc5ab544623f2a273c4e21de1b72",
|
|
4
|
+
"source_sha256": "7280c8ff78ee957cc06bc7d07ed12a4b36a4c64c3a5968a710a1d371ab1b33c9",
|
|
5
5
|
"target": "darwin-arm64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "c57ada939dcf3d5c0ad7cefdbf27ae9995a06a14446ca8774a94c76c61083b00"
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.61.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.61.5",
|
|
3
|
+
"source_commit": "f53c37db06f6fc5ab544623f2a273c4e21de1b72",
|
|
4
|
+
"source_sha256": "7280c8ff78ee957cc06bc7d07ed12a4b36a4c64c3a5968a710a1d371ab1b33c9",
|
|
5
5
|
"target": "linux-x64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "1002356a262f413e793af8779bec4208426d47bc38d6e5ef115a06b0fa4fd64c"
|
|
7
7
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"release_version": "1.61.
|
|
4
|
-
"source_commit": "
|
|
5
|
-
"source_sha256": "
|
|
3
|
+
"release_version": "1.61.5",
|
|
4
|
+
"source_commit": "f53c37db06f6fc5ab544623f2a273c4e21de1b72",
|
|
5
|
+
"source_sha256": "7280c8ff78ee957cc06bc7d07ed12a4b36a4c64c3a5968a710a1d371ab1b33c9",
|
|
6
6
|
"targets": {
|
|
7
7
|
"darwin-arm64": {
|
|
8
8
|
"goos": "darwin",
|
|
9
9
|
"goarch": "arm64",
|
|
10
10
|
"binary": "daemon/bin/darwin-arm64/botbuddy-daemon",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "c57ada939dcf3d5c0ad7cefdbf27ae9995a06a14446ca8774a94c76c61083b00",
|
|
12
12
|
"mode": "0755"
|
|
13
13
|
},
|
|
14
14
|
"linux-x64": {
|
|
15
15
|
"goos": "linux",
|
|
16
16
|
"goarch": "amd64",
|
|
17
17
|
"binary": "daemon/bin/linux-x64/botbuddy-daemon",
|
|
18
|
-
"sha256": "
|
|
18
|
+
"sha256": "1002356a262f413e793af8779bec4208426d47bc38d6e5ef115a06b0fa4fd64c",
|
|
19
19
|
"mode": "0755"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/package.json
CHANGED
package/src/daemon/bootstrap.mjs
CHANGED
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
// no local approval polling loop: host policy wakes only through the pushed
|
|
5
5
|
// BOT-2324 raw wait condition, then this flow re-registers server-side.
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
|
+
import { dirname } from "node:path";
|
|
7
8
|
|
|
8
9
|
import { DAEMON_PRODUCTION_MCP_SERVER, enrollDaemonDeviceProfileFromBootstrapIdentity } from "./enrollment.mjs";
|
|
9
10
|
import { installRemoteService, installedBinaryPath, stageRemoteDaemonRelease } from "./installer.mjs";
|
|
10
11
|
import {
|
|
11
12
|
createRemoteBootstrapIdentity,
|
|
12
13
|
deliverDaemonProfileFromBootstrapIdentityOverSSH,
|
|
14
|
+
installDaemonRuntimeConfigOverSSH,
|
|
13
15
|
inspectRemoteBootstrapIdentity,
|
|
14
16
|
verifyRemoteServiceIdentity,
|
|
15
17
|
} from "./profile-delivery.mjs";
|
|
18
|
+
import { buildRuntimeConfig } from "./runtime-config.mjs";
|
|
16
19
|
import { validateDaemonRelease } from "./release.mjs";
|
|
17
20
|
import { renderLinuxUnit, renderMacDaemon } from "./service.mjs";
|
|
18
21
|
|
|
@@ -45,7 +48,7 @@ function exactObject(value, keys) {
|
|
|
45
48
|
function checkedSpec(spec) {
|
|
46
49
|
const keys = [
|
|
47
50
|
"mode", "serverUrl", "sshHost", "serviceUser", "daemonBinary", "profilePath", "requestingHost",
|
|
48
|
-
"runtimeEngineId", "platform", "arch", "releaseRoot", "home", "config", "approvalTimeoutSeconds",
|
|
51
|
+
"runtimeEngineId", "platform", "arch", "releaseRoot", "home", "config", "hostPolicy", "approvalTimeoutSeconds",
|
|
49
52
|
];
|
|
50
53
|
const optional = ["caller", "callerHarness", "callerTicket"];
|
|
51
54
|
if (!spec || typeof spec !== "object" || Array.isArray(spec) ||
|
|
@@ -59,7 +62,11 @@ function checkedSpec(spec) {
|
|
|
59
62
|
typeof spec.requestingHost !== "string" || !spec.requestingHost || Buffer.byteLength(spec.requestingHost, "utf8") > 80 ||
|
|
60
63
|
typeof spec.runtimeEngineId !== "string" || !ENGINE_ID_RE.test(spec.runtimeEngineId) ||
|
|
61
64
|
!["darwin", "linux"].includes(spec.platform) || typeof spec.arch !== "string" || !spec.arch ||
|
|
62
|
-
!validPath(spec.releaseRoot) || !validPath(spec.home) || !validPath(spec.config) ||
|
|
65
|
+
!validPath(spec.releaseRoot) || !validPath(spec.home) || !validPath(spec.config) || !spec.config.endsWith("/daemon.json") ||
|
|
66
|
+
dirname(spec.config) !== dirname(spec.profilePath) ||
|
|
67
|
+
!spec.hostPolicy || typeof spec.hostPolicy !== "object" || Array.isArray(spec.hostPolicy) ||
|
|
68
|
+
Object.keys(spec.hostPolicy).length !== 4 ||
|
|
69
|
+
!["machineId", "dockerEndpoint", "supabaseBinary", "dockerCLI"].every((key) => typeof spec.hostPolicy[key] === "string" && spec.hostPolicy[key]) ||
|
|
63
70
|
!Number.isSafeInteger(spec.approvalTimeoutSeconds) || spec.approvalTimeoutSeconds < 1 || spec.approvalTimeoutSeconds > 3_600 ||
|
|
64
71
|
optional.some((key) => spec[key] !== undefined && (typeof spec[key] !== "string" || !spec[key]))
|
|
65
72
|
) fail("daemon_bootstrap_spec_invalid");
|
|
@@ -215,12 +222,14 @@ export async function bootstrapFreshDaemon(input, {
|
|
|
215
222
|
enroll = enrollDaemonDeviceProfileFromBootstrapIdentity,
|
|
216
223
|
deliver = deliverDaemonProfileFromBootstrapIdentityOverSSH,
|
|
217
224
|
installRemote = installRemoteService,
|
|
225
|
+
installRuntimeConfig = installDaemonRuntimeConfigOverSSH,
|
|
218
226
|
} = {}) {
|
|
219
227
|
const spec = checkedSpec(input);
|
|
220
228
|
if (typeof registerHost !== "function" || typeof verifyRemoteIdentity !== "function" ||
|
|
221
229
|
typeof createIdentity !== "function" || typeof inspectIdentity !== "function" ||
|
|
222
230
|
typeof validateRelease !== "function" || typeof stageRemote !== "function" || typeof enroll !== "function" ||
|
|
223
231
|
typeof deliver !== "function" || typeof installRemote !== "function" ||
|
|
232
|
+
typeof installRuntimeConfig !== "function" ||
|
|
224
233
|
(awaitApproval !== null && typeof awaitApproval !== "function") ||
|
|
225
234
|
(onApprovalRequired !== null && typeof onApprovalRequired !== "function") ||
|
|
226
235
|
(resumeStore !== null && (typeof resumeStore !== "object" || typeof resumeStore.save !== "function" ||
|
|
@@ -355,6 +364,42 @@ export async function bootstrapFreshDaemon(input, {
|
|
|
355
364
|
}
|
|
356
365
|
}
|
|
357
366
|
|
|
367
|
+
let runtimeConfig;
|
|
368
|
+
try {
|
|
369
|
+
runtimeConfig = buildRuntimeConfig({
|
|
370
|
+
host_key: publicIdentity.hostKey,
|
|
371
|
+
state_dir: dirname(spec.config),
|
|
372
|
+
docker_endpoint: spec.hostPolicy.dockerEndpoint,
|
|
373
|
+
expected_engine_id: spec.runtimeEngineId,
|
|
374
|
+
machine_id: spec.hostPolicy.machineId,
|
|
375
|
+
supabase_binary: spec.hostPolicy.supabaseBinary,
|
|
376
|
+
docker_cli: spec.hostPolicy.dockerCLI,
|
|
377
|
+
host_credential_profile: spec.profilePath,
|
|
378
|
+
device_consent: true,
|
|
379
|
+
runtime_version: `go-daemon/${release.releaseVersion}`,
|
|
380
|
+
runtime_git_sha: release.sourceCommit,
|
|
381
|
+
runtime_protocol_version: 2,
|
|
382
|
+
});
|
|
383
|
+
} catch {
|
|
384
|
+
fail("daemon_bootstrap_runtime_config_invalid");
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
const installed = await installRuntimeConfig({
|
|
388
|
+
config: JSON.stringify(runtimeConfig),
|
|
389
|
+
configPath: spec.config,
|
|
390
|
+
sshHost: spec.sshHost,
|
|
391
|
+
serviceUser: spec.serviceUser,
|
|
392
|
+
daemonBinary: trustedDaemonBinary,
|
|
393
|
+
profilePath: spec.profilePath,
|
|
394
|
+
expectedHostKey: publicIdentity.hostKey,
|
|
395
|
+
directInstall: remote.directInstall,
|
|
396
|
+
});
|
|
397
|
+
if (!installed || installed.installed !== true) fail("daemon_bootstrap_runtime_config_failed");
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (error instanceof DaemonBootstrapError) throw error;
|
|
400
|
+
fail("daemon_bootstrap_runtime_config_failed");
|
|
401
|
+
}
|
|
402
|
+
|
|
358
403
|
const serviceSpec = {
|
|
359
404
|
user: spec.serviceUser,
|
|
360
405
|
home: spec.home,
|
package/src/daemon/commands.mjs
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
createRemoteBootstrapIdentity,
|
|
30
30
|
deliverDaemonProfileFromBootstrapIdentityOverSSH,
|
|
31
31
|
deliverDaemonProfileFromHelperIdentityOverSSH,
|
|
32
|
+
installDaemonRuntimeConfigOverSSH,
|
|
32
33
|
inspectRemoteBootstrapIdentity,
|
|
33
34
|
verifyRemoteHelperIdentity as verifyRemoteHelperIdentityOnTarget,
|
|
34
35
|
verifyRemoteServiceIdentity,
|
|
@@ -285,6 +286,7 @@ export async function cmdDaemon(args, {
|
|
|
285
286
|
verifyRuntime = checkRuntimeConfig,
|
|
286
287
|
enroll = enrollDaemonDeviceProfileFromHelperIdentity,
|
|
287
288
|
deliver = deliverDaemonProfileFromHelperIdentityOverSSH,
|
|
289
|
+
installRuntimeConfig = installDaemonRuntimeConfigOverSSH,
|
|
288
290
|
verifyRemoteIdentity = verifyRemoteServiceIdentity,
|
|
289
291
|
verifyRemoteHelperIdentity = verifyRemoteHelperIdentityOnTarget,
|
|
290
292
|
bootstrap = bootstrapFreshDaemon,
|
|
@@ -332,6 +334,7 @@ export async function cmdDaemon(args, {
|
|
|
332
334
|
},
|
|
333
335
|
enroll: enrollBootstrap,
|
|
334
336
|
deliver: deliverBootstrap,
|
|
337
|
+
installRuntimeConfig,
|
|
335
338
|
installRemote,
|
|
336
339
|
onApprovalRequired: ({ approval_url: approvalUrl, host_key: hostKey }) => {
|
|
337
340
|
notice(`bb daemon bootstrap: owner approval required for ${hostKey}: ${approvalUrl}`);
|
|
@@ -334,3 +334,32 @@ export async function deliverDaemonProfileFromBootstrapIdentityOverSSH({
|
|
|
334
334
|
installFlag: "--install-profile-from-bootstrap-identity",
|
|
335
335
|
});
|
|
336
336
|
}
|
|
337
|
+
|
|
338
|
+
// Runtime policy is public host metadata, never a credential. It is still
|
|
339
|
+
// installed through the daemon's descriptor-pinned private root so a caller
|
|
340
|
+
// cannot redirect it with a symlink or broaden a prior host's policy.
|
|
341
|
+
export async function installDaemonRuntimeConfigOverSSH({
|
|
342
|
+
config,
|
|
343
|
+
configPath,
|
|
344
|
+
sshHost,
|
|
345
|
+
serviceUser,
|
|
346
|
+
daemonBinary,
|
|
347
|
+
profilePath,
|
|
348
|
+
expectedHostKey,
|
|
349
|
+
sshBin = "ssh",
|
|
350
|
+
spawnImpl = realSpawn,
|
|
351
|
+
env = process.env,
|
|
352
|
+
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
353
|
+
directInstall = false,
|
|
354
|
+
} = {}) {
|
|
355
|
+
safeInputs({ sshHost, serviceUser, daemonBinary, profilePath, expectedHostKey, sshBin, spawnImpl, env, timeoutMs, directInstall });
|
|
356
|
+
if (typeof config !== "string" || config.length === 0 || Buffer.byteLength(config, "utf8") > 64 * 1024 ||
|
|
357
|
+
typeof configPath !== "string" || !SAFE_ABSOLUTE_PATH.test(configPath) || !configPath.endsWith("/daemon.json")) throw invalid();
|
|
358
|
+
const command = remoteDaemonCommand({
|
|
359
|
+
serviceUser, daemonBinary, directInstall,
|
|
360
|
+
args: ["--install-runtime-config", "--config", configPath, "--profile", profilePath, "--expected-host-key", expectedHostKey],
|
|
361
|
+
});
|
|
362
|
+
const stdout = await fixedSsh({ sshHost, sshBin, spawnImpl, env, timeoutMs, command, stdin: Buffer.from(config, "utf8") });
|
|
363
|
+
if (!stdout.equals(Buffer.from('{"installed":true}\n'))) throw failed();
|
|
364
|
+
return { installed: true };
|
|
365
|
+
}
|