@botbuddy/cli 1.64.32 → 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
- package/src/stack.mjs +3 -0
|
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) {
|
package/src/stack.mjs
CHANGED
|
@@ -5618,6 +5618,9 @@ export async function cmdRun(opts, childArgv, {
|
|
|
5618
5618
|
receipt.feedback_recovery = { status: "not_yet_checked", available_after: "command_exits", recover_command: "bb feedback recover", list_command: "bb call list_feedback" };
|
|
5619
5619
|
}
|
|
5620
5620
|
const code = emit(receipt, opts, result.exitCode);
|
|
5621
|
+
// BOT-3126: the requester line already says BotBuddy was not at fault; the
|
|
5622
|
+
// launcher's generic "If BotBuddy is blocking your work" reminder would undercut it.
|
|
5623
|
+
if (failureClass.category === "requester") markFeedback();
|
|
5621
5624
|
try {
|
|
5622
5625
|
const outcome = await report({ fields: stackRunOutcomeFields(result), exitCode: code, runId, opts, env, durationMs: now() - startedAt, channel: result?.[OUTCOME_CHANNEL] ?? null });
|
|
5623
5626
|
const capture = outcome?.feedback_capture;
|