关于 tracewatch
tracewatch 持续保存 Security Wave 工具的扫描报告,用于跟踪变化、发现来源和检测延迟。它面向调查代码库安全问题的团队,使用仅追加的本地 JSONL 存储,并区分已证实、推断和未能确定的证据。
主要功能
- 01导入并跟踪扫描发现
- 02比较新增、已解决和变化项
- 03追溯发现对应的提交与 PR
- 04监视文件、议题和 PR
- 05报告判定趋势与检测延迟
适用场景
- 01比较代码库不同版本的安全扫描
- 02查找问题源自哪个提交和 PR
- 03衡量新代码库内容的检测时间
- 04查看未解决问题和安全趋势
MCP 相关
`tracewatch mcp` 命令提供 stdio MCP 服务,包含扫描导入、差异比较、来源追踪、代码库健康度、监视状态、发现列表和问题说明等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
7收录的工具列表 · 更新于 3 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | 否 | 用于归档扫描结果的仓库键(默认值:来自 git remote 的 GitHub slug,否则为目录名称) |
| path | string | 是 | 要扫描的仓库或目录的本地路径 |
| tools | array | 否 | 要运行的工具子集(默认值:全部六个) |
详细介绍
tracewatch
Security Wave 的可观测性、跟踪与根因分析。
Security Wave 工具(hookcheck、actionpin、injectcheck、mcpvet、depguard、flowcheck)回答的是“这次扫描中当前有什么问题”。tracewatch 是这一波工具的记忆和秒表。它会随时间接收这些工具的 JSON 报告,并回答事件调查真正关心的问题:
- 自上次扫描以来发生了什么变化?某个 pin 是否悄悄退回到可变标签?某个已固定 action 下的 ref 是否发生了变动?2025 年 3 月的 tj-actions 事件就是这种情况:标签在所有信任它的仓库中被重新指向,只有运行过一次扫描的人根本看不到这种变化。
- 这个发现源自哪里?tracewatch 会将发现归因于引入它的 commit(使用 git pickaxe 搜索发现本身的内容)以及包含它的 pull request,并将每条陈述标记为已确认、推断或未能证实。
- 我们发现问题有多快?监视模式会在新问题、PR、文件和树变更出现时扫描并记录每项的检测用时,因此“早期检测”是一个可衡量的数字。对比基准很重要:托管式 AI 防火墙会在提示词提交时检测,此时 Agent 已经读取了内容。tracewatch 会在内容静止时和到达时检测,早于任何 Agent 会话的开始。
- 整体情况是否在改善?按仓库统计整个扫描历史中的 verdict 趋势、按工具和严重程度划分的未解决发现、已解决发现的平均未解决时长,以及检测延迟统计数据。
确定性、离线优先、本地存储,可用 grep 搜索。没有托管后端、账号或遥测数据。
安装
npx -y @reneturcios/tracewatch --version
npm install -g @reneturcios/tracewatch
docker run -i --rm ghcr.io/cloudcorprecords/tracewatch mcp
快速开始
# scan a repo with all six tools and start tracking it
tracewatch ingest ~/src/myrepo
# what changed since the previous scan?
tracewatch diff myrepo
# where did this finding come from?
tracewatch blame myrepo --finding tw_0123456789abcdef
# health over time
tracewatch report myrepo
# watch a directory and scan new content on arrival
tracewatch watch ~/src/myrepo --interval 30
跟踪内容
每次摄取都会存储一条扫描记录(时间戳、工具版本、verdict、git HEAD),并为每项发现存储一条观测记录。发现带有稳定 ID:由工具、规则、规范化位置和内容签名的哈希组成。同一项发现会在不同扫描和工具版本中保持相同身份;编辑内容不会改变身份,但会改变 ID 版本,diff 报告会将其标记为 CHANGED。
Diff 分组:NEW、RESOLVED、CHANGED(包含字段级的新旧值)、verdict 变更,以及 REF EVENTS。每当 action 的 ref 或分类发生变化时,都会触发 ref 事件,并明确列出两个值:
- pin-regression:从 PINNED 变为 MUTABLE 或 BRANCH
- pin-improvement:从 MUTABLE 或 BRANCH 变为 PINNED
- ref-move:在同一分类内 ref 发生变化(对于已固定的 action,即 SHA 本身发生了变化)
归因(根因)
tracewatch blame myrepo --rule CURL-PIPE-SH --file package.json
tracewatch blame myrepo --finding tw_0123456789abcdef --json
证据会单独标记,绝不混为一谈:
- CONFIRMED:通过本地克隆中对发现内容关键词运行
git log -S找到的引入 commit;通过git blame找到的当前行 commit;当克隆仓库配置了 GitHub remote 时,从 GitHub API(commits/{sha}/pulls)获取的 PR 关联;以及直接来自存储本身的 ref 历史和首次/最后一次发现时间。 - INFERRED:基于旁证的陈述,并明确写作推断(例如,引入 commit 与当前行 commit 不同时,说明该行后来被重写,但内容并非由此引入)。
- NOT ESTABLISHED:任何无法证实的内容,并说明原因(未记录克隆仓库、没有 GitHub remote、API 无法访问)。绝不猜测来源信息来填满页面。
监视与检测时间
tracewatch watch ~/src/myrepo --interval 60 --alerts alerts.jsonl
tracewatch watch owner/repo --path ~/src/myrepo-clone --interval 60
本地模式会轮询目录:新建或更改的文本文件会在被轮询发现的那一轮由 injectcheck 扫描;git HEAD 移动会触发完整摄取和差异比较。GitHub 模式会轮询 owner/repo 标识:新 issue 和 PR 会在出现时扫描,HEAD 移动会被记录(如果通过 --path 传入本地克隆,则也会扫描)。每次检测都会写入一条记录,检测时间 = 检测时间减去内容自身的创建时间(issue 的 created_at、提交时间、文件创建时间)。每轮结束后都会保存状态检查点,因此重启监视后会接续运行,不会对历史内容重复告警。告警会以 JSONL 格式流式输出到 stdout 和 --alerts 文件。
轮询是可移植的后备方案。在 CI 中,基于事件的方式最快:
name: tracewatch-issues
on:
issues:
types: [opened, edited]
pull_request:
types: [opened, edited, synchronize]
permissions:
contents: read
jobs:
scan-new-content:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
- name: Scan the new issue or PR body on arrival
env:
BODY: ${{ github.event.issue.body || github.event.pull_request.body }}
run: |
printf '%s' "$BODY" > /tmp/body.md
npx -y @reneturcios/injectcheck file /tmp/body.md --json > /tmp/report.json
npx -y @reneturcios/tracewatch import ${{ github.repository }} --report injectcheck=/tmp/report.json
明确说明一个已知限制:GitHub 监视模式通过本地 ghapi 助手读取数据,其输出会截断较长的响应;如果 issue 轮询的结果无法完整解析,就会记录为监视备注,并在下一轮重试,而不是部分采信。上面的 CI 模式没有这个限制,是 issue 扫描推荐的生产方案。
报告
tracewatch report myrepo # human
tracewatch report myrepo --json # machine
tracewatch findings myrepo --tool hookcheck --status open
健康报告包含每次扫描的判定趋势、按工具和严重程度划分的未解决发现、已解决数量、已解决发现的平均未解决时长(从首次出现的扫描到该发现消失的扫描)、所有引用事件,以及检测延迟统计(数量、中位数、最大值、按类型划分)。
MCP
tracewatch mcp 会启动一个基于 stdio 的 MCP 服务,提供七个工具:
| 工具 | 功能 |
|---|---|
| ingest_scan | 在本地路径上运行六个工具并存储扫描结果 |
| diff_scans | 比较两次扫描之间的 NEW / RESOLVED / CHANGED、判定变化和引用事件 |
| finding_provenance | 某项发现的引入提交、当前行提交、PR、引用历史 |
| repo_health | 判定趋势、未解决发现、平均未解决时长、检测延迟 |
| watch_status | 每个受跟踪的仓库:扫描次数、上次扫描、未解决发现、中位 TTD |
| list_findings | 按工具、严重程度、状态筛选受跟踪的发现 |
| explain_finding | 某项发现的完整证据包,可据此采取行动 |
存储
以仅追加的 JSONL 格式存储在 ~/.tracewatch 下(可使用 --store
或 TRACEWATCH_STORE 覆盖):scans.jsonl、findings.jsonl、detections.jsonl、alerts.jsonl,以及 watch-state.json 检查点。特意采用纯文本格式。每次读取时都会根据观察序列推导发现状态,而不会将其存储为可变状态,因此存储数据不会自相矛盾。相同的存储状态始终会生成相同的差异和报告输出。退出码:0 表示成功或没有更改;1 表示差异中发现了更改;2 表示用法错误或完全失败;141 表示报告送达前,读取方关闭了输出管道。
诚实原则
- 判定是扫描结果,不是安全声明。tracewatch 会报告六个工具发现了什么以及何时发现;它不会认证仓库没有问题。
- 检测时间根据内容自身的时间戳衡量,并按每次检测记录;报告展示的是分布,而非最佳情况。
- 归因会区分已确认的证据和推断,并明确说明“尚未证实”。
depguard 范围说明
depguard 发现仅在比较场景中存在:依赖项相对于基线被添加、删除或更改。tracewatch 会端到端保留这一上下文。每条 depguard 发现都包含基线(git 引用、目录路径或无)、目标路径、运行模式,以及该发现对应的变更类型和版本变动;扫描记录也会在扫描级别包含相同上下文,因此差异可以说明相对于什么发生了哪些变化。
直接运行导入(tracewatch ingest)会以离线快照模式运行 depguard,对裸目标进行扫描,发现清单和锁文件中的问题(包括疑似拼写仿冒项),并将基线记录为无。要进行完整的基线/目标比较,需要指定裸目标中未提供的基线:自行运行 depguard 并使用 --base <ref> 或 --base-path <dir>,然后导入报告(tracewatch import <repo> --report depguard=<file>),差异上下文便会与发现一同写入存储。
MIT。属于 Security Wave:hookcheck(持久化钩子)、actionpin(Actions 固定版本)、injectcheck(Agent 读取内容中的提示词注入)、mcpvet(MCP 服务和技能审查)、depguard(依赖变更防护)、flowcheck(工作流权限强化)、tracewatch(可观测性和根因分析)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。