Skip to content

CLDSRV-982: Guard against storing a request logger on a long-lived object - #6262

Closed
anurag4DSB wants to merge 2 commits into
development/9.3from
improvement/CLDSRV-982-guard-against-pinned-request-loggers
Closed

CLDSRV-982: Guard against storing a request logger on a long-lived object#6262
anurag4DSB wants to merge 2 commits into
development/9.3from
improvement/CLDSRV-982-guard-against-pinned-request-loggers

Conversation

@anurag4DSB

Copy link
Copy Markdown
Contributor

Intent: why does this change exist?

CLDSRV-979 and CLDSRV-981 are the same mistake in two places, and both shipped with unit coverage of the module they lived in. The tests hand the code a stub logger, which has no entries buffer, so the werelogs behaviour that is the bug was never exercised. This adds the thing that would have caught them.

System impact: what's affected, including downstream?

A no-restricted-syntax rule scoped to lib/**, plus two test helpers. No production code behaviour changes. eslint.config.mjs uses only built-in ESLint capability, so there is no new dependency or plugin.

Merge order: this must land after #6259 (CLDSRV-979) and #6261 (CLDSRV-981). Lint goes from 0 errors to 2 on development/9.3, and those 2 are exactly the tokenBucket and Scuba sites those PRs remove. Draft until then; it turns green on rebase with no further edits.

Preserved behavior: what explicitly stays the same?

Everything at runtime. DummyRequestLogger stays as it is and every existing test using it is untouched — the new fixture sits alongside it for tests that need to observe buffering.

Intended change: what's different after this PR?

this.x = log under lib/ is a lint error, with a message naming the two correct choices: lib/utilities/logger for anything outliving the request, a RequestLogger for anything that does not. The two streamingV4 transforms are genuinely per-request and destroyed with the request, so they disable the rule on the line and say why — the point of the rule is to force that decision to be explicit rather than to ban the assignment.

Tests get makeRealRequestLogger() and bufferedEntryCount() in tests/unit/helpers.js, and requestLoggerBuffering.js pins the werelogs contract itself: sub-level entries are retained rather than dropped, everything below error keeps accumulating, one error-level write flushes the lot, and the plain server logger has no buffer at all.

Verification: how do we know this worked, or how would we know if it didn't?

Checked the rule against the real tree rather than trusting the selector: it flags all four this.x = log sites on development/9.3, and after exempting the two per-request transforms exactly the two known bugs remain. yarn lint goes 0 errors → 2 errors with the same 2945 pre-existing warnings.

The four buffering tests pass and are the executable statement of why the rule exists. tests/unit 5118 passing, with the 15 pre-existing failures this branch inherits (bucketPut/bucketUpdateQuota quota metric seeding, ScubaClientImpl — the last four of which #6261 fixes).

One caveat worth stating: the rule is deliberately shallow. It catches assignment of an identifier named log, logger or _log to a this property, which is how both bugs were written, but it will not catch a logger arriving under another name or reached through a longer path. It raises the cost of the mistake rather than making it impossible.

@bert-e

bert-e commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Hello anurag4dsb,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval
/bypass_build_status Bypass the build and test status
/bypass_commit_size Bypass the check on the size of the changeset TBA
/bypass_incompatible_branch Bypass the check on the source branch prefix
/bypass_jira_check Bypass the Jira issue check
/bypass_peer_approval Bypass the pull request peers' approval
/bypass_leader_approval Bypass the pull request leaders' approval
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e

bert-e commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Incorrect fix version

The Fix Version/s in issue CLDSRV-982 contains:

  • None

Considering where you are trying to merge, I ignored possible hotfix versions and I expected to find:

  • 9.3.17

  • 9.4.2

Please check the Fix Version/s of CLDSRV-982, or the target
branch of this pull request.

// lib/utilities/logger is a werelogs Logger, not a RequestLogger: it
// writes through and drops sub-level entries. This is what long-lived
// objects must use.
const logger = require('../../../lib/utilities/logger');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

require() inside an it() block — the project convention is to keep all requires at the top of the file. Moving this to the top-level would also make the dependency obvious at a glance.

That said, lib/utilities/logger triggers Config initialization as a side effect, so if that's intentional isolation, a short comment explaining why would help.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hoisted to the top in 903e71d, with a note on the Config-on-load side effect — the unit env (CI=true, S3BACKEND=mem) is set before mocha loads any file, so it is safe there, same as every test that pulls in helpers.

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.17%. Comparing base (24fb6b3) to head (3dfbdf8).
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

Files with missing lines Coverage Δ
lib/auth/streamingV4/V4Transform.js 89.60% <ø> (ø)
lib/auth/streamingV4/trailingChecksumTransform.js 88.67% <ø> (ø)
@@               Coverage Diff                @@
##           development/9.3    #6262   +/-   ##
================================================
  Coverage            85.17%   85.17%           
================================================
  Files                  206      206           
  Lines                13424    13424           
================================================
  Hits                 11434    11434           
  Misses                1990     1990           
Flag Coverage Δ
file-ft-tests 68.33% <ø> (-0.07%) ⬇️
file-ft-tests-null-compat 68.84% <ø> (-0.06%) ⬇️
kmip-ft-tests 28.36% <ø> (ø)
mongo-v0-ft-tests 69.55% <ø> (ø)
mongo-v1-ft-tests 69.58% <ø> (-0.03%) ⬇️
multiple-backend 36.83% <ø> (ø)
s3c-ft-tests-v0 64.07% <ø> (ø)
s3c-ft-tests-v0-null-compat 64.13% <ø> (ø)
s3c-ft-tests-v1 64.05% <ø> (ø)
sur-tests 35.98% <ø> (ø)
sur-tests-inflights 37.81% <ø> (-0.03%) ⬇️
unit 71.08% <ø> (ø)
utapi-v2-tests 34.62% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bert-e

bert-e commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Request integration branches

Waiting for integration branch creation to be requested by the user.

To request integration branches, please comment on this pull request with the following command:

/create_integration_branches

Alternatively, the /approve and /create_pull_requests commands will automatically
create the integration branches.

A werelogs RequestLogger buffers every entry it is handed and only
flushes when something logs at or above the dump threshold. That is safe
for one request and a leak for anything outliving it: CLDSRV-979 grew the
buffer 10 times a second per account, and CLDSRV-981 does the same on
every Scuba health check transition. Both shipped with unit coverage of
the module they lived in, because the tests hand over a stub with no
entries buffer.

A no-restricted-syntax rule now flags storing log, logger, _log or
_logger on `this` under lib/, which forces an explicit decision at each
site. The two streamingV4 transforms are genuinely per request and are
destroyed with it, so they disable the rule on the line and say why.

This leaves two violations on development/9.3 - the tokenBucket and Scuba
sites - which are the bugs fixed by CLDSRV-979 and CLDSRV-981. Lint goes
from 0 errors to 2 until those merge, and green afterwards.
DummyRequestLogger counts calls but has no entries buffer, so no test
using it can see werelogs buffering. makeRealRequestLogger() hands out a
real RequestLogger and bufferedEntryCount() reads its buffer, so a test
can assert that something is not accumulating.

requestLoggerBuffering.js pins the behaviour the lint rule protects
against: sub-level entries are retained rather than dropped, everything
below error keeps accumulating, one error-level write flushes the lot,
and the plain server logger has no buffer at all. If werelogs changes
this contract, that is where it surfaces.
@anurag4DSB
anurag4DSB force-pushed the improvement/CLDSRV-982-guard-against-pinned-request-loggers branch from 903e71d to 3dfbdf8 Compare August 20, 2026 14:22
@anurag4DSB anurag4DSB closed this Aug 20, 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.

2 participants