企业版 — 注册与设备群
单独一份 Bromure Agentic Coding 是个人工具。而在整个团队中,管理员往往需要回答组织层面的问题:哪些 Mac 正在运行应用、代理正在引入哪些软件包、花费了多少令牌,以及是否有工作区触发了提示注入检测器。通过向 Bromure Enterprise Manager(bromure.io 上的一个工作区)注册,即可精确获得这种设备群可见性——它会从每一台已注册的 Mac 上传会话元数据(绝不上传提示,绝不上传机密)。
本章介绍如何注册一台 Mac、用于对其上传内容进行认证的 mTLS 身份、究竟哪些内容会被上传以及哪些不会、按工作区退出、管理员的设备群视图、远程许可处理,以及注销流程。本地追踪——注册并不会取代这一在 Mac 本地的审计记录——在 追踪 中介绍;为企业报告提供数据的软件包清单则见 供应链保护。
两个相互独立的系统
“设备群”一词涵盖了两个值得区分清楚的功能,因为它们不共享任何信任根:
- bromure.io 注册(本章)将一台 Mac 注册到你的工作区,并将会话元数据流式传输到云端,由你所在组织的 CA 签发的双向 TLS 证书进行认证。
- 富客户端(远程访问)让一台 Mac 通过 SSH 镜像其他 Mac 上正在运行的实例,由 SSH 主机密钥和已注册的公钥进行认证。
两者互不依赖。你可以在从不使用富客户端的情况下注册,也可以在不注册任何主机的情况下镜像它们,或者两者都做。注册的 mTLS 栈仅用于设备群遥测;富客户端镜像信任 SSH——在本版本中这两者是有意不合并的。
使用 Bromure Enterprise Manager 注册
注册是基于代码的。管理员在 bromure.io 上你的用户详情页面上生成一个一次性的六词注册代码,范围限定为应用 agentic-coding。你将该代码粘贴到应用(或 CLI)中,该 Mac 便会将自身注册为该工作区的一个安装。
在应用中
- 从管理员处获取一个六词注册代码。
- 打开 Bromure Agentic Coding(应用名菜单)→ 注册到 bromure.io…——该项就位于 检查更新… 的正下方。此时会打开一个标题为 bromure.io 注册 的窗口。
- 将代码粘贴到 注册代码 字段(占位符:
six-word-enrollment-code)。 - 可选地编辑 设备名称(默认为这台 Mac 的名称;帮助文本为:“显示给你的管理员,以便他们识别这台 Mac。”)。
- 可选地展开 高级 并为自托管或预发布服务器设置 服务器 URL(可选)。
- 点击 注册(Return)或 取消(Esc)。
该表单明确说明了注册会启用什么:它会“将会话元数据(工具、文件、命令、令牌用量)发送到你的工作区,以便管理员审阅活动。处于私密模式的工作区绝不会流式传输。”成功后,该安装会出现在管理员的 /agentic-coding/installs 页面上。
注意: 某些应用内提示文本仍写着“打开 窗口 → 注册到 bromure.io…”,但该项实际上位于应用(应用名)菜单中——那才是权威位置。为不同 Bromure 应用生成的代码会被拒绝,并显示 Code was issued for app '…', expected 'agentic-coding'.,而第二次注册会失败并显示 Bromure Agentic Coding is already enrolled.
在 CLI 中
图形界面的流程都有精确对应的 CLI 命令,它们在 bromure-cli --help 中归入 Enterprise features 分组,并共享相同的磁盘存储。这些命令便于脚本化配置或在既有 SSH 会话上进行注册。
| 命令 | 作用 |
|---|---|
bromure-cli enroll --code <code> [--server-url <url>] [--device-name <name>] | 注册这台 Mac。成功时打印电子邮件、工作区、安装 ID、服务器和设备;失败时以非零状态退出。 |
bromure-cli enrollment-status | 打印当前状态。未注册时打印 not enrolled 并以 0 退出,因此自动化可以安全地探测。 |
bromure-cli unenroll [--force] | 登出(见 撤销、注销与取消注册)。 |
默认值与图形界面一致:服务器 URL 为 https://bromure.io/api(可通过 BROMURE_MANAGED_URL 或 managed.serverURL UserDefaults 键覆盖),设备名称为该 Mac 的本地化主机名。
mTLS 安装身份
遥测上传不携带令牌——它们使用客户端证书进行认证。在注册时(以及每次续期时),应用会生成一个全新的 RSA-2048 密钥,构建一个公用名为 bromure-install-<installId> 的证书签名请求,并让你的工作区的 组织 CA 通过托管服务器对其进行签名。叶证书和 CA 证书以可检查的 PEM 文件形式存储;私钥则保存在 macOS 钥匙串中。
在发出请求时,证书和密钥会被打包成一个内存中的 PKCS#12 并在不触及钥匙串的情况下导入,因此该身份本身绝不会出现任何钥匙串访问条目或解锁提示。分析端点自身的服务器证书则针对常规的系统根存储进行验证。
注意: 注册期间的叶证书请求是尽力而为的。如果组织 CA 尚未配置,注册仍会成功,证书将在首次心跳时获取。
注册状态面板
一旦注册,同一菜单项就会自身重命名为 bromure.io 注册…,并打开一个状态面板(标题为 bromure.io 注册)而非录入表单。它会显示 工作区、用户、设备、服务器、已注册(日期)和 证书 各行——全部文本可选。证书 行显示 有效期至 <date>,如果已过期,则显示 已过期 — 正在自动续期。
底部有两个按钮:续期证书 强制签发一张新的叶证书;登出 取消注册(具有破坏性——见下文)。健康问题会以橙色警告横幅显示:
| 横幅 | 含义 | 应对措施 |
|---|---|---|
| 注册已撤销 | “你的管理员撤销了此安装。请登出并使用新代码重新注册以恢复托管模式。” | 登出并使用新代码注册。 |
| 注册不再被接受 | “服务器拒绝了此安装的凭据——它们可能已过期或已被重置。” | 登出并使用新代码注册。 |
成功执行 续期证书 会清除过期的凭据拒绝状态,但它绝不会清除已撤销状态——只有重新注册才能清除。
心跳与证书续期
当应用以注册状态运行时,一个后台任务每 10 分钟向工作区服务器发送一次心跳(并在启动时和注册时各立即发送一次),这使管理员的最后可见时间戳保持最新。服务器的响应是健康状态的权威依据:撤销会翻转横幅;干净的响应会清除先前的不良状态。只有心跳的持有者令牌收到 401/403 才会将健康状态变为“令牌被拒绝”——瞬时错误(离线、5xx)绝不会改变它。
每次心跳还会检查 mTLS 叶证书,并在其缺失或距离过期不足 72 小时 时进行续期。续期由持有者令牌而非叶证书进行认证,因此即使是已经过期的证书也会在下次启动时自愈。
警告: 一台在其证书过期后仍处于关闭状态的 Mac 会静默地无法完成托管上传,直到下次启动续期叶证书为止。这在正常使用中是透明的,但如果一台机器长时间关闭,则值得留意。
上传的内容——以及不上传的内容
已注册的非私密会话会流式传输结构化的 云事件——每条一个记录:会话 id、工作区 id、时间戳、事件类型,以及一小段 JSON 载荷。这里的会话是活动窗口,而非虚拟机生命周期:每个工作区在每个活动窗口内对应一个会话 id,在 20 分钟无活动后滚动重置。
| 事件 | 载荷要点 |
|---|---|
session.start / session.end | 活动窗口的开始与结束;session.end 携带一个原因(例如 idle_timeout)并回溯到空闲边界。 |
llm.request | 提供商、主机、路径、状态码、延迟、模型,以及输入/输出/缓存令牌计数。实时 WebSocket 会话还会增加传输方式和响应 id。 |
tool.use | 工具名称和输入摘要(截断至 240 个字符)。 |
file.read / file.write | 文件路径和触及它的工具。 |
command.run | 命令文本(截断至 500 个字符)和工具。 |
credential.token_swap | 主机和路径,以及伪令牌和真实令牌的简短预览——绝不包含令牌本身。 |
credential.ssh_sign | 密钥标签、SHA-256 指纹和密钥类型(托管 / 导入)。 |
credential.aws_sign | 方法、主机、路径、服务、区域和一个掩码后的访问密钥。 |
supply_chain.fetch | 生态系统、软件包、版本、请求类型、结果和原因。 |
vm.disk_reset | 原因和涉及的基础镜像版本。 |
prompt_injection.detection | 检测器、方法、动作、主机、来源、评分、信号、工具使用 id,以及整个被标记的片段(最多 20,000 个字符)。 |
流式传输状态在每个会话窗口中都可见,并在管理员看到的设备群报告中得到反映。
永不离开 Mac 的内容
这部分需要精确说明。传输的是元数据;你工作的内容始终留在本地。Bromure 绝不上传:
- 原始用户提示 或 模型响应正文。
- 机密值。 凭据事件仅携带掩码后的预览或指纹——真实密钥字节绝不离开 Mac。
- 私密模式工作区中的任何内容(见下文),以及未注册时的任何内容。
缓冲的事件仅保存在内存中;强制退出会丢弃任何尚未刷新的事件,并且没有基于磁盘的重试队列。这是有意为之的设计——遥测是尽力而为的,绝不以牺牲你的工作为代价。
警告: 元数据专用规则有一个刻意的例外:
prompt_injection.detection会上传整个被标记的片段(最多 20,000 个字符),以便管理员能够准确看到代理即将读取的内容。这是内容而非元数据——权衡在于,提示注入企图恰恰是安全团队需要逐字检查的东西。其他所有内容仍然是预览、路径、计数和掩码。关于什么会触发检测,参见 提示注入保护。
批处理与投递
事件在内存中批处理,并发送到分析摄取端点,仅由 mTLS 叶证书进行认证——遥测数据不随附任何持有者令牌。缓冲区每 5 秒刷新一次,在待处理事件达到 200 条时自动刷新,每次请求最多发送 500 个事件。在长时间中断期间,缓冲区会被裁剪至最近的事件(丢弃最旧的),而不会无限增长;刷新失败会在下一个周期重试同一批次。
私密模式
流式传输是按工作区退出的。工作区编辑器中的 私密模式 开关(眼睛加斜线图标)可将该工作区的活动完全保留在本地:不流式传输任何元数据,标题栏指示器对它消失,管理员的会话列表也看不到它的任何内容。本地追踪检查器不受影响——它会按照自身的 追踪级别 继续记录。该开关对每个工作区默认关闭(启用流式传输),并且仅在已注册的 Mac 上出现,因为在其他情况下它不起作用。
私密模式位于工作区编辑器中的 追踪 设置里。在未注册的 Mac 上,该开关根本不存在,这正是下面的窗格仅显示追踪选择器的原因:
事件在发出时便受到门控——私密模式的流量甚至不会进入上传缓冲区。
提示: 当你在某个工作区中使用个人 API 密钥,并且不希望该活动对组织的管理员可见时,私密模式正是合适的开关。它不会改变本地审计记录的任何内容。
流式传输指示器
只要一台 Mac 已注册且某个工作区未处于私密模式,该会话窗口的工具栏中就会出现一个脉动的红色录制样式圆点(并在统一窗口侧边栏行上显示为一个圆点)。其工具提示为“会话元数据正在发送到 bromure.io。切换该工作区的私密模式即可停止流式传输。”其辅助功能标签为 正在流式传输到 bromure.io。该圆点纯属信息性质,在未注册或私密模式下会被隐藏。
出口 IP 注册
已注册的安装还会每 60 秒(并在启动时和注册时各一次)向分析服务的 /register-ip 端点发送一个微小的 mTLS 认证 ping,以便工作区的记录反映该 Mac 当前的公网 IP。未注册时会静默跳过。该端点默认为 https://analytics.bromure.io/register-ip,可通过 BROMURE_AC_REGISTER_IP_URL 或 managed.acRegisterIPURL UserDefaults 键覆盖。
供应链清单与令牌用量汇总
在所流式传输的事件类型中,有两种正是让企业级报告能在整个团队范围内发挥价值的关键。
- 供应链清单。 每次元数据和构件获取都会发出一个
supply_chain.fetch事件,携带生态系统、软件包、版本、请求类型、结果(allowed、rewritten、blocked或stripped)和原因。仅注册本身就能为管理员提供一份覆盖全组织的清单,记录每个代理引入的每个软件包——即使在关闭了所有供应链强制层的工作区上也是如此,因为观察与强制是解耦的。这方面的强制侧在 供应链保护 中有说明。 - 令牌用量汇总。 每个
llm.request事件都携带模型、输入和输出令牌计数,以及缓存创建和缓存读取计数。在整个设备群中聚合后,这些数据便成为按用户、按工作区和按模型的花费报告,而无需上传任何提示或响应内容。其本地对应物——你可以在自己的 Mac 上查看的按请求令牌统计——在 追踪 中。
设备群视图
在 bromure.io 一侧,每台已注册的 Mac 都以一行的形式出现在工作区的 /agentic-coding/installs 页面上,由其安装 ID 标识,并显示你设置的设备名称、用户,以及由 10 分钟心跳保持最新的最后可见时间戳。管理员可以从那里审阅整个设备群的流式会话元数据、供应链清单、令牌用量汇总和提示注入检测。
这与富客户端中“设备群”的概念不同——后者是通过 SSH 同时镜像多个远程主机——那在 远程访问 中介绍。两者绝不共享信任根。
远程许可处理
当一个工作区会话通过 CLI 或 SSH 以交互方式挂载——前面没有 GUI 窗口——应用无法弹出对话框。取而代之的是,四个中间人许可代理会将它们的问题以编号菜单的形式呈现在挂载用户的终端上:
| 提示 | 选项 |
|---|---|
凭据使用——Allow "<workspace>" to use <credential>? | 允许 1 小时 / 允许 5 分钟 / 允许本次会话剩余时间 / 不允许 |
供应链绕过——Pass through <package> from workspace …? | 允许 15 分钟 / 允许一次 / 允许本次会话剩余时间 / 不允许 |
护栏写入——Allow write on … from workspace …? | (与上面相同的四个选项) |
提示注入——Possible <detector> in …(显示最多 1,500 个字符的被标记文本) | 阻止此请求 / 允许此请求 |
关键特性在于提示呈现的位置:在终端泵的宿主机一侧。客户机虚拟机只能看到连接的另一端,因此被入侵的客户机既无法读取提示,也无法注入答案。如果有多个客户端挂载到同一个工作区,最新的交互式挂载会收到这些提示(“最近挂载者胜出”)。
警告: 这些提示会安全失败。没有活动挂载、超时(默认 120 秒)、被驳回,或在提示进行中断开连接,全都会解析为拒绝——对于提示注入,则解析为阻止。对于以交互方式挂载的会话,注册表认证失败警报会被抑制为一行日志,因为没有 GUI 来显示它。这些相同决策的 GUI 路径在 凭据、供应链保护 和 提示注入保护 中介绍。
撤销、注销与取消注册
一个安装有两种方式离开设备群,二者作用不同。
取消注册(本地)。 在注册状态面板中点击 登出,或运行 bromure-cli unenroll。除非你传入 --force,否则 CLI 会提示 Sign out of <org> (<email>)? [y/N],并在没有可移除内容时打印 not enrolled — nothing to do(退出 0)。登出会删除所有本地注册材料——install.json、leaf.crt、ca.crt、leaf.serial 和健康文件——从钥匙串中移除持有者令牌和每一个叶私钥,清除缓存的 mTLS 身份,丢弃任何缓冲的遥测,并停止心跳和 IP 注册任务。应用返回 未注册 状态,状态窗口切换回注册表单,以便你立即用另一个代码重新注册。
撤销(服务器端)。 管理员在 bromure.io 上撤销该安装。在 Mac 上,下一次心跳会浮现 注册已撤销 横幅,托管上传停止。
警告: 登出纯属本地操作——不会进行任何服务器调用。管理员在停用一台设备时应在服务器端撤销该安装;否则那个(现已失效的)安装行会一直滞留在设备群页面上,直到它停止心跳为止。要完全注销一台 Mac,请在工作区中撤销它并在设备上登出。
参考
注册状态位于 ~/Library/Application Support/BromureAC/managed/ 下:install.json(安装 ID、工作区 slug、用户、服务器 URL、设备名称、注册时间)、leaf.crt 和 ca.crt(PEM)、leaf.serial(指向持有当前叶密钥的钥匙串条目的指针),以及 health(ok / tokenRejected / revoked)。在 macOS 钥匙串中,服务 io.bromure.agentic-coding.managed-install 持有 install-token 持有者令牌,以及每个已签发证书序列号对应的一个 leaf-cert-key-<serialHex> 条目(仅限本设备、解锁时可用)。
客户端会联系三个托管服务器路由和一个摄取端点:
POST {server}/v1/enroll (code redemption)
POST {server}/v1/installs/{installId}/heartbeat (Bearer)
POST {server}/v1/installs/{installId}/cert (Bearer + CSR PEM)
POST {ingest URL} {"events":[…]} (mTLS, no bearer)
| 间隔 / 限制 | 值 |
|---|---|
| 心跳 | 每 10 分钟 |
| 出口 IP 注册 | 每 60 秒 |
| 叶证书续期阈值 | 过期前 72 小时 |
| 事件刷新 | 每 5 秒(或待处理达 200 条时) |
| 每批次最大事件数 | 500 |
| 会话空闲滚动 | 20 分钟 |
| 远程许可超时 | 120 秒 |
| 提示注入片段上限 | 20,000 个字符 |
服务器和端点覆盖项(无 GUI)为 BROMURE_MANAGED_URL(或 managed.serverURL,默认 https://bromure.io/api)、BROMURE_AC_INGEST_URL(或 managed.acIngestURL,默认 https://analytics.bromure.io/ac-ingest),以及 BROMURE_AC_REGISTER_IP_URL(或 managed.acRegisterIPURL)。完整的命令参考在 自动化与 CLI 中。