Skip to content

fix(core): redact request targets and preserve tool schema order - #966

Merged
LIghtJUNction merged 4 commits into
wip/rust-core-go-extensionsfrom
cursor/redact-query-schema-order-92bc
Oct 26, 2026
Merged

LIghtJUNction merged 4 commits into
wip/rust-core-go-extensionsfrom
cursor/redact-query-schema-order-92bc

Conversation

@LIghtJUNction

@LIghtJUNction LIghtJUNction commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Requests with credential-bearing query strings must not disclose those fields in access logs, and tool schema property order must survive conversion without changing an earlier same-value tool argument. This revision removes the old global JSON substring replacement and custom lexer, while preserving current selected-route/deferred-request policy and the strict honeypot boundary. Fixes #944.

The logger keeps only bounded model/alt/api-version/stream values; all other query keys and values are omitted, URL userinfo/fragment are removed, and malformed targets return a fixed marker. Schema order is restored only at the actual protocol/tool/index path, using bounded serde RawValue parsing plus an indexed ordered object. Full Value equality and the existing encoded-request limits remain enforced. Global JSON ordering, billing hashes and money authority are unchanged.

Current independent review and local verification

ChatGPT Pro code review and separate implementation/test owners accepted the fixed v2 business patch. Its SHA256 is 6d5a2f5859fdec2676bacd03c3e5314c7cd98df747dcdc0f453fc37e2c269308; the additional real-middleware test changes test code only. Frozen source base: a2e98793aa2ca1c27825665e32805c9b1584f222.

The combined scoped snapshot passed 309 tests, with one preexisting opt-in benchmark ignored and not counted passed. It covers protocol conversion, selected-route/strict transport, actual loopback HTTP, the actual Go-extension stop/stream case, isolated PostgreSQL authorization/unknown-money/lineage cases, and the independently authored schema/log regressions. Actual production middleware was exercised through Axum over four loopback HTTP requests in a child process; captured stderr had the expected 401/404/200 safe targets and no code/state/unknown-secret material, while a query-less health request was silent.

Strict cargo clippy --locked --all-targets -- -D warnings and maintained-doc validation passed on that snapshot. The old routing source-bridge wiring failure was separately corrected without deleting its real assertions; its library routing and upstream-cost groups are both retained. That separate current-WIP test-wiring commit is ef05110cdee1f6d8b689df3fd651c6801d768a9c. Original failed runs and later corrected fixture/infrastructure runs are retained as distinct evidence. No CI reruns or workflow dispatches.

This is scoped local source acceptance, not production deployment, real OAuth/provider acceptance, paid model/image calls, release performance or whole-project acceptance. The source and behavior below describe the current revision; the original author record is preserved separately.

Original frozen head 4c2ab13 author description and historical validation

变更说明

问题与关联 Issue/PR:

Fixes #944。把 QuantumNous/new-api 的两处后端修复移植到 Rust services/core:

  • 日志脱敏 query 凭证:30748c6558bc97de49ff74871cfec717e50f3322(fix(logging): 隐藏访问日志中的查询凭据)
  • JSON Schema properties 保持客户端键序:d0b840e75ff36d731b04ff981ee361819acd593f(fix(relay): keep the client's JSON Schema property order)

为什么采用此方案:

访问日志原先不记录 URL。一旦请求带 query,凭证仍可能进入 stderr。新增最外层访问日志,只在 request-target 含 ? 时写一行,并按上游规则脱敏。

serde_json 的 Map 是 BTreeMap。全局打开 preserve_order 会改变计费、滥用策略、路由和工具市场所用 JSON 的 SHA-256。因此只在工具 schema 上保留客户端键序:解析原始 schema 字节,确认与已校验的 Value 语义相同后,再拼回上游 body。对不上则仍发送排序后的规范字节。

复用了什么,替代或删除了什么:

行为按上述两个上游提交重新实现,没有拷贝 Go 源码,也没有改 apps/api-go、apps/web 或其他仓库。上游发送从 serde_json::to_vec 改为 Request::upstream_body。Request::upstream 仅测试使用。

可能破坏的行为、外部契约或数据路径:

  • 带 query 的请求会多一行 stderr:core_access method=… status=… target=…。不含对端地址,query 中的凭证值被替换。无 query 的请求(含 /health/live)不写这行。
  • 工具参数发往上游时,对象键序可能与以往的字母序不同。语义与校验后的 JSON 值相同。其他对象键仍按字母序编码。
  • 钱包、支付、订阅、助手、HeroSMS、赏金、Redis-off、1 USD = 500000 credits 未改。未加入 task/JS 插件宿主。

上游来源与许可证影响(不适用时说明):

上游仓库 QuantumNous/new-api,提交 30748c6558bc97de49ff74871cfec717e50f3322 与 d0b840e75ff36d731b04ff981ee361819acd593f。本仓库保持 LMM 品牌、NOTICE 与 AGPL。本次是行为移植,不是整段复制;来源写在 log_redact 与 schema_order 的模块注释里。未改 NOTICE。

Query 键:拒绝与保留

拒绝(大小写不敏感,先 TrimSpace)的精确键:

key、api_key、api-key、apikey、x-api-key、access_token、refresh_token、id_token、token、authorization、auth、client_secret、secret、password、passwd、signature、sig、awsaccesskeyid、x-amz-credential、x-amz-security-token、x-amz-signature。

另外,规范化后的键名只要包含子串 token、secret 或 signature 也拒绝(例如 session_token、nottoken、client_secret)。author 与 authentication 不因此被拒绝。auth 只按精确键拒绝。

掩码值为 ***masked***。写入 query 时 * 编码为 %2A。键名保留,只替换值。

访问日志会先按 Go Query().Encode() 的方式重编码:无效百分号转义被丢弃,含 ; 的片段被丢弃,键按解码后的字节序排列。然后做脱敏。因此 alt、api-version、model、stream、client_id、code、state 等运维键仍然可见。

整段 query 被去掉的路径只有解码后的 /api/oauth/ 与 /oauth/ 前缀。/api/oauth2/ 不去掉;其上的 code 与 state 会原样留下(它们不在拒绝表中)。

sanitize_url_for_log 在解析后没有任何敏感键时返回原字符串(含无效转义的单独 key=bad%ZZ)。绝对 URL 的 userinfo(user:pass@)按上游 url.URL.String() 保留,不在本次拒绝范围内。访问日志记的是 request-target,不含 userinfo。

JSON Schema 键序范围

覆盖:Chat / Responses 的 function parameters,Anthropic input_schema,Gemini OpenAPI parameters(类型改为小写,属性序保留)和 parametersJsonSchema。

本 relay 没有 response_format / json_schema 结构化输出路径,本次不新增。重复键沿用现有语义:值取后者,键位取首次出现。

改动文件

  • services/core/src/log_redact.rs(新)
  • services/core/src/relay/schema_order.rs(新)
  • services/core/src/lib.rs
  • services/core/src/main.rs
  • services/core/src/relay/mod.rs
  • services/core/src/relay/request.rs
  • services/core/src/relay/honeypot.rs
  • services/core/src/relay/native_anthropic.rs
  • services/core/src/relay/native_gemini.rs

验证证据

审查基点 SHA:3ecb3ede394f418b7d2b5e761d979879ad99a2d9(wip/rust-core-go-extensions)

实际测试的 HEAD 与工作区摘要:9d2fe268ae68c1d5cffbaf96e01d59d5aa09484c,工作区干净。工具链 services/core/rust-toolchain.toml 的 Rust 1.99.0。

修复前失败、修复后通过的命令与日志:

在 services/core 执行,均退出码 0:

  • cargo fmt --all
  • cargo clippy --all-targets --message-format=short(无 warning)
  • cargo test --lib log_redact:: -- --test-threads=8:3 passed
  • cargo test --lib relay:: -- --test-threads=8:152 passed(含 schema 键序 4 项与既有 relay 回归)

黄金用例覆盖上游访问日志样例:key / token / api_key / access_token / secret 等不以明文出现;model、alt、api-version 保留。Schema 往返后 properties 仍为 reasoning 然后 answer,而 serde_json 排序结果相反。

重构的行为保持证据,或明确的业务语义差异:

既有 relay 单测仍比较 upstream() 的 Value,不比较字节序。键序只影响实际上游 body。语义不等的拼接会退回排序字节。

quick / related / full 的报告、失败、受阻及未执行项目:

本次是 related 的 services/core 库测试与 clippy,不是 full just test-core,未跑 PostgreSQL 集成,未做独立验收。

用户可见变化的浏览器证据;核心变化的同环境资源对比(适用时):

无 UI。不适用浏览器。

必须独立审查的内容

门禁、测试断言、类型配置、阈值、锁文件、基线或例外的变更与理由:

无锁文件、阈值或 CI 门禁改动。新增断言锁定脱敏黄金字符串和 schema 键序。

高风险业务、临时方案的责任人、到期时间与退出条件:

日志脱敏影响安全审计可见性:拒绝表过宽会挡住排障,过窄会漏凭证。当前表与上游一致,并在上文列出保留键。拼接 schema 失败时退回排序编码,请求不会因此失败。

独立审查者与证据(尚未执行请写 pending,作者不能自行批准):

pending。作者自测不能作为独立签收。

提交前核对

  • 一个明确目标,无夹带格式化、重命名或架构重写;已核对重复工作及被删除内容的消费者。
  • 没有通过跳过测试、删除有效断言、测试专用成功分支或降低门槛换取通过。
  • 模块测试、真实业务验收、未执行与受阻项目已区分;构建成功未冒充完整验收。
  • 已更新受影响的文档和配置;代码及提交证据不含凭据、DSN 或用户私密数据。

拒绝/保留键写在 services/core/src/log_redact.rs 模块文档和本说明中,未另开文档。未包含 Claude cache writes billing(94cc3ff0)或 channel custom body(7fb6e57a)。提交不代表允许合并、发布或部署。

Open in Web Open in Cursor 

…property order

Port QuantumNous/new-api 30748c6558bc97de49ff74871cfec717e50f3322 and
d0b840e75ff36d731b04ff981ee361819acd593f into services/core. Access logs
mask credential query keys, and tool schemas sent upstream keep the
client's property order.

Fixes #944

Co-authored-by: LIghtJUNction <lightjunction.me@gmail.com>
Copilot AI balanced review requested due to automatic review settings October 26, 2026 08:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-26T08:18:58.093471Z 9d2fe26 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copy link
Copy Markdown
Collaborator Author

小时巡检(Asia/Taipei 2026-10-26 ~16:35):

Copy link
Copy Markdown
Collaborator Author

小时巡检:默认分支 tip 已前进到 ebabe6fcc89d(相对本 PR 原 base 3ecb3ede)。上一轮 identity 为 cancelled、protocol 绿导致 mergeable_state=unstable,且无 Actions re-run MCP 工具。已对本 PR 执行 Update branch,新 head 93886cd66f7d5e98f92623aa0bbca53604207aaa;identity + protocol 正在重跑(runs 40300763680 / 40300763130)。两绿且可合并后将 squash-merge 并关闭 #944。

Copy link
Copy Markdown
Collaborator Author

小时巡检续:Update branch 后重跑结果——identity 再次 cancelled(run 40300763680,卡在「Test against isolated PostgreSQL databases」约 21 分钟后被取消);protocol 仍在跑(run 40300763130)。cursor-github MCP 无 Actions re-run 工具,本机 gh 未登录,无法在本轮代重跑。两绿前不 squash-merge;下轮再查。

Copy link
Copy Markdown
Collaborator Author

小时巡检(Asia/Taipei 2026-10-26 ~18:40):

…lly [skip ci]

Preserve selected-route authority and strict honeypot boundaries. Replace global schema substring matching and the custom lexer with bounded structural serde processing. Add independently authored protocol and real middleware regressions.
@LIghtJUNction LIghtJUNction changed the title fix(core): redact query credentials in logs + preserve JSON Schema property order fix(core): redact request targets and preserve tool schema order Oct 26, 2026
@LIghtJUNction
LIghtJUNction merged commit b3b3567 into wip/rust-core-go-extensions Oct 26, 2026
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.

[upstream-port] 日志脱敏 query 凭证 + JSON Schema 属性序(30748c65 + d0b840e7)

3 participants