Skip to content

fix(quota): sanitize Anthropic quota labels - #5463

Closed
luvs01 wants to merge 3 commits into
lidge-jun:devfrom
luvs01:fix/335-anthropic-quota-labels
Closed

luvs01 wants to merge 3 commits into
lidge-jun:devfrom
luvs01:fix/335-anthropic-quota-labels

Conversation

@luvs01

@luvs01 luvs01 commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

  • Anthropic quota responses can embed terminal control characters (OSC/CSI sequences) in model-scoped labels, which lets an upstream label inject terminal escapes into CLI output.

Description

  • Strip terminal control characters from the raw Anthropic quota label before it is published, and cover the path with a dedicated test.

Testing

  • bun test tests/providers/provider-quota-label-sanitize.test.ts (1 pass)
  • bun test tests/providers/provider-quota.test.ts tests/providers/provider-quota-observed-marker.test.ts (180 pass)

Summary by CodeRabbit

  • Bug Fixes

    • Sanitized Claude model quota labels by removing terminal control characters.
    • Limited published labels to recognized model families: Fable, Opus, and Sonnet.
    • Omitted quota windows with unrecognized model labels instead of displaying them verbatim.
    • Preserved valid quota reporting for recognized labels such as “Claude Opus 4.7.”
  • Tests

    • Added coverage for unsafe and recognized provider quota labels.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: a322db31-b90c-47ae-b578-170ec40ddd96

📥 Commits

Reviewing files that changed from the base of the PR and between 39143fd and 492f541.

📒 Files selected for processing (4)
  • scripts/test-layout/layout.json
  • src/providers/quota/vendor-probes-oauth.ts
  • tests/fixtures/test-layout-expected.json
  • tests/providers/provider-quota-label-sanitize.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The Claude quota parser now sanitizes model display names and accepts only recognized model families. New provider tests verify unsafe labels are omitted and recognized labels produce sanitized quota windows. Test-layout configuration registers the new test file.

Changes

Claude quota label sanitization

Layer / File(s) Summary
Sanitize and allowlist Claude labels
src/providers/quota/vendor-probes-oauth.ts
parseClaudeLimit removes control characters from display names. It maps recognized fable, opus, and sonnet labels to canonical names and rejects empty or unrecognized labels.
Validate quota output and register tests
tests/providers/provider-quota-label-sanitize.test.ts, scripts/test-layout/layout.json, tests/fixtures/test-layout-expected.json
Tests verify that terminal control sequences produce no custom quota window and that "Claude Opus 4.7" produces label: "Opus" with percent: 41. Test-layout files register the new provider test.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 492f5

The change prevents terminal-control residue from appearing in Claude quota labels while preserving recognized model labels. The supplied coverage shows no remaining merge-blocking risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. (2 skipped: 2 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: sanitizing Anthropic quota labels. This matches the implementation in src/providers/quota/vendor-probes-oauth.ts and the added sanitization t…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 21, 2026
@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed.

Hygiene

✅ Deterministic PR hygiene checks passed.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 62 / 80

Anthropic 사용량 응답의 모델 이름(display_name)을 쿼터 창 라벨로 쓰기 전에, 터미널 제어 문자를 빼는 수정입니다. 이름 안에 ESC나 BEL 같은 문자가 있으면, CLI가 쿼터를 출력할 때 터미널이 그 문자를 명령으로 읽습니다. OSC 52는 클립보드에 글을 쓸 수 있는 명령입니다. parseClaudeLimit에서 C0, DEL, C1 범위 문자를 지운 뒤 라벨을 만들고, 그 경로를 테스트로 고정합니다. 베이스는 dev입니다.

src/providers/quota/vendor-probes-oauth.ts parseClaudeLimit - 제어 문자만 지우고, 그 뒤에 붙은 명령 본문은 라벨에 남습니다. 테스트가 기대하는 값은 Other]52;c;UFdORUQ= model31m입니다. ESC와 BEL이 빠져 터미널 명령은 끊깁니다. 공격자가 넣은 글은 쿼터 줄에 그대로 남습니다. quotaParts가 window.label을 가공 없이 이어 붙입니다.

tests/providers/provider-quota-label-sanitize.test.ts - 위 찌꺼기 문자열을 성공 조건으로 고정합니다. 나중에 모르는 이름을 버리거나 안전한 이름으로 바꿔도, 이 테스트가 지금의 찌꺼기를 정답으로 붙잡습니다.

메인테이너의 판단이 필요한 지점
모르는 모델 이름은 제어 문자만 지운 채 살릴지, 알려진 이름(Fable, Opus, Sonnet)이 아니면 창을 버릴지입니다. 지금 코드는 이름을 살리는 쪽입니다. 드래프트이고 체크리스트 네 칸은 아직 비어 있습니다.

너의 추천
제어 문자를 지우는 방향은 맞습니다. 모르는 display_name은 라벨로 올리지 않는 편이 더 안전합니다. 알려진 세 이름으로 줄어들지 않으면 parseClaudeLimit이 null을 반환하게 하고, 테스트는 찌꺼기 문자열이 출력되지 않는지로 바꾸면 됩니다. 지금 방식을 유지하면 라벨 길이 상한을 하나 두는 편이 좋습니다.

이 댓글은 grok-bot이 작성했습니다

Per review on lidge-jun#5463: stripping terminal control characters still left attacker-chosen residue on the quota line. parseClaudeLimit now returns null unless the name reduces to a recognized model (Fable, Opus, Sonnet); the test asserts the residue is not emitted and adds a recognized-name positive case.
@luvs01

luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

Review feedback applied on a9a6bac2:

  • parseClaudeLimit now returns null for unrecognized display_name values instead of publishing sanitized residue — only names reducing to Fable, Opus, or Sonnet become quota labels.
  • Test updated: the residue string now asserts customWindows is empty, plus a new positive case keeps Claude Opus 4.7 → Opus.

Tests: provider-quota-label-sanitize 2 pass. (The quota-bars-rows GUI test fails on this host for a missing react/jsx-dev-runtime install, unrelated to this change.)

@luvs01
luvs01 marked this pull request as ready for review September 22, 2026 01:44
@luvs01

luvs01 commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator Author

Consolidated into #5538 as a single related-function aggregate.

Source head: 492f541e31c292f14ea0bc4090f4d9d237552ad1. Replacement head: 62c677c05d880a5c231bb4efd35b7f8bb637d16f.

Both unique source commits, including the review follow-up, match carried commits by stable Git patch ID. All affected runtime and test files match the source head exactly at the replacement head; merge-only source commits have no additional combined diff. The combined changed-file run passed 85 tests / 376 assertions; typecheck, structure, privacy and standalone size-ratchet checks passed. Full suite, hosted cross-platform CI and independent review remain pending.

Closing this duplicate standalone review entry at the author's request after verifying migration. This is not a merge or release claim; remaining integration checks and reviews are tracked on the draft replacement. Original branches are retained.

@luvs01 luvs01 closed this Sep 22, 2026
lidge-jun added a commit that referenced this pull request Sep 22, 2026
…c and config output (#5573)

* fix(lab): combine host-redaction hardening for socket markers and connect-to failures

Combines three fork PRs into one change on current dev: bare destinations after resolver/socket markers are redacted only where grammar proves the position (sole argument or after 'lookup'), connect-to failures redact the bare target when a failure term follows, and rewrites splice at the tail offset so a marker word that repeats the destination cannot take the [host] itself.

bun test tests/lab/lab-evidence-sanitization.test.ts: 31 pass

(cherry picked from commit 69990d9)

Source: #5538 commit b90139f

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(lab): redact socket destinations carrying a sentence-final period

Classify the token without its trailing period and leave the period outside the mask: ECONNREFUSED redis. -> ECONNREFUSED [host]. Previously the punctuation defeated host classification and leaked the destination.

(cherry picked from commit a74038c)

Source: #5538 commit d8042a5

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(config): avoid logging operator-supplied credential/group identifiers in credentialGroups diagnostics

(cherry picked from commit 0354bd9)

Source: #5538 commit fc57a55

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(config): align comments with indexed messages and cover every issue shape

(cherry picked from commit f8a67b3)

Source: #5538 commit 038c0fa

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(cli): redact proxy credentials in config output

(cherry picked from commit 73946f3)

Source: #5538 commit b31732a

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(cli): keep non-secret proxy values readable in config output

Mask only credential-bearing proxy URLs (userinfo stripped via redactUrlForLog, host/port kept); direct and credential-less values print unchanged. Clarify that config export stays raw for restore.

(cherry picked from commit acdbb1c)

Source: #5538 commit dc4d273

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(quota): sanitize Anthropic quota labels

(cherry picked from commit ee716bf)

Source: #5538 commit 4a04458

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(quota): drop unrecognized Anthropic display_name from quota labels

Per review on #5463: stripping terminal control characters still left attacker-chosen residue on the quota line. parseClaudeLimit now returns null unless the name reduces to a recognized model (Fable, Opus, Sonnet); the test asserts the residue is not emitted and adds a recognized-name positive case.

(cherry picked from commit a9a6bac)

Source: #5538 commit aaffe75

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(providers): state canonical quota label boundary

Source: #5538 commit 62c677c

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(diagnostics): preserve redaction across path aliases and resolver prose

Use normalized config keys for get and mutation output. Preserve direct
resolver destinations when explanatory text follows, while retaining socket
prose exclusions. Add focused regressions and align output contracts.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(structure): keep runtime doc within its line budget

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: Epinephrine <luvs01@hanmail.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants