@botbuddy/cli 1.64.33 → 1.64.34
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/api.mjs +2 -0
- package/src/daemon/automatic.mjs +32 -11
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.64.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.64.34",
|
|
3
|
+
"source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
|
|
4
|
+
"source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
|
|
5
5
|
"target": "darwin-arm64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "5fba031a897c73f93e078e0aca1c4e8338926dc3501e512b3a9f0d706f39708c"
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.64.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.64.34",
|
|
3
|
+
"source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
|
|
4
|
+
"source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
|
|
5
5
|
"target": "linux-x64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "7d722a654dd8da0794024fc6c0dba71034d631e1de87f434e5fbd8399f0d08af"
|
|
7
7
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"release_version": "1.64.
|
|
4
|
-
"source_commit": "
|
|
5
|
-
"source_sha256": "
|
|
3
|
+
"release_version": "1.64.34",
|
|
4
|
+
"source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
|
|
5
|
+
"source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
|
|
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": "5fba031a897c73f93e078e0aca1c4e8338926dc3501e512b3a9f0d706f39708c",
|
|
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": "7d722a654dd8da0794024fc6c0dba71034d631e1de87f434e5fbd8399f0d08af",
|
|
19
19
|
"mode": "0755"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/package.json
CHANGED
package/src/api.mjs
CHANGED
|
@@ -415,6 +415,8 @@ export function containerHostRegisterEndpoint(serverUrl = SERVER_URL) {
|
|
|
415
415
|
*/
|
|
416
416
|
export function registerContainerHost(body, options = {}) { return postContainerHostControl(body, options, "register", "container_host_register"); }
|
|
417
417
|
export function daemonHandoverRequest(body, options = {}) { return postContainerHostControl(body, options, "handover", "daemon_handover"); }
|
|
418
|
+
// BOT-3127: the owner-only automatic-update describe read (same auth as handover).
|
|
419
|
+
export function daemonAutomaticUpdateRequest(body, options = {}) { return postContainerHostControl(body, options, "automatic-update", "daemon_handover"); }
|
|
418
420
|
async function postContainerHostControl(body, {
|
|
419
421
|
fetchImpl = fetch,
|
|
420
422
|
auth: pinnedAuth = null,
|
package/src/daemon/automatic.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { callToolJson, resolveCallAuth } from "../api.mjs";
|
|
1
|
+
import { callToolJson, daemonAutomaticUpdateRequest, resolveCallAuth } from "../api.mjs";
|
|
2
2
|
import {
|
|
3
3
|
assertSshHost,
|
|
4
4
|
installedBinaryPath,
|
|
@@ -11,13 +11,20 @@ const fail = (code) => {
|
|
|
11
11
|
};
|
|
12
12
|
// One explicit administrator installation grants only the fixed native
|
|
13
13
|
// coordinator/schedule. Persisted operator opt-in remains a separate drawer act.
|
|
14
|
+
// BOT-3127: user-scoped. The spec names no tenant; the host's owner asks the
|
|
15
|
+
// server for the host's inert rollout label and the root binding pins that.
|
|
14
16
|
export async function installAutomaticDaemonUpdater(spec, {
|
|
15
17
|
validateRelease = validateDaemonRelease,
|
|
16
18
|
resolveAuth = resolveCallAuth,
|
|
17
19
|
identity = callToolJson,
|
|
20
|
+
describe = daemonAutomaticUpdateRequest,
|
|
18
21
|
stage = stageRemoteDaemonRelease,
|
|
19
22
|
native = nativeHandoverCommand,
|
|
20
23
|
} = {}) {
|
|
24
|
+
if (spec && typeof spec === "object" && Object.hasOwn(spec, "tenant")) {
|
|
25
|
+
// Automatic updates belong to the host's owner, not a project.
|
|
26
|
+
fail("daemon_automatic_install_tenant_not_used");
|
|
27
|
+
}
|
|
21
28
|
if (
|
|
22
29
|
!spec || typeof spec !== "object" || Array.isArray(spec) ||
|
|
23
30
|
Object.keys(spec).some((key) =>
|
|
@@ -28,13 +35,11 @@ export async function installAutomaticDaemonUpdater(spec, {
|
|
|
28
35
|
"serviceUser",
|
|
29
36
|
"releaseRoot",
|
|
30
37
|
"expectedHostKey",
|
|
31
|
-
"tenant",
|
|
32
38
|
].includes(key)
|
|
33
39
|
) || !["linux", "darwin"].includes(spec.platform) ||
|
|
34
40
|
typeof spec.serviceUser !== "string" || spec.serviceUser === "root" ||
|
|
35
41
|
!/^[a-z_][a-z0-9_-]*$/i.test(spec.serviceUser) ||
|
|
36
|
-
!/^bbh-[0-9a-f]{24}$/.test(spec.expectedHostKey)
|
|
37
|
-
typeof spec.tenant !== "string" || !spec.tenant
|
|
42
|
+
!/^bbh-[0-9a-f]{24}$/.test(spec.expectedHostKey)
|
|
38
43
|
) fail("daemon_automatic_install_spec_invalid");
|
|
39
44
|
assertSshHost(spec.sshHost);
|
|
40
45
|
const release = await validateRelease({ releaseRoot: spec.releaseRoot }, {
|
|
@@ -48,14 +53,30 @@ export async function installAutomaticDaemonUpdater(spec, {
|
|
|
48
53
|
if (resolved?.error || !resolved?.auth) {
|
|
49
54
|
fail("daemon_automatic_install_auth_required");
|
|
50
55
|
}
|
|
51
|
-
const who = await identity("whoami", {}, {
|
|
52
|
-
auth: resolved.auth,
|
|
53
|
-
tenant: spec.tenant,
|
|
54
|
-
});
|
|
56
|
+
const who = await identity("whoami", {}, { auth: resolved.auth });
|
|
55
57
|
if (
|
|
56
58
|
!who?.ok || who.isError || typeof who.data?.owner_email !== "string" ||
|
|
57
|
-
!who.data.owner_email.includes("@")
|
|
59
|
+
!who.data.owner_email.includes("@")
|
|
58
60
|
) fail("daemon_automatic_install_owner_unavailable");
|
|
61
|
+
const described = await describe({
|
|
62
|
+
action: "describe",
|
|
63
|
+
host_key: spec.expectedHostKey,
|
|
64
|
+
}, { auth: resolved.auth });
|
|
65
|
+
const owner = described?.data?.owner_email, label = described?.data?.tenant_id;
|
|
66
|
+
if (
|
|
67
|
+
!described?.ok || described.data?.success !== true ||
|
|
68
|
+
described.data.host_key !== spec.expectedHostKey ||
|
|
69
|
+
typeof owner !== "string" || owner.toLowerCase() !== who.data.owner_email.toLowerCase() ||
|
|
70
|
+
typeof label !== "string" || !label
|
|
71
|
+
) {
|
|
72
|
+
// A 4xx answer carries its code in `error` (e.g. daemon_host_scope).
|
|
73
|
+
const code = described?.data?.code ?? described?.error;
|
|
74
|
+
fail(
|
|
75
|
+
typeof code === "string" && /^(?:[A-Z_]{1,64}|[a-z_]{1,64})$/.test(code)
|
|
76
|
+
? `daemon_automatic_install_owner_refused: ${code}`
|
|
77
|
+
: "daemon_automatic_install_owner_refused",
|
|
78
|
+
);
|
|
79
|
+
}
|
|
59
80
|
const staged = await stage({
|
|
60
81
|
platform: spec.platform,
|
|
61
82
|
host: spec.sshHost,
|
|
@@ -70,8 +91,8 @@ export async function installAutomaticDaemonUpdater(spec, {
|
|
|
70
91
|
mode: "automatic-install",
|
|
71
92
|
input: {
|
|
72
93
|
host_key: spec.expectedHostKey,
|
|
73
|
-
owner_email:
|
|
74
|
-
tenant_id:
|
|
94
|
+
owner_email: owner,
|
|
95
|
+
tenant_id: label,
|
|
75
96
|
},
|
|
76
97
|
});
|
|
77
98
|
if (result?.installed !== true || result.protocol !== 2) {
|