The project's README from github.com/MaxHu-xuan/chat-archive-guard. As one markdown file: README.md.
English: English overview | English technical reference | Project information
准备保存、迁移、共享或分析聊天导出时,可以先让 ChatArchiveGuard(聊天归档守护)在 自己的电脑上做一次只读检查:
扫描器只读取你指定的文件或目录,不修改原文件,也不上传数据。使用 --summary-only 时,
报告只保留真实状态、数量和类别,不包含文件名或命中值。默认报告仍会显示相对文件名,方便
本地定位问题。运行时没有网络客户端、遥测或自动更新功能。
它是一道面向交付或迁移前检查的审计门禁,不是聊天归档阅读器、导入器、搜索器,也不能 证明消息业务完整或来源真实。
一次扫描可以回答三个实际问题:
这里的聊天归档完整性指文件格式、SQLite 结构和本次扫描覆盖状态。它不等于消息完整性, 也不能证明归档没有丢消息、来源真实或文件从未被篡改。
| 你的问题 | 选择 |
|---|---|
| 分享或迁移聊天导出前,本地检查疑似秘密、个人信息形态、格式、SQLite 与扫描盲区 | ChatArchiveGuard(聊天归档守护),当前项目 |
| 确认最终 PPTX 及随附验收证据仍匹配结构检查后生成的 HMAC 签名收据 | ArtifactProof(PPTX 交付物验真) |
| 重启后核对卡住任务、超时与待投递状态,不把未知结果猜成成功 | TaskStateGuard(任务状态守护) |
三个工具解决的是不同问题,可以单独使用;ChatArchiveGuard 不负责 PPTX 验真或任务状态修复。
ChatArchiveGuard 会按文件类型执行不同检查:
PRAGMA quick_check(1),扫描普通表和可访问的 FTS 虚拟表文本;
FTS 影子表不会重复计数。files_seen、files_scanned、complete 和 truncated 区分遍历范围与实际
内容检查范围。轮转日志会作为独立文件处理。只有最终扩展名属于支持范围的文件,例如 history.1.log,
才会进入文本扫描;history.log.1 和压缩后的 .gz 文件不会被自动识别为文本。工具不会
拼接轮转序列,也不会判断时间段是否连续。
默认报告中的相对文件名仍是元数据。使用 --summary-only 后,JSON 和文本输出都会省略
全部发现明细与相对文件名,只保留真实状态、扫描计数和类别汇总,适合 CI 或分享
脱敏报告。无论使用哪种报告模式,退出码和 finding_count 都不会被改写。
摘要模式不会建立用户或渠道隔离。类别计数仍然汇总整个扫描根目录,因此调用者应先把根 目录限制在自己有权检查的单个数据集,不要用一个跨用户目录生成共享摘要。
需要 Python 3.11 或更高版本。安装已发布版本时,建议先创建隔离环境,再从 PyPI 安装, 避免影响系统 Python。
macOS 或 Linux:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install chat-archive-guard
chat-archive-guard /path/to/archive
chat-archive-guard /path/to/archive --json --summary-only
Windows PowerShell 使用 Python Launcher 和不同的路径写法:
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install chat-archive-guard
.\.venv\Scripts\python.exe -m chat_archive_guard C:\path\to\archive
.\.venv\Scripts\python.exe -m chat_archive_guard C:\path\to\archive --json --summary-only
同时查看退出码和 ok、complete、truncated。只有没有发现项、扫描完整且未截断时,
ok 才会是 true。
如果正在审核尚未发布的候选版本,或希望从源码安装,请先进入你已核对的源码仓库根目录
(即包含 pyproject.toml 的目录)。在已经创建并激活的 macOS 或 Linux 隔离环境中运行:
python -m pip install .
Windows PowerShell 使用已经创建的同一个隔离环境:
.\.venv\Scripts\python.exe -m pip install .
如需从 wheel 离线安装,请从同一个
GitHub Release 页面下载
SHA256SUMS 和 chat_archive_guard-0.1.0-py3-none-any.whl,并把两个文件放在同一目录。
SHA-256 核对只能确认 wheel 与该清单一致,不能替代对发布来源的核对。
macOS 或 Linux 先运行:
wheel="chat_archive_guard-0.1.0-py3-none-any.whl"
if command -v sha256sum >/dev/null 2>&1; then
awk -v name="$wheel" '$2 == name { print }' SHA256SUMS | sha256sum -c -
else
awk -v name="$wheel" '$2 == name { print }' SHA256SUMS | shasum -a 256 -c -
fi
只有在输出 chat_archive_guard-0.1.0-py3-none-any.whl: OK 后,才在已经激活的隔离环境中安装:
python -m pip install --no-index --no-deps ./chat_archive_guard-0.1.0-py3-none-any.whl
Windows PowerShell 先核对同一目录中的文件:
$wheel = "chat_archive_guard-0.1.0-py3-none-any.whl"
$rows = @(Get-Content .\SHA256SUMS | Where-Object {
$_ -match ("^[0-9a-f]{64} " + [regex]::Escape($wheel) + "$")
})
if ($rows.Count -ne 1) { throw "Expected exactly one checksum row" }
$expected = ($rows[0] -split " ", 2)[0]
$actual = (Get-FileHash -Algorithm SHA256 ".\$wheel").Hash.ToLowerInvariant()
if ($actual -ne $expected) { throw "SHA-256 verification failed" }
"SHA-256 OK: $wheel"
只有核对成功后才安装:
.\.venv\Scripts\python.exe -m pip install --no-index --no-deps .\chat_archive_guard-0.1.0-py3-none-any.whl
未安装时,macOS 和 Linux 可以从你已核对的源码仓库根目录运行:
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m chat_archive_guard /path/to/archive --json
Windows PowerShell 使用不同的环境变量语法:
$env:PYTHONDONTWRITEBYTECODE = "1"
$env:PYTHONPATH = "src"
py -3 -m chat_archive_guard C:\path\to\archive --json
仓库附带的生成器只创建两份固定的虚构数据:一份 JSONL 和一份 SQLite。它不会读取现有 文件,也不会覆盖已有目录。演示中的测试标记都明确写着永不有效,只用于证明检查器确实能 发现问题,不是可用凭据,也不来自任何真实对话。
macOS 或 Linux(在仓库根目录执行):
demo_parent="$(mktemp -d)"
demo_parent="$(cd "$demo_parent" && pwd -P)"
demo_dir="$demo_parent/chat-archive-guard-demo"
PYTHONDONTWRITEBYTECODE=1 python3 scripts/generate_demo.py "$demo_dir"
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m chat_archive_guard "$demo_dir" --summary-only
实测输出如下:
synthetic demo: PASS files=2
FAIL files_seen=2 files_scanned=2 finding_count=3 complete=true truncated=false details_omitted=true findings_omitted=true
category=format.invalid_jsonl count=1
category=secret.assignment count=1
category=secret.provider_key count=1
Windows PowerShell(在仓库根目录执行):
$demoDir = Join-Path ([System.IO.Path]::GetTempPath()) ("chat-archive-guard-demo-" + [guid]::NewGuid())
$env:PYTHONDONTWRITEBYTECODE = "1"
$env:PYTHONPATH = "src"
py -3 scripts/generate_demo.py $demoDir
py -3 -m chat_archive_guard $demoDir --summary-only
Windows 的文本检查结果相同,但标准 Python 会按安全边界拒绝直接检查 SQLite,因此输出为:
synthetic demo: PASS files=2
FAIL files_seen=2 files_scanned=1 finding_count=3 complete=false truncated=true details_omitted=true findings_omitted=true
category=format.invalid_jsonl count=1
category=secret.assignment count=1
category=sqlite.sidecar_unsafe count=1
两组扫描命令的退出码都会按设计返回 1,因为演示数据故意包含三个发现项。这表示门禁
发现了问题,不表示生成器或扫描器运行失败。演示结束后可以删除刚创建的唯一临时目录。
| 内容 | 含义 |
|---|---|
退出码 0 |
没有发现项,并且符合范围的内容完成扫描 |
退出码 1 |
发现问题,或有符合范围的内容未能完整检查 |
退出码 2 |
扫描路径或参数无效 |
files_seen |
遍历到的常规文件数量,包括不支持内容检查的文件 |
files_scanned |
已进入受支持内容检查阶段的文件数量 |
finding_count |
所有类别的真实发现总数,包括摘要模式省略的明细 |
complete |
符合当前检查范围的内容是否全部完成检查 |
truncated |
是否因限制、读取失败或安全拒绝留下未检查内容 |
findings |
默认报告中的相对路径、固定类别和数量,不含命中值 |
details_omitted、findings_omitted |
摘要模式明确表示明细和文件名已省略 |
下面是默认 JSON 模式扫描一个合成无效文件后的完整结果。
format.invalid_json 表示 JSON 格式错误:
{
"schema_version": 1,
"ok": false,
"complete": true,
"truncated": false,
"root": ".",
"summary": {
"files_seen": 1,
"files_scanned": 1,
"finding_count": 1,
"categories": {"format.invalid_json": 1}
},
"findings": [
{"path": "broken.json", "category": "format.invalid_json", "count": 1}
]
}
complete=true 只表示符合当前范围的内容完成检查,不代表聊天记录在业务上完整,也不代表
工具能证明文件中不存在任何敏感信息。
| 能力 | Linux | macOS | Windows |
|---|---|---|---|
| 文本、JSON、JSONL 检查 | 支持 | 支持 | 支持 |
| SQLite、WAL、SHM 检查 | 提供 O_NOFOLLOW 时支持 |
提供 O_NOFOLLOW 时支持 |
标准 Python 下安全拒绝 |
| 文件权限检查 | POSIX 权限位 | POSIX 权限位 | 不推断或审计 ACL |
| 链接防护 | 拒绝或跳过符号链接 | 拒绝或跳过符号链接 | 拒绝或跳过重解析点及类似入口 |
Windows 标准库 Python 没有本项目安全边界要求的原子 no-follow 打开能力。遇到 SQLite 时,
工具会返回 sqlite.sidecar_unsafe,并设置 complete=false、truncated=true,不会降低保护
等级后继续读取。
内容检查覆盖 .txt、.md、.log、.csv、.tsv、.yaml、.yml、.json、
.jsonl 和 .ndjson。.db、.sqlite、.sqlite3 以及带 SQLite 文件头的文件会按
SQLite 处理。
压缩包、加密文件、专有格式、附件、图片、音频和其他二进制内容不在检查范围内。这些常规
文件仍计入 files_seen,并在 POSIX 系统上接受权限检查,但不计入 files_scanned。
工具不会验证消息完整性(message completeness)、来源归属(source attribution)、导出 时间范围、参与者身份或平台签名。它也不是聊天阅读器、备份恢复工具、杀毒软件、OCR 工具、 取证工具或完整的数据防泄漏系统。匹配结果只是风险提示,可能存在误报和漏报。
不会。安装后的扫描器只读取本地路径,没有网络客户端或遥测。常规安装可能访问包索引;
需要完全离线时,请按前述步骤从同一个 GitHub Release 下载 wheel 和 SHA256SUMS,
核对后再使用 --no-index --no-deps 安装。
不能。工具只检查支持的文本、JSON、JSONL 和 SQLite 内容,不要求文件来自特定应用。 压缩、加密、专有格式和附件内容不受支持。
不能。工具可以报告文件格式、SQLite 快检和扫描覆盖状态,但无法知道平台是否漏导、记录 是否被删除,也不能认证某条消息来自哪个平台、账户或设备。需要这类结论时,应另外保存并 核对原始来源、耐久记录、可读归档、记录计数、时间范围、导出签名或可信来源回执,并对 轮转来源的归属冲突采用安全拒绝策略。本项目不建立或修复这些跨层关系。
把需要检查的未压缩日志放在同一扫描根目录下,并确保最终扩展名是 .log。每份文件会独立
扫描,但工具不会还原轮转顺序、去重或证明时间覆盖连续。压缩日志需要先在受控目录中安全
解包,解包能力不属于本项目。工具也不会根据文件名推断日志属于哪个用户、渠道或来源。
不代表。完整且无发现的结果只说明已检查内容没有触发当前规则。未知模式、不支持的格式、 语义重识别和检测器漏报仍然可能存在。
可以,但 CI 必须有权读取输入。建议使用 --json --summary-only 读取真实状态与类别汇总,
避免在构建日志中暴露相对文件名。不要把真实聊天内容上传为公开构建产物。本项目自己的 CI
只使用运行时生成的合成数据。
0700 的临时目录和权限为 0600 的临时文件。工具重新校验来源身份和 SHA-256,
只让 SQLite 打开私有副本,再在内存备份上运行 PRAGMA quick_check(1) 和内容检查。扫描器只使用 Python 标准库。完整边界和残余风险见
THREAT_MODEL.md。
secret.*:私钥标记、提供商密钥、Bearer 令牌、凭证赋值和 JWT 形态值;pii.*:邮箱、部分电话、IPv4、证件号形态和通过 Luhn 校验的银行卡号形态;format.*:无效 UTF-8、JSON 或 JSONL;sqlite.*:快检、打开、结构或表扫描失败;permissions.group_or_other:POSIX 文件向组或其他用户授予了权限;scan.*:链接、读取错误或资源限制。| 参数 | 默认值 | 最大值 |
|---|---|---|
--max-file-mib |
16 MiB | 256 MiB |
--max-sqlite-rows |
100,000 | 1,000,000 |
--max-sqlite-value-kib |
1,024 KiB | 16,384 KiB |
--max-files |
10,000 | 100,000 |
--max-findings |
10,000 | 100,000 |
达到文件数、发现数、字节、行数或值大小限制时,结果会出现对应发现项,并设置
complete=false、truncated=true。有限扫描不会因为未检查内容暂时没有命中而返回健康
结果。
ChatArchiveGuard 采用 Apache License 2.0,详见
LICENSE 和
PROVENANCE.md。
参与贡献时请只使用合成数据。支持、安全、贡献规范与项目记录见
SUPPORT.md、
SECURITY.md、
CONTRIBUTING.md、
CODE_OF_CONDUCT.md、
CHANGELOG.md、
RELEASE_NOTES.md 和
RELEASING.md。
需要帮助、报告安全问题或参与贡献时,请按对应文档操作。版本记录、发布说明和维护者发布 流程分别列出,方便使用者与贡献者直接找到所需内容。
Before you store, migrate, share, or analyze a chat export, run ChatArchiveGuard locally to:
The scanner reads only the file or directory you choose. It does not modify the
source or upload data. With --summary-only, the report keeps real status,
counts, and categories while omitting filenames and matched values. Default
reports retain relative filenames for local troubleshooting. The runtime has no
network client, telemetry, or automatic update check.
It is a pre-delivery or pre-migration audit gate, not a chat archive reader, importer, search tool, or proof of message completeness or source authenticity.
Try the one-minute synthetic demo, or compare the three related tools.
One scan answers three practical questions: