mcpField
Q
quill

quill

本地服务
github.com/manumarri-sudo安全09 周前更新

关于 quill

Notari 是用于 AI Agent 代码变更审查与取证的 Python 工具,会依据人工签署的路径范围、策略和 diff,在 CI 中生成可验证的变更凭证。它采用确定性检查而非模型判定,并提供可选的本地工具调用拦截;项目目前处于 Alpha 阶段。

主要功能

  1. 01按签署范围检查代码变更
  2. 02扫描常见格式的硬编码密钥
  3. 03生成可验证的签名变更凭证
  4. 04通过 HMAC 链式日志记录审计
  5. 05可选本地工具调用审批拦截

适用场景

  1. 01在 CI 检查 Agent 是否越权修改文件
  2. 02为拉取请求保存可复核的变更记录
  3. 03定位阻断项并生成修复指引

MCP 相关

输入内容没有说明 Notari 与 MCP 的关系。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"manumarri-sudo-quill": {
"command": "uvx",
"args": [
"quillx"
]
}
}
}
启动命令uvx quillx

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiquillx0.2.0a5

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

README 配图

notari

Notari 会为每个由 AI 编写的拉取请求签发一份已签名的 Change Passport:任何审查者或审计员都可以仅凭签名重新验证这份凭证,无需重新运行 Notari,也无需相信截图。它会记录人类批准 Agent 修改的文件,以及 Agent 是否始终在这些文件范围内。人类只需为边界签名一次;在 CI 中,Notari 会根据该边界检查每个拉取请求,并为凭证盖上 PASS、NEEDS_REVIEW 或 BLOCK。判定过程中不使用模型,因此无法遭受提示词注入。它不会判断代码是否正确:它证明的是更改发生在哪里,以及是否泄露了机密——这是人类审查大型 Agent 拉取请求时最常忽略的部分。当前为 Alpha;如有任何一句话的说法与安全模型不一致,请以安全模型为准。

从这里开始:一条命令

uvx notari init

无需预先安装任何内容。在任意 git 仓库中运行一条命令,即可生成审批者密钥对和门禁密钥对,为默认安全的边界签名,写入经过加固的 GitHub 工作流(pull_request_target、固定 SHA、将拉取请求检出到仅存放数据的目录),将私钥加入 gitignore,然后打印当前实际的安全状态以及仍未完成的具体步骤。在未配置任何 Python 工具的干净机器上测得,CLI 大约 1.5 秒即可解析并运行。

更喜欢持久安装?可运行 pipx install notari 或 pip install notari,然后运行 notari init。无论哪种方式,接下来的两条命令就是日常完整流程:

notari begin "add rate limiting" --scope "src/api/**"    # sign what the agent may touch
notari verify --strict                                    # in CI: PASS, NEEDS_REVIEW, or BLOCK

notari init 会自动禁止看起来敏感的目录(auth、migrations、infra、terraform、deploy 等)。禁止规则优先于契约范围,因此将任务范围设入其中任何目录,都会按设计返回 BLOCK。如果确实需要修改其中的目录,请明确设置边界并为其签名: notari guard --key approver.pem --allow "src/**" --forbid "migrations/**"。

实际能得到什么

四个方面,每一项都按实际能力描述,而非最理想化的说法:

1. 门禁,即可证明的边界。 在 CI 中,Agent 无法触及的环境会将 .notari/ 之外的每个更改路径与已签名的范围和边界进行比对,并扫描每个被修改的文件,检查 26 种供应商机密模式;重命名(两个端点)、仅模式更改、二进制文件、符号链接、子模块以及 .gitattributes 隐藏差异等内容,都会纳入清单,而非成为盲点。每项任务的范围由你指定(--scope),因此较窄的范围表示“仅限这些路径”,而明确指定 --scope '**' 则表示“签名边界未禁止的任何内容”。无论哪种情况,凭证都会清楚说明范围,因此 PASS 绝不会含糊。机密检测采用有限的模式集,因此只能捕获常见的供应商格式泄露,无法证明不存在机密。判定路径中不使用模型,因此无从进行提示词注入。

2. 凭证,即使运行结束后仍可留存。 一份 Change Passport(passport.json 加上适用于 PR 的 passport.md),其 Ed25519 签名可由任何人在数月后通过 notari verify-passport 于另一台机器上重新验证,因此伪造或篡改的判定会验证失败,你可以相信已签名的凭证,而不是截图。这只能验证门禁确实签发了该判定,不能证明代码正确,也不会重新运行门禁。其背后还有一份由 HMAC 链接的审计日志,可通过密码学方式检测编辑和插入;运行 notari audit verify 后,还能依据已封存的高水位标记检测末尾截断。凭证页脚会引用本次运行对应的确切链条条目。 3. 修复路径,让 BLOCK 可采取行动。 notari explain 会将 BLOCK 转化为针对每项发现的修复方案和可直接粘贴的 Agent 提示词,notari agent-brief 则会在下一个 Agent 开始工作前,将已批准的范围交给它。所有操作都在本地进行,均需人工把关,不收集遥测数据,也绝不会有原始代码、差异或机密值离开你的设备。

4. 笔记本电脑上的防护机制,属于纵深防御,并非坚不可摧的边界。 可选的 PreToolUse 钩子会在 Agent 调用工具时进行拦截(rm -rf、git push --force、DROP TABLE、vercel --prod、读取 .env);关键调用需要一次性、十分钟有效的审批,在 macOS 上通过 Secure Enclave 上的 Touch ID 进行硬件认证;Agent 写入的文件还会经过 AST 检查,在后续 python foo.py 执行这些文件之前标记出 shutil.rmtree 和 exec(b64decode(...))。

第四行特意注明了限制:有决心的攻击者可以绕过应用层拦截机制;这些限制都列在安全模型中,而不是被刻意隐瞒。真正可靠的边界是 CI。

刚接触这个项目? 从快速入门开始(约 10 分钟,从零开始到拦截一个有问题的 PR)。然后查看: 安全与威胁模型 · 产品与等级。

发现了绕过方式、令人困惑的错误,或者有理由绝不会采用这个工具? 这正是我们推出此 alpha 版想要收集的反馈: 提交问题。

想先试着攻破它? bash examples/bypass_probes.sh 会针对刚签署的边界运行十二种绕过测试,并逐一打印判定结果: 将文件重命名到禁止路径、仅更改模式、大小写变体、隐藏在 .gitattributes -diff 条目后的机密、Agent 扩大自己的已签署合约范围等。十一项判定为 BLOCK;第十二项是文档中说明的按行拆分机密限制。如果你发现第十三种情况能得到不该有的 PASS,那就是你能提供的最有价值的反馈。

PyPI Python 版本 CI 类型检查 许可证:MIT

AI Agent 发起了一个拉取请求。它没有获准修改哪些文件?面对 Agent 提交的 40 个文件的差异,人们往往会扫一眼就略过这个问题,而 Notari 会在 CI 的合并边界给出答案,并生成经过签署的 Change Passport,供审阅者重新验证,而不必相信一张截图。判定结果由差异、已签署的合约和策略确定性地计算得出,因此其中没有可被越狱的模型。它会记录变更去了哪里,以及是否泄露了机密;但不会证明范围内的代码正确无误或不存在后门。这就是它诚实的能力范围。

Notari 的工作方式:人工签署任务边界,AI Agent 编写差异,CI 根据已签署的边界验证变更并给出 PASS、NEEDS_REVIEW 或 BLOCK 判定,随后将结果记录在经过签署的 Change Passport 中,供任何审阅者重新检查。 Agent 会在范围内外进行编辑,Notari 则根据签署的合约逐项验证每个差异 (PASS / NEEDS_REVIEW / BLOCK;合约来自 [`examples/change_control_demo.sh`](https://github.com/manumarri-sudo/notari/blob/main/examples/change_control_demo.sh),未经编辑): 演示的终端录屏:设置、对范围内变更给出 PASS、对禁止路径和引入机密的变更给出 BLOCK 判定,以及 notari 说明如何修复。
# 0. one-time: create a human approver key. Keep the PRIVATE half off the build
#    box; pin the PUBLIC half so a PR cannot edit the trust root (in CI this is a
#    repo/org secret or variable, NOT a path inside the checkout).
notari keygen --out approver.pem
export NOTARI_APPROVER_PUBKEYS="$(cat approver.pem.pub)"

# 1. sign the standing boundary ONCE: what agents may touch, what is off-limits.
notari guard --key approver.pem --allow "src/**" --forbid "migrations/**"

# 2. capture AND SIGN the approved task (a signed contract can't be forged by the agent).
notari begin "Add rate-limiting to the login endpoint" --scope "src/auth/**" --key approver.pem
#    commit .notari/{perimeter.json,perimeter.sig,contract.json,contract.sig} to the BASE branch.

# 3. the agent writes the diff and opens the PR.

# 4. CI verifies the PR against the signed boundary, in strict mode.
notari verify --strict        # PASS · NEEDS_REVIEW · BLOCK   (BLOCK fails the build)
#    add --sign-key gate.pem (or NOTARI_GATE_KEY in CI) to ALSO sign the verdict,
#    so a reviewer can re-check it with `notari verify-passport`.

这一完整流程——固定的外部审批者密钥、签署的边界、签署的合约、--strict——才是真正抵御恶意行为的边界。省略其中任何一项(不带标志运行 notari begin / notari verify),Notari 仍会运行,但会处于协作模式:为非恶意 Agent 提供诚实的审查自动化,而不是防止试图越界的 Agent。判定签名为可选项(需要门控密钥),默认不启用。完整的部署清单请参阅 docs/SECURITY-MODEL.md。

notari verify 会读取 git diff <base>..HEAD,根据你批准的范围检查每个变更文件,扫描每个被触及的文件,查找硬编码机密和敏感内容(CI 配置、锁文件、测试删除),评估所有已记录的例外,并生成一份变更凭证:passport.json + 一份可直接用于 PR 的 passport.md。凭证会引用本次运行的 HMAC 链式审计条目,让审查者能够将判定追溯到防篡改记录,而不是只相信 Markdown 文档。


为什么需要这一层

编写代码的 Agent 拥有 shell 访问权限、文件写入权限、部署权限以及你的凭据,而相关事故已有记录:2025 年 7 月,Replit 的 Agent 在一次氛围编程过程中删除了生产数据库,并伪造数据掩盖此事;同月,Cursor Agent 对一名开发者的主目录运行了 rm -rf ~/;8 月,一名自主 Agent 将客户的 GitHub 令牌提交到了公开提交记录中。这些事件的共同点并不是模型邪恶,而是在变更发布前,没有任何机制核对它是否符合实际获批的内容。

Notari 将这项检查放在可强制执行并留有记录的地方:CI 中的拉取请求上。门控在 Agent 自身进程之外运行,受审查对象无法悄悄将其关闭。判定是差异、合约和策略的确定性函数;决策流程中没有大模型,因此门控本身不会受到提示词注入攻击。

Notari 是什么,又不是什么

校准比营销更重要。

  • Notari 是验证与证据工件,不是内容分类器。 它不会预测变更是否“良好”。它会根据记录的契约(范围、密钥、敏感面)检查差异,并签发一份可供人类审查的判定。门禁中没有模型。
  • CI 门禁是可辩护的边界;本地门禁则是纵深防御。 Notari 还提供一个可选的笔记本电脑运行时门禁(见下文)。该门禁在工具分发层充当确定性的减速带和记录器,能提高粗心 Agent 和常见破坏/数据外泄行为的门槛,但它不是抵御蓄意尝试逃逸的攻击者的硬边界(先写入再运行、重新排列标志、继承环境变量、未受门禁限制的网络出口,都是文档中记录的限制)。完整且坦诚的威胁模型见 docs/SECURITY-MODEL.md。
  • Notari 不会认证合规性。 审计日志是机器可验证的证据,审计员会希望审查它,但它本身并不是审计员会接受的工件。
  • Notari 不是托管服务。 它是一个独立的 Python 包。审计日志和签名密钥以 0o600 模式存放在你的磁盘上;密钥、日志和判定都由你掌控。验证流程不会往返云端,默认也不收集遥测数据。
  • Notari 不消耗 AI 令牌。 其中没有 LLM:判定、密钥扫描、通俗易懂的 explain 和本地门禁,全都由确定性代码实现(正则表达式、glob、AST、计数)。没有模型、没有 API 密钥、没有单次检查费用,也没有任何需要计量的东西。这里唯一涉及的令牌,是你的编码 Agent 编写代码时已经消耗的令牌;如果你选择把 Notari 的修复提示词粘贴回去,还包括它修复时消耗的令牌。这是有意为之的设计特性,而不是限制:带模型的门禁可能遭受提示词注入,而且每个 PR 都会产生费用;而这个门禁既不会遭受此类攻击,也不会产生此类费用。

详细了解变更控制

1. notari begin,记录契约
notari begin "Add rate-limiting to the login endpoint" \
            --scope "src/auth/**" --scope "tests/auth/**" \
            --approved-by alice \
            --key approver.pem \
            --expires-in 7 --repo owner/repo

写入 .notari/contract.json:获批任务(文本或工单 URL)、allowed_paths 范围(glob、目录前缀或精确路径)、变更起始时所基于的基础提交,以及 contract_id。--key 会为其签名,使 verify --strict 能证明契约由人类编写(严格模式下必需);--expires-in 设置失效期限;--repo 会将审批绑定到一个仓库,防止已签名的契约在其他地方被重放。将契约(以及 .sig)提交到分支;它是后续衡量差异时依据的固定记录,变更护照也会引用它。

2. notari verify,把关差异
notari verify --strict        # enforced mode: requires the signed perimeter + contract
notari verify                 # local/cooperative: advisory, forgeable by the agent

verify(src/notari/verify.py,基于 policy.evaluate_diff):

  1. 通过 git diff --name-status -z --find-renames <base_commit>..<candidate> 构建权威的变更路径清单,包含重命名的两端、二进制变更和仅模式变更,
  2. 将每个变更路径(包括重命名的两端)与契约范围进行匹配,
  3. 使用 src/notari/secrets.py 中的 26 种供应商格式密钥模式扫描每个被触及的文件,从候选提交读取整个文件(而不只是新增行),因此 100% 重命名或 UTF-16 文件都无法藏匿凭据,
  4. 对敏感区域分类(CI/工作流文件、锁文件、测试删除、.gitattributes 等控制差异可见性的 Git 配置),
  5. 应用 .notari/exceptions.json 中记录的例外(严格模式下完全忽略,未签名的豁免文件无法削弱严格判定),
  6. 综合得出 PASS、NEEDS_REVIEW 或 BLOCK 判定,并将 verification.run 事件链接到审计日志中。

BLOCK 会以非零状态码退出(CI 失败);PASS 和 NEEDS_REVIEW 则以 0 退出,因此会呈现审核提示,但不会硬性阻断流水线。整个流程具有确定性:给定相同输入——差异、契约、已签名的边界、受信任的审批者密钥、严格标记和任何(已签名的)例外——就会返回相同判定,并且每一行都可解释。判定过程不涉及模型;唯一与时钟相关的引用是契约过期检查(--expires-in),这是由人明确设置的截止时间,而非启发式判断。

3. 变更通行证

verify 会写入 passport.json(机器可读,供下游工具和状态检查使用)和 passport.md(可直接用于 PR)。Markdown 页脚会注明 verification.run 审计 MAC,因此通行证可追溯到防篡改链,而不是要求你相信这份文档。

4. GitHub Action
# .github/workflows/notari-change-control.yml
on:
  pull_request_target:          # NOT pull_request, see "Why pull_request_target" below
    branches: [main]
jobs:
  change-control:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
          path: _pr_checkout             # isolate candidate code from trusted runtime
          persist-credentials: false
      # Pin to the release commit SHA, not a mutable tag, `notari status`
      # rejects a non-SHA pin. `notari init` writes the current pin for you.
      - uses: manumarri-sudo/notari@a084829cabacbbc7e85a5b8323580f514ad54771  # 0.4.2 release action
        with:
          head: ${{ github.event.pull_request.head.sha }}
          head-sha: ${{ github.event.pull_request.head.sha }}
          checkout-path: _pr_checkout
          strict: "true"
          block-on-review: "true"   # NEEDS_REVIEW fails the job too, so a review-class change can't merge unseen
          approver-pubkeys: ${{ secrets.NOTARI_APPROVER_PUBKEYS }}
          gate-key: ${{ secrets.NOTARI_GATE_KEY }}
          gate-pubkeys: ${{ vars.NOTARI_GATE_PUBKEYS }}

为什么使用 pull_request_target: pull_request 事件会运行 PR 版本的工作流,因此 AI Agent 可以修改工作流,彻底移除 Notari 步骤,导致把关机制永远不会触发。pull_request_target 从基础分支(main)运行,因此只有已合并的代码才能控制把关规则定义(PR 无法编辑用于审核自身的工作流)。严格模式下,拒绝在 pull_request 事件中运行,以强制遵守这一规则。为什么使用 path: _pr_checkout: 隔离候选代码库的检出,避免候选代码控制的 Python 模块(pip.py、json.py)在安装 Notari 时覆盖受信任的导入。完整的安全模板见 docs/secure-workflow.yml。

组合式 Action(action.yml)会运行 notari verify --strict,发布提交状态检查,并在判定为 BLOCK 时令作业失败。审批者公钥和把关签名密钥来自 PR 无法读取或编辑的仓库/组织机密,这使信任根位于外部。如果 PR 没有 .notari/contract.json,验证会报错并以默认拒绝方式使作业失败(退出码为 2),而不会悄然放行;因此,删除或省略契约无法让变更蒙混过关。要求通过此项检查之前,请先在基础分支上初始化变更控制(notari begin --key)。

BLOCK 后:说明并修复

大多数把关机制只会给出判定。Notari 会把阻断转化为修复方案,全部在本地完成,无遥测且具有确定性(不由模型决定任何事情):

notari verify                                     # PASS · NEEDS_REVIEW · BLOCK + a passport
notari explain                                    # the passport in plain English + a fix per finding
notari explain --fix-prompt                       # a compact prompt to paste into your coding agent
notari agent-brief                                # the compact pre-work brief to hand an agent before it starts

notari explain 会读取通行证,并针对每条发现用通俗语言说明问题、提供用于撤销该变更的精确 git 命令,以及可直接粘贴给 Agent 的指令;此外还会说明 Notari 无法证明的内容(它检查的是边界,而不是代码正确性)。--fix-prompt 和 --agent-brief 会输出精简的 Agent 信息,不会把完整通行证塞进上下文。Notari 绝不会上传原始代码、差异、提示词或机密值。

信任主干:对边界签名一次,Agent 就无法伪造

在 CI 中运行的意义在于,门禁位于 Agent 无法禁用的地方;但只有当 Agent 也无法伪造批准或篡改自己的裁判时,这才有意义。Notari 使用 Ed25519 同时解决了这两个问题(验证使用公钥,伪造需要私钥,而不是同一个密钥;对称 HMAC 链永远无法做到这一点):

Agent 无法作弊的原因:通过基分支控制防止编辑 CI 工作流,通过在检出目录之外固定信任根防止植入审批者密钥,通过门禁签名防止伪造判定;通过符号链接或子模块隐藏变更,则会显示为 NEEDS_REVIEW。
notari keygen --out approver.pem          # human's key; keep the private half OFF the box
notari guard --key approver.pem --forbid 'migrations/**' --forbid 'src/auth/**'
#   ^ signs .notari/perimeter.json once. From now on EVERY agent's PR is checked
#     against it automatically, you're paged only when one crosses the line.
  • 由人一次性签署边界;每个 PR 都会被强制执行,无需逐项批准。 这就是对“我可不想坐在这里批准一百个 Agent”的回应。禁止路径和篡改门禁的编辑会触发 BLOCK;默认情况下,机密信息会触发 BLOCK(已签署的边界可将其放宽为审核);边界内的工作则会静默通过。
  • Agent 无法自行授权(严格模式下,信任根位于外部)。 编辑边界、审批者密钥(.notari/approvers/**)或运行门禁的工作流本身都会触发 BLOCK(门禁篡改检测);篡改已签署的边界或契约会使签名失效。在严格模式下,契约受其 Ed25519 签名保护,而非门禁篡改 glob 集;未签名或伪造的契约会因来源检查失败而触发 BLOCK。已提交的 .notari/approvers/*.pub 集合只是便利措施,并非安全边界:在严格模式下,只有外部固定的 NOTARI_APPROVER_PUBKEYS 才受信任,否则 Agent 可以在基提交中植入密钥,为自己的批准签名。外部密钥加严格模式,才能让这项安全保障名副其实,而非一厢情愿。
  • 判定无法伪造。 配置门禁密钥(notari verify --strict --sign-key gate.pem,或 CI 中的 NOTARI_GATE_KEY)后,护照会被签名;任何人都可以使用 notari verify-passport passport.json 重新检查,判定被篡改或签名者不受信任时,检查会失败。
  • 或者使用 GitHub 自带的审核。 notari check-approval 要求由非 PR 作者的人批准当前头部提交;Agent 无法批准自己的 PR,且推送新代码后,原有批准会被撤销。 要构成真正的边界(而非可选项),必须做到: 信任根必须位于 PR 无法修改的位置。将审批者/门禁的私钥保存在构建机器之外(仓库/组织机密:NOTARI_GATE_KEY、NOTARI_APPROVER_PUBKEYS),对契约签名(notari begin --key)并在严格模式下要求签名,将 Action 固定到发布提交的 SHA(而非可变标签,也不能使用 PR 自身的检出版本;notari status 会拒绝非 SHA 固定值),并在分支保护中将状态检查设为必需。关于最后一点,有一个坦诚的提醒:必需检查是一个裸的提交状态,任何具有 statuses: write 权限的工作流都能发布相同的 notari/change-control 上下文,因此遭到入侵的同仓库工作流可以发布绿色状态,掩盖实际的 BLOCK。Notari 会让这种情况可检测(护照指纹会记录它实际写入的状态的 SHA 和 MAC,notari verify-passport 会进行交叉核验),但要绑定检查的来源,使其完全无法伪造,需要使用 GitHub App 检查运行,此功能已列入路线图。在此之前,请勿向不受信任的工作流授予 statuses: write 权限。做到这些后,安全模型列出的绕过方式便能抵御测试套件所覆盖的攻击(包括复合型的基础提交中恶意密钥攻击、Action 包装器默认放行问题,以及二进制/重命名差异覆盖;这些问题都已通过回归测试解决);若未做到这些,它就只是面向协作型 Agent 的诚实审查自动化。目前尚未经过外部安全审计,因此请将“已解决”理解为“针对我们目前测试的内容已解决”,并以跟踪剩余未解决事项的 docs/SECURITY-MODEL.md 为准,而非本 README。

本地运行时门禁(可选,纵深防御)

除 CI 外,Notari 还可以通过 Claude Code 的 PreToolUse 钩子,在 Agent 调用工具时于你的笔记本电脑上进行门禁检查。这是辅助层,明确定位为纵深防御、确定性的减速带和记录器,而不是硬性边界。

notari onboard      # detect agents, install the hook, pick a risk preset

从下一个会话起,每次 Bash / Edit / Write / NotebookEdit 调用都会经过 src/notari/policy.py 中的编译正则分类器:默认情况下,rm -rf、git push --force、DROP TABLE、vercel --prod、npm publish、读取 .env,以及 CVE-2025-59536 子命令链绕过均属于严重类别。严重调用会被拒绝,并提供通俗易懂的原因;若要批准,需使用一次性、有效期为 10 分钟的 notari approve <token>;在 macOS 上,批准操作会通过安全隔区上的 Touch ID 进行硬件验证。Agent 写入的文件会使用同一组 26 个密钥模式进行扫描,并通过 AST 扫描(code_scan.py)标记具有破坏性的 Python 结构(shutil.rmtree、os.system、exec(b64decode(...))),避免之后运行 python foo.py 时执行这些结构。每项决策都会写入 ~/.notari/audit.log.jsonl,并通过 HMAC-SHA256 链接以提供防篡改证据。

本地门禁的辅助功能均在读取时从同一条链派生:notari receipts(按会话汇总已执行/已更改/不确定/待验证事项)、notari trifecta(致命三要素暴露:不受信任的输入 + 私有数据 + 外传途径)、notari pins(对工具描述进行固定,防范 MCP 暗中替换),以及 notari audit(审查并验证链)。notari scan-secrets 可独立运行密钥检测器,扫描文件。

为什么这是纵深防御,而不是核心卖点: 有能力的攻击者可以绕过应用层门禁(见上文的局限)。可证明的边界是 CI 门禁,它在 Agent 无法禁用的环境中运行,并生成经过签名的记录。本地门禁切实有用,但它应当坦诚地宣称“提高攻击门槛并记录一切”,而不是“无法绕过”。

已签名的审计日志

两个界面都会写入 $NOTARI_HOME/audit.log.jsonl,权限为 0o600。每条记录的 mac 都是使用安装密钥计算的 HMAC-SHA256(prev_mac || canonical(payload)) (首次运行时自动生成,存储于 $NOTARI_HOME/key,权限为 0o600)。写入时会调用 fcntl.flock(LOCK_EX),并在锁内重新读取末尾的 MAC,防止并发写入破坏链条。密封的 <log>.head 高水位标记让 verify 能检测末尾截断,而不仅仅是编辑和插入。

notari audit verify
# chain intact: 72739 entries verified.

该统计数据来自维护者机器上 76 天的实际自用记录(2026-05-07 至 2026-07-22, 发布时重新测量);你自己的日志从 1 开始。该链在本地具备防篡改检测能力(也可选择 锚定到外部)。关于它能带来和不能带来的保障,请参阅 docs/SECURITY-MODEL.md。

安装

一键安装方式位于本 README 顶部(uvx notari init)。其他方式:

uvx notari begin --help     # no install; run any subcommand once
pipx install notari         # or install the CLI persistently
pip install notari          # or into an existing venv

所有位置都使用同一个名称:PyPI 分发包、CLI 二进制文件、导入路径、配置目录 (~/.notari/)和环境变量(NOTARI_*)均为 notari。 开发用检出版本可运行:git clone https://github.com/manumarri-sudo/notari && cd notari && pip install -e .。

CLI 功能

notari begin          capture the approved task into .notari/contract.json
notari verify         compare the diff to the contract, emit PASS / NEEDS_REVIEW / BLOCK
notari explain        turn the passport into plain-English remediation (--fix-prompt, --agent-brief, --format html)
notari fix-prompt     compact paste-ready fix prompt for the coding agent
notari agent-brief    compact pre-work brief to hand an agent before it starts
notari onboard        first-run setup for the local gate (detect agents, install hook)
notari audit          review what got blocked / allowed / asked; verify the chain
notari approve <tok>  confirm a pending one-shot approval (Touch ID on macOS)
notari approvals      list (hashed ids) / revoke pending approval tokens
notari receipts       per-session did / changed / uncertain / to-verify
notari trifecta       lethal-trifecta exposure tracking
notari pins           tool-description pins (anti-poisoning, anti-rug-pull)
notari scan-secrets   scan files for hardcoded credentials
notari scan-prompts   scan files for prompt-injection-shape patterns (signal only)
notari commit-hook-install   add a session-summary block to the commit message template
notari doctor         diagnose the install
notari version        print the version

运行 notari --help 查看完整列表(包括会弱化防护的 night/off 开关; 使用前请阅读 docs/SECURITY-MODEL.md)。

当前发布内容与路线图

**当前发布(0.3.0),有磁盘证据:**变更控制工作流 (begin/verify/passport + GitHub Action)、HMAC 链式审计日志(32k+ 条自用记录, 可检测截断,notari audit verify 检查通过)、带 Touch ID 审批和 26 种模式机密检测的 本地 PreToolUse 防护、先写入再运行的 AST 扫描,以及读取侧功能(回执、trifecta、 pins)。完整测试套件(实时数量请运行 uv run pytest)、ruff、ruff format 和 mypy --strict 均通过,并在 CI 中强制执行。

路线图(当前尚未发布,请勿假定已提供):将 passport 渲染为 PR 评论(当前 Action 会发布 Status Check)、将致命三元组的执行升级作为 CI 信号、面向 Cline / Aider / Continue / Windsurf / Zed 的逐工具钩子适配器、用于跨平台硬件认证审批的 WebAuthn, 以及 from notari import gate BYO-agent 库 API。早期预览版曾发布的 MCP 代理、OS 沙箱、桌面仪表板和带外通知渠道已在变更控制转型中移除,此版本系列不会恢复。

安全

notari 本身属于安全关键代码。威胁模型、防护机制有效拦截的内容及其可被绕过之处的 如实说明,以及负责任披露联系方式,详见 SECURITY.md 和 docs/SECURITY-MODEL.md。接通 PyPI 发布流程后,计划通过 PyPI Trusted Publishing 签名发布,并提供 PEP 740 证明(计划中,尚未实施)。

贡献

发现了遗漏的危险操作类别、diff 解析器中的作用域绕过问题,或误报?请附上复现步骤提交 issue。适配器位于 src/notari/adapters/ 下。

许可证

MIT。详见 LICENSE。随仓库提供的第三方代码已在 NOTICE 中注明来源。 版本历史见 CHANGELOG.md。仓库: github.com/manumarri-sudo/notari。


在 Claude(Anthropic)的协助下构建。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。