feat(privacy): unify redaction and data minimization behind one rule source - #64
feat(privacy): unify redaction and data minimization behind one rule source#64yjg-djb wants to merge 2 commits into
Conversation
52cbdb9 to
83db04e
Compare
测试报告(按维护者在 #62 上要求的格式补充)1. 实际执行的命令bun install --frozen-lockfile # 依赖安装(CI 同款)
bun run typecheck # 全 workspace 类型检查(CI gate 1)
bun test --isolate # 全仓单测(CI gate 2)
bun test packages/shared/src/privacy # 新增 privacy 模块
bun test packages/shared/src/diagnostics # 诊断/脱敏边界
bun test packages/shared/src/evaluation # 评测产物脱敏
# CI 密钥扫描等价命令(pr.yml Secret scan 的 grep 模式原样本地执行)→ No secret patterns found.2. 关键环境信息
3. 每组测试 pass/fail 数量
4. 关于 5 个失败:均可在当前 main 复现,与本 PR 无关在干净 main(
CI 在 ubuntu 运行,不受影响。如需要我可以另行提一个修复 Windows 测试兼容性的 PR。 5. 针对性脱敏用例结果(新增单测,全部通过)
6. Canary 泄漏检查(等价于 CanaryScanner 的实际执行结果)将 9 类已知 canary secret(sk- key / Bearer / cookie / 连接串 / URL query / JWT / whsec_ / AKIA / x-api-key)注入各真实边界后序列化输出并扫描,canary 值零残留: fail-closed 行为(循环引用 / 超深嵌套 / 内部异常 → |
83db04e to
92b1cab
Compare
helsome
left a comment
There was a problem hiding this comment.
这条实现和测试报告已经明显优于重复的 #62(#62 已关闭为 superseded),当前只保留 #64 作为 #19 主实现。现有 Bun 1.4.2 / Windows、privacy/diagnostics/evaluation focused tests、全仓 baseline 对照、canary 扫描都有效。
但 #19 属隐私/secret 出站边界,Issue 自身明确要求:必须走一次 production Agent / Deep Research path,把 canary secret 放进环境变量、tool input/error 或测试上下文,最终扫描 logs、diagnostics、eval artifacts、待发送 telemetry;若 #14 已接入,还要验证 Langfuse 中 0 canary。请补这一次真实运行证据。
另外 #84 刚合入 main,请 rebase 最新 main 后跑基础 CI。除这两项外,不要求扩大 redaction 规则或新增框架。若暂时不做 production-path canary,请把 Closes #19 改成 Refs/Part of #19,作为安全增量合入,Issue 保持 open。
将仓库中四套分散的脱敏实现(diagnostics 正则列表、evaluation 字段 级深脱敏、export 账户字段过滤、credentialStore 的 redactSecrets) 整合到共享 privacy 模块,使日志、诊断、telemetry 与评测产物使用 同一套规则。 - 新增 packages/shared/src/privacy:redactText(fail-closed 模式 引擎)、deepRedact(敏感字段深层遍历,带环/深度保护)、 redactError(消息+堆栈序列化)、策略常量 - 扩展覆盖:cookie/session token、连接串凭证、webhook secret 与 签名、私钥 PEM 块、URL query/fragment 中的 secret、Slack/ SendGrid/GitLab/npm/Google token - 边界加固:ErrorLog 采集时脱敏消息与堆栈;评测 run 错误与 judge 失败原因落盘前脱敏;内核 console.error 经 redactError 序列化 - 保留可观测性字段(run id、工具名、状态、时延),新增幂等性与 fail-closed 测试 - 文档化默认 telemetry 内容策略及 privacy-safe / full-content 模式切换方式(docs/privacy-redaction*.md) Closes helsome#19
52be6d2 to
e1fe63a
Compare
|
两项评审意见均已完成: 1. Rebase 最新 main + 基础 CI已 rebase 到含 #84 的 2. Production-path canary 运行证据按 #19 的要求完成了一次真实应用内的 canary 运行——不是单测,而是构建产物 + CDP 驱动渲染进程走真实 IPC production path: 注入面(canary 均带
|
| 注入路径 | canary |
|---|---|
| 启动环境变量 | ANTHROPIC_API_KEY=sk-CANARYLEAK01…、FINAGENT_JUDGE_API_KEY=lsv2_pt_CANARYLEAK05… |
生产凭证库 evaluation.setCredential / setLangfuseCredential |
lsv2_pt_CANARYLEAK05…、pk-lf-CANARYLEAK06…、sk-lf-CANARYLEAK07… |
生产连接配置 connections.setConfig |
apiKey mk-CANARYLEAK03… + endpoint https://folio_user:CANARYLEAK04dbpass@db.host.internal/api(连接串形) |
真实外呼与错误路径
testLangfuseConnection→ 真实出站到 cloud.langfuse.com → 401 → 渲染层可见消息为 Langfuse 自身错误文本,0 canary 回显connections.test→ 对 canary endpoint 真实网络尝试 → 不可达 → 消息"Could not reach the data provider",0 canaryevaluation.testConnection→backend: none,无外呼
扫描结果(outbound-facing 产物必须干净)
| 产物 | 结果 |
|---|---|
Support bundle(diagnostics.collect 后经生产 serializeSupportBundle 序列化,即 diagnostics:export 落盘内容,14,296 bytes,含完整错误环) |
CLEAN |
| IPC 响应(渲染层收到的全部消息/错误) | CLEAN(仅 connections.json 本地配置回显包含 endpoint 本身,见下) |
| echo 服务器(capture 出站请求) | 0 请求命中 |
evaluation/store.json、store/research/runs.json |
0 canary |
凭证落盘 credentials.json |
全部 safeStorage 密文(v1:…),无明文 canary |
| Langfuse 侧 | status() 证实 backend: none / tracingEnabled: false / langfuseTracingEnabled: false——telemetry 出站关闭,无任何 trace 导出,故 Langfuse 中 0 canary |
原始产物:bundle.json · canary-log.json(存于 fork 的独立 assets 分支,不进入 PR diff)
一条诚实的观察(不扩大本 PR 范围)
本地 at-rest 配置 connections.json 按本地优先设计原样保存 endpoint(含 userinfo)——它不是出站边界(不出设备、bundle 不含它),但若未来有任何同步/导出场景,建议在持久化或回显 endpoint 时剥离 userinfo。可作为后续 issue 跟进。
基于以上,保留 Closes #19。
Summary
Consolidates the four scattered redaction implementations into one shared rule source so every outbound boundary — kernel logs, diagnostics bundles, LangSmith telemetry, eval artifacts, IPC errors, report exports — redacts with the same rules.
New unified module:
packages/shared/src/privacyredactText— fail-closed string pattern engine (never falls back to the raw payload on internal failure)deepRedact— deep JSON walk driven by shared secret-field-name rules, with cycle/depth guards (cyclic or over-deep nodes become[REDACTED], not a crash or a raw leak)redactError— error message + stack serialization for logs/IPC/diagnosticspolicy.ts— field-name rules, account-like key shapes,REDACTION_POLICY, telemetry content policy constantsNew secret coverage (previously unhandled anywhere)
Set-Cookie/session_tokenpostgres://user:pass@…,redis://:pass@…,mongodb+srv://…— scheme and host preserved)whsec_,x-hub-signature(-256))?apikey=…,#token=…)xox, SendGridSG., GitLabglpat-, npmnpm_, GoogleAIza/ya29.tokensBoundary fixes
ErrorLog.pushnow redacts message and stack at collection time (stack first lines echo the raw error message)errorobjects and judgejudge_errorreasons are redacted before persisting to eval artifactsconsole.errorsite serializes viaredactErrordiagnostics/redact,evaluation/redactor,export/privacy, main-processredactSecrets) now delegate to the shared module — API-compatibleData minimization & safety properties
minimal/standard(default)/fullopt-in), plus how to switch:docs/privacy-redaction.md+docs/privacy-redaction.zh-CN.mdTesting
packages/shared/src/privacy/covering every secret class above, nested tool args/results, HTTP error body echoes, fail-closed cycles/depth, immutability, and observability-field survivalErrorLoggained a collection-time redaction test; existing redaction suites (diagnostics/redact.test.ts,evaluation/redactor.test.ts,export/privacy.test.ts,credentialStore.test.ts) pass unchangedbun run typecheckgreen across all workspaces;bun test --isolateshows no new failures (5 pre-existing Windows-path/symlink failures reproduce on a clean checkout and are unrelated — CI runs on ubuntu)Closes #19