fix(proactive-refresh): redact account email through maskEmail in log calls - #444
Conversation
… calls
Three log calls in `proactive-refresh.ts` emitted `email: account.email`
as a raw string:
- "Proactively refreshing token" (line 113)
- "Proactive refresh succeeded" (line 127)
- "Proactive refresh failed" (line 134)
The shared logger does auto-redact "email" keys via `maskToken`, but
that produces partial-leak output like `user.e...e.com` for any email
longer than 12 chars (first 6 + last 4 of the raw string), which still
exposes most of the local part and most of the domain.
Switch to the email-specific `maskEmail` helper from `lib/logger.ts`,
which produces `us***@***.com` (first 2 chars of local + tld only).
This is the same redaction shape used elsewhere in the codebase
(audit.ts and the embedded EMAIL_PATTERN sanitizer in maskString).
Per `lib/AGENTS.md` ("focus on auth rotation, windows filesystem io,
and concurrency. check for logging that leaks tokens or emails.").
Tests:
- "redacts the account email through maskEmail in every log path" —
spies on logger.maskEmail and asserts it is called with the raw
email value across both success and failure paths (≥4 calls for the
two invocations × two log calls each).
- "omits the email field entirely when account has no email" —
guards against ever emitting an `email: undefined` key when the
account record has no email.
Suite: 3746/3746 pass.
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
📝 WalkthroughWalkthroughthis change redacts account email from proactive refresh logging by importing Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Notes for reviewer
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
…le-masking The logger's sanitizeValue treats 'email' as a SENSITIVE_KEYS entry and re-applies maskToken to the value, distorting the intended maskEmail format. Renaming the log key to emailMasked keeps the value out of the sensitive-key sanitizer and preserves the maskEmail output verbatim. Reported by greptile P2 on PR #444.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/proactive-refresh.test.ts`:
- Line 241: The test "omits the email field entirely when account has no email"
currently only checks that maskEmail is not called (maskEmail), which doesn't
prove the payload lacks an email key; update the test to assert the key is
absent (e.g., expect(payload).not.toHaveProperty('emailMasked') or equivalent)
OR rename the test to "does not call maskEmail when account has no email" to
match the existing assertion, and adjust assertions around where the payload is
produced so the code paths that could produce emailMasked: undefined are
rejected.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 136950d6-f736-4cc7-bb81-5f573f75917c
📒 Files selected for processing (2)
lib/proactive-refresh.tstest/proactive-refresh.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (2)
test/**
⚙️ CodeRabbit configuration file
tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.
Files:
test/proactive-refresh.test.ts
lib/**
⚙️ CodeRabbit configuration file
focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.
Files:
lib/proactive-refresh.ts
🔇 Additional comments (2)
lib/proactive-refresh.ts (1)
14-14: good pii redaction wiring.
lib/proactive-refresh.ts:113,lib/proactive-refresh.ts:127, andlib/proactive-refresh.ts:134now avoid raw email logging and only include masked email when present. that aligns with the added vitest coverage intest/proactive-refresh.test.ts:207andtest/proactive-refresh.test.ts:241.As per coding guidelines, "check for logging that leaks tokens or emails."
Also applies to: 113-113, 127-127, 134-134
test/proactive-refresh.test.ts (1)
12-12: good deterministic regression coverage for mask paths.
test/proactive-refresh.test.ts:207covers both success and failure log flows, and theloggermodule import attest/proactive-refresh.test.ts:12enables directmaskEmailspying with vitest.As per coding guidelines, "test/**: tests must stay deterministic and use vitest."
Also applies to: 207-207, 214-239
The previous assertion only verified that maskEmail was not called, which would still pass if the log payload included 'emailMasked: undefined'. Spy on console.info/console.warn to capture the actual emitted data and assert neither 'email' nor 'emailMasked' appears as a key when account.email is absent. Reported by CodeRabbit on PR #444.
Summary
Three log calls in
lib/proactive-refresh.tsemittedemail: account.emailas a raw string:lib/proactive-refresh.ts:113— "Proactively refreshing token"lib/proactive-refresh.ts:127— "Proactive refresh succeeded"lib/proactive-refresh.ts:134— "Proactive refresh failed"Why this matters
lib/AGENTS.md(lib/**section) is explicit:The shared logger in
lib/logger.tsdoes auto-redact any key whose normalized name is inSENSITIVE_KEYS(emailis on that list), but it routes throughmaskToken, which produces partial-leak output for emails longer than 12 chars:maskTokenmaskEmailuser.example@longdomain.orguser.e...n.orgus***@***.orgfirstname.lastname@gmail.comfirstn...l.comfi***@***.comThe token-style mask still exposes most of the local part and most of the domain, which makes correlation across logs trivial. The email-aware mask (already used in
lib/audit.tsand the embeddedEMAIL_PATTERNinmaskString) produces a much smaller fingerprint.Changes
lib/proactive-refresh.ts— importmaskEmailfrom the same logger module; rewrite the three log calls to spread{ email: maskEmail(account.email) }only when the field is defined (avoids emittingemail: undefined).test/proactive-refresh.test.ts— two new regression tests:redacts the account email through maskEmail in every log pathspies onlogger.maskEmailand asserts it is called with the raw email across success and failure paths.omits the email field entirely when account has no emailguards against accidentally emittingemail: undefined.Test plan
npm run typechecknpx eslintnpx vitest run test/proactive-refresh.test.ts— 31/31 pass (29 existing + 2 new)Notes
This was found via a deeper PII-redaction sweep of
lib/after #443. I scanned alllog.{info,debug,warn,error}calls inlib/for raw email/token interpolation. These three were the only sites still using rawaccount.email; everywhere else either usesaccountId, an account fingerprint helper, a tokenSuffix, or already routes throughmaskEmail.note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
fixes raw
account.emailleaking into three log calls inlib/proactive-refresh.tsby importingmaskEmailand emitting the field asemailMasked(conditional spread) — the key rename also sidesteps thesanitizeValuedouble-mask path since"emailmasked"is not inSENSITIVE_KEYS.Confidence Score: 5/5
safe to merge — production code change is correct and the single p2 test gap doesn't affect runtime behavior
all three log sites are fixed consistently, key rename correctly avoids double-masking, conditional spread prevents undefined emission; only finding is a vacuous spy in the omit-email test which doesn't affect production correctness
test/proactive-refresh.test.ts — the
console.infospy in the "omits email" test should beconsole.logImportant Files Changed
emailkey toemailMaskedand wraps withmaskEmail()— correctly avoids double-masking viasanitizeValueand prevents emittingemailMasked: undefinedvia conditional spreadmaskEmailspy and the no-call assertion are sound, but the payload-content assertions in the "omits email" test are vacuously true becauseconsole.infois spied instead ofconsole.logFlowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[proactiveRefreshAccount called] --> B[log.info: Proactively refreshing token] B --> C{account.email defined?} C -- yes --> D["maskEmail(account.email) → emailMasked: us***@***.org"] C -- no --> E[key omitted entirely] D --> F[sanitizeValue: key emailMasked not in SENSITIVE_KEYS] E --> F F --> G[maskString passes masked value unchanged — no double-mask] G --> H{queuedRefresh result} H -- success --> I[log.info: Proactive refresh succeeded + emailMasked] H -- failed --> J[log.warn: Proactive refresh failed + emailMasked]Prompt To Fix All With AI
Reviews (3): Last reviewed commit: "test(proactive-refresh): assert email ke..." | Re-trigger Greptile
Context used: