安全与隐私,
供你审查。

Gnista 是一个 Mac 应用,它盯着你的编程 Agent,让人在刘海里直接回应它们。这一页写给在它装上公司 Mac 之前负责审查的人:它读什么,发什么,出问题时会怎样。

更新于

简而言之

  • 在 Mac 上运行。不用账号,没有遥测,没有分析。
  • 任何人的会话、代码或提示词,都不会离开这台 Mac。
  • 只有下面列出的网络请求,别无其他。
  • 它从不自己批准任何东西。拿不准时,Agent 会在自己的提示里询问。
  • 使用 Developer ID 签名,经 Apple 公证,启用 hardened runtime 构建。

Gnista 读取什么

  • 来自 Agent hooks(钩子)的事件,由它的小辅助程序通过 Application Support 里 Gnista 文件夹中的 Unix socket 发来。仅限本地:唯一的网络监听,是开启容器时 Mac 回环地址上的一个端口,而且要求密码。远程机器的事件经由用户自己的 ssh,送到 Mac 上一个专属于它的 socket。
  • Agent 自己的会话文件和配置,就在它们原来的位置,用来显示标题、进度、费用和套餐额度。
  • 它自己的钥匙串项目,保存许可证密钥和试用开始时间(试用开始时间在它的偏好设置里也存了一份)。从不同步。
  • 仅在获得许可时:自动化和辅助功能,用来把对的终端标签页或编辑器窗口调到前面。两者都是可选的。

它从不做什么

  • 它不读取其他应用的钥匙串项目,也不读取任何凭据。
  • 它不探测端口,也不扫描网络。
  • 它不向任何服务发送遥测或分析数据,也没有账号。只有在用户同意,或组织把 CrashReportsMode 设为 always 时,才会发送崩溃报告。
  • 它对 Agent 配置的改动仅限于自己的条目:每个配置都先备份,格式和键的顺序保持不变,断开一个 Agent 时只删掉 Gnista 自己那几行。

每一个网络请求

主机请求何时,发送什么
gnista.sh检查更新开启自动更新时大约每天一次。和任何请求一样会带上 IP 地址,另外是 Gnista 的版本。不发送这台 Mac 的画像。
github.com下载:更新;Linux 辅助程序检查发现更新时下载该更新;连接了远程机器且需要时,下载对应这个版本和那种处理器的 Linux 辅助程序:都来自 Gnista 的公开下载(github.com/BlixtDunder/gnista-downloads,由 release-assets.githubusercontent.com 提供)。和任何请求一样会带上 IP 地址。都只在带有 Gnista 密钥的签名时才使用。
report.gnista.sh许可证;崩溃报告许可证:激活密钥时,发送密钥,以及作为这次激活标签的 Mac 名称;之后大约每周验证一次;移除密钥时释放这台 Mac 的名额;这两种请求都带着密钥和这台 Mac 的激活 ID。Gnista 的中转服务器只把这些转交给记录商户 Creem,关于许可证,除了按地址统计的请求次数(以加盐哈希保存,第二天就丢弃)之外,什么都不保留。不涉及 Agent、项目或用量的任何信息。崩溃报告:只在 Gnista 或它的辅助程序崩溃之后,并且只有在用户同意、选择了始终发送,或组织把 CrashReportsMode 设为 always 时:错误内容、发生的时间及其在 Gnista 代码中的位置、它各线程所在队列的名称、它加载的库的名称和地址、Gnista 和 macOS 的版本、Mac 型号和处理器架构,以及一个为崩溃报告生成的随机 ID。没有用户名、文件路径、项目、提示词或代码。Gnista 托管在瑞典的中转服务器把它以邮件发给 Gnista 团队,不保留副本。
ssh远程机器只针对在设置 ▸ 远程里连接的机器,经由用户自己的 ssh 和 ssh 配置,Pod 则经由 kubectl:安装它的辅助程序和它那里 Agent 的 hooks,保持一条连接,把它们的事件带到 Mac、再把回应送回去(“连接”设为 manual 时没有这条连接),以及点击时显示某个 Agent 的 tmux 窗格。什么都不会发给 Gnista 团队。
ampcode.comAmp 线程只针对这一行上的 Amp 会话:Gnista 以用户自己的登录身份运行 Amp 自己的 CLI(amp threads export、amp threads usage、amp usage),由它从 Amp 读取线程、线程的费用和账户的积分。Gnista 不附加任何自己的东西;什么都不会发给 Gnista 团队。
raw.githubusercontent.com模型价格只有开启“用量”时:下载 LiteLLM 公开的模型价格表,最多每天一次。只是普通下载,不附带任何关于用户的信息。

关闭“自动安装更新”(或由你们的 MDM 把 AutomaticUpdates 设为 false)就会停止检查更新。试用不需要联网;激活之后,个人密钥离线也能用;团队密钥则需要不时验证一下,才能用在它上次验证 30 天之后发布的版本上。把 RemoteMachinesAllowed 设为 false,会关闭所有隧道,谁也无法再连接服务器。

批准如何安全兜底

“在 Gnista 中回应提示”是一项设置,适用于能在刘海里接收回应的 Agent,比如 Claude Code、Codex 和 OpenCode。只有一个人点了允许,请求才会被允许;而且“允许”要等半秒才能按下。默认不批准任何东西。

  • 没人在 Gnista 中回应:Claude Code 会同时显示它自己的提示,哪边先回应就算哪边。其他 Agent 会拿回请求,照常在自己的提示里询问:你一切到它们的标签页就问,刘海收起时 10 秒后问,你在刘海里时最多等 45 秒。
  • Gnista 没在运行:hook 发现没人在听,立刻返回。Agent 在自己的提示里询问。
  • Gnista 已锁定(试用结束,没有许可证):每个请求都立即退回,不等待。
  • hooks 从不阻塞 Agent:状态 hooks 大约 30 ms 就返回,并且总是正常退出。
  • 远程机器:只有“在 Gnista 中回应提示”开启时,那边的辅助程序才会等刘海的回应。那台机器上有 root 权限的人都能回应它的批准请求,连接机器时设置里也会这样提示。
  • 你们的规则:有了团队版,你们的 MDM 可以关闭“在 Gnista 中回应提示”,或只对部分 Agent 开放。见通过 MDM 部署 Gnista。

远程机器

Gnista 可以显示运行在服务器、容器或 Kubernetes Pod 里的 Agent,并让人在刘海里回应它们。在有人连接机器之前,这个功能是关闭的;把 RemoteMachinesAllowed 设为 false,它就一直关闭。

  • 用户自己的 ssh:Gnista 运行 Mac 上的 ssh,使用用户自己的 ssh 配置、密钥和 agent,就像用户自己连接一样。它不保存任何密码或密钥;登录需要人来操作时(密码、双重认证),“登录”会为此打开终端。Pod 经由用户自己的 kubectl。
  • 签名的辅助程序,不要 root,没有守护进程:Gnista 把它的辅助程序复制到那台机器上用户主目录里的 ~/.gnista,并在那里的 Agent 配置中加上自己的几行,和在 Mac 上一样。Linux 辅助程序用 Gnista 的密钥签名,签名对不上的,Gnista 一律拒绝;公钥在 gnista.sh/downloads/linux/gnista-linux.pub。它不需要 root,不安装任何服务,只在 Agent 的 hook 调用它时才运行。
  • 每台 Mac 一个 socket:每台连接了这台机器的 Mac,都在那里有一个专属的 socket,只有那个用户能读。Mac 上的容器经由 Mac 回环地址上的一个端口连到它,每个连接都必须先给出一个随机密码;密码保存在 ~/.gnista/containers 里,供挂载它的容器使用。
  • 断开连接会把 Gnista 的那几行从那里的 Agent 配置中删掉,并移除 ~/.gnista,除非还有别的 Mac 在用它。

当你们的安全工具标记隧道时

每台机器都有一项“连接”设置;有了团队版,你们的 MDM 可以用 RemoteConnection 为每台 Mac 设定它:

  • 自动(automatic):Gnista 自己的 ssh 连接把那台机器的 socket 转发到 Mac;服务器不转发 socket 时,改用它回环地址上一个要求密码的端口;什么都不转发时,就和“不转发”一样。
  • 不转发(relay):完全不转发。辅助程序通过一条普通 ssh 命令的输入和输出传递 hooks 的消息,和 Kubernetes Pod 的做法一样。
  • 通过我自己的 ssh(manual):Gnista 不打开任何连接。“设置”只安装一次辅助程序,并给出一行 RemoteForward,供用户写进自己的 ssh 配置;之后由用户自己的 ssh 会话传送 Agent 的事件。在服务器的 sshd_config 里设置 StreamLocalBindUnlink yes 后,断线后的下一个会话会立即连上。

它在 Mac 上保存什么

在 Application Support 里它自己的文件夹中:最近完成的会话、最新的套餐额度、模型价格表、它改过的 Agent 配置的备份、还没发送的崩溃报告(30 天后丢弃)、它下载的 Linux 辅助程序,以及用户自己的 Agent、模型和跳转规则文件。它的设置保存在它的偏好设置域 sh.gnista.Gnista 里;许可证密钥和试用开始时间保存在它自己的钥匙串项目里,试用开始时间在偏好设置里也有一份。在设置里移除 Gnista 的集成,会把它在每个 Agent 配置里的那几行都删掉。

签名与更新

Gnista 使用 Developer ID 签名,经 Apple 公证,并启用 hardened runtime 构建,所以打开时没有警告,macOS 也会检查它没被篡改。Gnista 在 gnista.sh 上发现更新,并通过 Sparkle 从 Gnista 在 GitHub 上的公开下载获取,每个更新都用我们的 EdDSA 密钥签名;签名对不上的更新,Gnista 一律拒绝。

它没有沙盒,也不能有:它得读取 Agent 的文件、编辑它们的配置。这也是它不在 Mac App Store 上架的原因。

有问题?

你们的审查还需要这里没写的东西?请写信到 support@gnista.sh。关于网站和购买的更多信息:隐私。