Skip to content

feat(privacy): unify redaction and data minimization behind one rule source - #64

Open
yjg-djb wants to merge 2 commits into
helsome:mainfrom
yjg-djb:fix/issue-19-unified-redaction
Open

feat(privacy): unify redaction and data minimization behind one rule source#64
yjg-djb wants to merge 2 commits into
helsome:mainfrom
yjg-djb:fix/issue-19-unified-redaction

Conversation

@yjg-djb

@yjg-djb yjg-djb commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

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/privacy

  • redactText — 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/diagnostics
  • policy.ts — field-name rules, account-like key shapes, REDACTION_POLICY, telemetry content policy constants

New secret coverage (previously unhandled anywhere)

  • cookies / Set-Cookie / session_token
  • connection-string credentials (postgres://user:pass@…, redis://:pass@…, mongodb+srv://… — scheme and host preserved)
  • webhook secrets & signatures (whsec_, x-hub-signature(-256))
  • private key PEM blocks
  • secrets in URL query strings / fragments (?apikey=…, #token=…)
  • Slack xox, SendGrid SG., GitLab glpat-, npm npm_, Google AIza/ya29. tokens
  • Basic auth alongside Bearer

Boundary fixes

  • ErrorLog.push now redacts message and stack at collection time (stack first lines echo the raw error message)
  • evaluation run error objects and judge judge_error reasons are redacted before persisting to eval artifacts
  • kernel console.error site serializes via redactError
  • legacy entry points (diagnostics/redact, evaluation/redactor, export/privacy, main-process redactSecrets) now delegate to the shared module — API-compatible

Data minimization & safety properties

  • observability fields (run ids, trace ids, tool names, statuses, latencies, timestamps) are preserved — asserted by tests
  • redaction is idempotent — asserted by tests
  • default telemetry content policy documented (minimal/standard(default)/full opt-in), plus how to switch: docs/privacy-redaction.md + docs/privacy-redaction.zh-CN.md

Testing

  • 21 new unit tests in 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 survival
  • ErrorLog gained a collection-time redaction test; existing redaction suites (diagnostics/redact.test.ts, evaluation/redactor.test.ts, export/privacy.test.ts, credentialStore.test.ts) pass unchanged
  • bun run typecheck green across all workspaces; bun test --isolate shows no new failures (5 pre-existing Windows-path/symlink failures reproduce on a clean checkout and are unrelated — CI runs on ubuntu)
  • local run of the CI secret-scan pattern set: clean

Closes #19

@yjg-djb
yjg-djb force-pushed the fix/issue-19-unified-redaction branch from 52cbdb9 to 83db04e Compare September 11, 2026 08:57
@yjg-djb

yjg-djb commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

测试报告(按维护者在 #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. 关键环境信息

  • OS: Windows 10.0.26200 (win32 x64)
  • Bun: 1.4.2
  • 提交: 83db04e(即本 PR 当前 head)

3. 每组测试 pass/fail 数量

结果
typecheck(core/i18n/shared/ui/electron 全部 workspace) 全部 exit 0
packages/shared/src/privacy(本 PR 新增) 21 pass / 0 fail
packages/shared/src/diagnostics 24 pass / 0 fail
packages/shared/src/evaluation 114 pass / 0 fail
bun test --isolate 全仓 1230 pass / 5 fail / 7 skip(1242 tests / 139 files)

4. 关于 5 个失败:均可在当前 main 复现,与本 PR 无关

在干净 main(git stash 本 PR 全部改动后重跑)上得到完全相同的 5 个失败,均为 Windows 环境专有问题:

  • PiRuntimeAdapter / AgentKernelHost:测试硬编码 POSIX 路径(/tmp/...),Windows 上 path 返回反斜杠;
  • SkillHub V2 blocks symlink escapes:Windows 创建 symlink 需开发者模式/管理员权限(EPERM);
  • score formatting renders short shas and datesformatDate 输出依赖系统 locale(zh-CN Windows 输出 2023年11月14日,断言假定为英文格式);
  • 其一为顺序依赖型(单文件运行通过,仅全量运行触发)。

CI 在 ubuntu 运行,不受影响。如需要我可以另行提一个修复 Windows 测试兼容性的 PR。

5. 针对性脱敏用例结果(新增单测,全部通过)

类别 用例 结果
Authorization Authorization: Bearer … / Basic …,保 scheme 去 token
Cookie cookie:/Set-Cookie:/session_token(含 JSON 形式)
API key sk-/sk-ant-/x-api-key/apiKey/AIza/xox/SG./glpat-/npm_/lsv2_
Connection string postgres://user:pass@hostredis://:pass@mongodb+srv://(保留 scheme+host)
嵌套 tool args/results 深层对象/数组中任意深度的敏感字段名与字符串
error/stack 消息+堆栈首行回显、HTTP 401 body 回显 key
URL query ?apikey=/&access_token=/#token=,benign 参数保留
其他 webhook 签名、PEM 私钥块、幂等性、可观测性字段保留

6. Canary 泄漏检查(等价于 CanaryScanner 的实际执行结果)

将 9 类已知 canary secret(sk- key / Bearer / cookie / 连接串 / URL query / JWT / whsec_ / AKIA / x-api-key)注入各真实边界后序列化输出并扫描,canary 值零残留:

PASS redactText (string engine)
PASS serializeSupportBundle (diagnostics export)
PASS ErrorLog.push (kernel error ring buffer)
PASS EvaluationRedactor (eval artifacts, standard)
PASS redactError + deepRedact (IPC/errors/telemetry)

ALL CANARIES CONTAINED

fail-closed 行为(循环引用 / 超深嵌套 / 内部异常 → [REDACTED],绝不回退原始负载)由 packages/shared/src/privacy/deep-redact.test.ts 覆盖。

@helsome helsome left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这条实现和测试报告已经明显优于重复的 #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
@yjg-djb
yjg-djb force-pushed the fix/issue-19-unified-redaction branch from 52be6d2 to e1fe63a Compare September 12, 2026 03:01
yjg-djb added a commit to yjg-djb/folio that referenced this pull request Sep 12, 2026
@yjg-djb

yjg-djb commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

两项评审意见均已完成:

1. Rebase 最新 main + 基础 CI

已 rebase 到含 #84main @ 4cdb6bd(本 PR head e1fe63a),CI 四项全绿(Typecheck / Focused tests / Full unit tests advisory / Secret scan)。rebase 后本地 focused privacy/diagnostics/evaluation 176 tests 全过。

2. Production-path canary 运行证据

#19 的要求完成了一次真实应用内的 canary 运行——不是单测,而是构建产物 + CDP 驱动渲染进程走真实 IPC production path:

注入面(canary 均带 CANARYLEAK 标记)

注入路径 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 canary
  • evaluation.testConnectionbackend: none,无外呼

扫描结果(outbound-facing 产物必须干净)

产物 结果
Support bundle(diagnostics.collect 后经生产 serializeSupportBundle 序列化,即 diagnostics:export 落盘内容,14,296 bytes,含完整错误环) CLEAN
IPC 响应(渲染层收到的全部消息/错误) CLEAN(仅 connections.json 本地配置回显包含 endpoint 本身,见下)
echo 服务器(capture 出站请求) 0 请求命中
evaluation/store.jsonstore/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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Privacy] Centralize redaction and data minimization for logs, diagnostics, traces, and eval artifacts

2 participants