@botlearn-course/daemon 0.0.20-beta.11 → 0.0.20-beta.13

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 CHANGED
@@ -36,13 +36,13 @@ npx --yes --package @botlearn-course/daemon@latest botlearn-course-daemon course
36
36
  | `course doctor` | 打印 Auth 状态(不含 token)与 runtime 探测表(安装路径 / 版本 / 登录状态 / 安装提示)。 |
37
37
  | `--help` / `--version` | 帮助与版本。 |
38
38
 
39
- 包内还包含供 BotLearn 托管 E2B Template 使用的内部命令
39
+ 包内还包含供 BotLearn 托管 sandbox 使用的内部命令
40
40
  `botlearn-sandbox-supervisor agent-service session`。它不是 BYOA 用户入口:生产环境只允许由
41
- Agent Service 以固定 argv 启动,通过 stdin 接收一次性 bootstrap。E2B 中 daemon/runtime 分别
41
+ Agent Service 以固定 argv 启动,通过 stdin 接收一次性 bootstrap。sandbox 中 daemon/runtime 分别
42
42
  降权到 `botlearn-control`/`user` UID;继承 `NoNewPrivs=1`、无法使用 sudo 的平台保留 root control
43
43
  daemon,由 root-owned 固定 launcher 清空附加组后直接降权为 `user`。两条路径都为 DeepSeek
44
44
  设置 `no_new_privs`,runtime 用户本身没有 sudo 权限。托管启动链只执行
45
- `/opt` 下的固定 Node、supervisor、daemon、launcher 与 DeepSeek 文件,不信任 E2B 会开放给 runtime
45
+ `/opt` 下的固定 Node、supervisor、daemon、launcher 与 DeepSeek 文件,不信任 provider 会开放给 runtime
46
46
  写入的 `/usr/local/bin`。
47
47
  `agent-service session --bootstrap-stdin` 同样属于受 supervisor 保护的内部协议,不应直接暴露给
48
48
  课程任务或 workspace shell。
@@ -4,7 +4,7 @@ import { Readable } from "node:stream";
4
4
  import { pipeline } from "node:stream/promises";
5
5
  import path from "node:path";
6
6
  import { ensureDaemonHome } from "./auth-store.js";
7
- import { AGENT_SERVICE_WS_SCHEMA, AGENT_SERVICE_WS_SUBPROTOCOL, createSandboxFrame, createWorkspaceFileChunk, parseSandboxFrame, UnsupportedSandboxProtocolError, WORKSPACE_FILE_READ_BINARY_CAPABILITY, } from "./agent-service-ws-protocol.js";
7
+ import { AGENT_SERVICE_WS_SCHEMA, AGENT_SERVICE_WS_SUBPROTOCOL, createSandboxFrame, createWorkspaceFileChunk, parseSandboxFrame, UnsupportedSandboxProtocolError, WORKSPACE_FILE_READ_BINARY_CAPABILITY, WORKSPACE_SNAPSHOT_ATTESTATION_CAPABILITY, } from "./agent-service-ws-protocol.js";
8
8
  import { log as defaultLog, setOperationalLogSink, } from "./log.js";
9
9
  import { availableRunCapabilities, runtimeSupportsCourseSkills, } from "./runtime-capabilities.js";
10
10
  import { activationRuntimeEnv, runtimeChildEnv } from "./runtime-env.js";
@@ -875,6 +875,7 @@ export class AgentServiceSandboxClient {
875
875
  "workspace_writer_freeze_v1",
876
876
  "workspace_snapshot_v2",
877
877
  "workspace_restore_v1",
878
+ WORKSPACE_SNAPSHOT_ATTESTATION_CAPABILITY,
878
879
  ...(nasWorkspaceEnabled() ? ["workspace_nas_v1"] : []),
879
880
  ...(workspaceCopyV1Supported() ? ["workspace_copy_v1"] : []),
880
881
  ],
@@ -1,6 +1,7 @@
1
1
  export declare const AGENT_SERVICE_WS_SCHEMA: "botlearn-agent-sandbox-ws/0.4";
2
2
  export declare const AGENT_SERVICE_WS_SUBPROTOCOL: "botlearn-agent-sandbox.v4";
3
3
  export declare const WORKSPACE_FILE_READ_BINARY_CAPABILITY: "workspace_file_read_binary_v1";
4
+ export declare const WORKSPACE_SNAPSHOT_ATTESTATION_CAPABILITY: "workspace_snapshot_attestation_v1";
4
5
  export declare const WORKSPACE_FILE_CHUNK_BYTES: number;
5
6
  export declare const WORKSPACE_FILE_CHUNK_HEADER_BYTES = 29;
6
7
  export type SandboxFrameType = "sandbox.hello" | "sandbox.sync" | "session.open" | "session.activate" | "turn.start" | "turn.cancel" | "session.close" | "sandbox.drain" | "sandbox.shutdown" | "event.ack" | "auth.rotate" | "workspace.file.read" | "workspace.checkpoint" | "workspace.thaw" | "ping" | "sandbox.ready" | "sandbox.heartbeat" | "command.ack" | "session.opened" | "session.open_failed" | "session.closed" | "turn.event" | "turn.file.report" | "workspace.file.result" | "sandbox.drained" | "sandbox.log" | "pong" | "protocol.error";
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  export const AGENT_SERVICE_WS_SCHEMA = "botlearn-agent-sandbox-ws/0.4";
3
3
  export const AGENT_SERVICE_WS_SUBPROTOCOL = "botlearn-agent-sandbox.v4";
4
4
  export const WORKSPACE_FILE_READ_BINARY_CAPABILITY = "workspace_file_read_binary_v1";
5
+ export const WORKSPACE_SNAPSHOT_ATTESTATION_CAPABILITY = "workspace_snapshot_attestation_v1";
5
6
  export const WORKSPACE_FILE_CHUNK_BYTES = 64 * 1024;
6
7
  export const WORKSPACE_FILE_CHUNK_HEADER_BYTES = 29;
7
8
  const WORKSPACE_FILE_CHUNK_MAGIC = Buffer.from("BLWF", "ascii");
package/dist/redaction.js CHANGED
@@ -25,6 +25,7 @@ const QUOTED_JSON_SECRET_PATTERN = new RegExp(`(["'])(${SECRET_KEY_NAME_SOURCE})
25
25
  const QUOTED_ARGV_SECRET_PATTERN = new RegExp(`(["'])(${SECRET_FLAG_SOURCE})\\1(\\s*,\\s*)(["'])([^"'\\\\]*(?:\\\\.[^"'\\\\]*)*)\\4`, "gi");
26
26
  // blic_ 是课程 install code 前缀,与 runtime token 前缀一并脱敏。
27
27
  const SECRET_PREFIX_PATTERN = /\b(blic_|drt_|dit_|gho_|ghp_|sk-)[A-Za-z0-9_-]+/g;
28
+ const SIGNED_OBJECT_URL_PATTERN = /https?:\/\/[^\s"'<>]*[?&](?:X-Amz-Algorithm|X-Amz-Credential|X-Amz-Signature|X-Amz-Security-Token)=[^\s"'<>]*/gi;
28
29
  const SECRET_VALUE_PATTERNS = [
29
30
  [/\b(Bearer\s+)[^\s"']+/gi, `$1${REDACTED}`],
30
31
  [new RegExp(`(^|[\\s])(${SECRET_FLAG_SOURCE})=([^\\s"']+)`, "gi"), `$1$2=${REDACTED}`],
@@ -83,6 +84,7 @@ export function assertNoInjectedCredentials(data, additionalSecrets = []) {
83
84
  }
84
85
  export function redactSecretString(text, additionalSecrets = []) {
85
86
  return redactInjectedCredentials(text, additionalSecrets)
87
+ .replace(SIGNED_OBJECT_URL_PATTERN, REDACTED)
86
88
  .replace(/\b(Bearer\s+)[^\s"']+/gi, `$1${REDACTED}`)
87
89
  .replace(new RegExp(`(^|[\\s])(${SECRET_FLAG_SOURCE})=([^\\s"']+)`, "gi"), `$1$2=${REDACTED}`)
88
90
  .replace(new RegExp(`(^|[\\s])(${SECRET_FLAG_SOURCE})(\\s+)([^\\s"']+)`, "gi"), `$1$2$3${REDACTED}`)
@@ -16,7 +16,7 @@ export declare function runtimeChildIdentity(env?: NodeJS.ProcessEnv): {
16
16
  /**
17
17
  * Build the fixed control-to-runtime privilege boundary used by managed sandboxes.
18
18
  *
19
- * E2B runs the daemon as botlearn-control and grants it one fixed sudoers command.
19
+ * The legacy image boundary may grant botlearn-control one fixed sudoers command.
20
20
  * Platforms that inherit no_new_privs cannot use sudo, so their root supervisor daemon
21
21
  * invokes the same immutable launcher directly; the launcher clears supplementary groups
22
22
  * and performs the one-way uid/gid drop. BYOA retains direct-spawn behavior.
@@ -96,7 +96,7 @@ export function runtimeChildIdentity(env = process.env) {
96
96
  /**
97
97
  * Build the fixed control-to-runtime privilege boundary used by managed sandboxes.
98
98
  *
99
- * E2B runs the daemon as botlearn-control and grants it one fixed sudoers command.
99
+ * The legacy image boundary may grant botlearn-control one fixed sudoers command.
100
100
  * Platforms that inherit no_new_privs cannot use sudo, so their root supervisor daemon
101
101
  * invokes the same immutable launcher directly; the launcher clears supplementary groups
102
102
  * and performs the one-way uid/gid drop. BYOA retains direct-spawn behavior.
@@ -19,7 +19,7 @@ const MANAGED_PATH = [
19
19
  "/opt/node/22.23.1/bin",
20
20
  "/usr/bin",
21
21
  "/bin",
22
- // E2B materializes this directory as runtime-writable. Keep it last and never
22
+ // The managed image exposes this directory as runtime-writable. Keep it last and never
23
23
  // use it for a managed control-plane executable.
24
24
  "/usr/local/bin",
25
25
  ].join(":");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botlearn-course/daemon",
3
- "version": "0.0.20-beta.11",
3
+ "version": "0.0.20-beta.13",
4
4
  "description": "Lightweight BotLearn Course daemon: run course tasks on your own machine with your own agent runtime (BYOA).",
5
5
  "type": "module",
6
6
  "bin": {