Skip to content

chore(node-client): harden existing platform implementation#1403

Open
joker23 wants to merge 7 commits into
mainfrom
skz/sdk-2195/node-client-sdk-next-port-client-harden-platform-io
Open

chore(node-client): harden existing platform implementation#1403
joker23 wants to merge 7 commits into
mainfrom
skz/sdk-2195/node-client-sdk-next-port-client-harden-platform-io

Conversation

@joker23
Copy link
Copy Markdown
Contributor

@joker23 joker23 commented Jun 1, 2026

Hardens the Node platform layer landed in #1393, ahead of the client-side SDK implementation that builds on it. First atomic in the node-client port stack.

  • NodeStorage: log (no longer swallow) flush errors; validate/log on malformed cache reads and ignore non-string cache values; write the temp file via an exclusive wx open so the write cannot be redirected through a symlink; warn when getNodeStorage is called with a localStoragePath that differs from the process singleton's.

Note

Medium Risk
Changes local filesystem cache read/write semantics and symlink-resistant atomic writes; impact is confined to on-disk flag cache, but misconfiguration or path warnings could surprise multi-instance setups in one process.

Overview
Hardens Node flag disk cache behavior in NodeStorage and getNodeStorage.

Load path: Missing ldcache.json no longer triggers a rewrite or warning. Invalid JSON or other read failures log a malformed cache warning and reset via an atomic write. Loaded JSON must be a plain object; only string values are kept (arrays, numbers, nested objects are dropped).

Write path: Persists through an exclusive wx open on the temp file (after unlinking any existing temp path) instead of a plain writeFile, so a symlink at the temp path cannot redirect writes to another file.

Singleton: getNodeStorage records the first localStoragePath and warns if a later call passes a different path; resetNodeStorage clears that path as well.

Tests cover first-run behavior, malformed cache warnings, non-string entries, symlink resistance, and the path mismatch warning.

Reviewed by Cursor Bugbot for commit a00473e. Bugbot is set up for automated code reviews on this repo. Configure here.

joker23 and others added 2 commits June 1, 2026 12:43
Improves robustness of the already-merged Node platform layer:
- NodeStorage logs swallowed flush errors, validates and logs on malformed
  cache reads, writes the temp file with an exclusive (symlink-safe) open,
  and warns on localStoragePath mismatch across the process singleton.
- NodeResponse caps the buffered response body to guard against memory
  exhaustion from an oversized or hostile response.
- NodeRequests applies a default request timeout so a stuck server cannot
  hang polling or event delivery indefinitely.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pins the new hardening behavior:
- NodeStorage: warn on malformed cache, non-string cache values ignored,
  symlink-safe temp write, localStoragePath-mismatch warning.
- NodeResponse: rejects when the body exceeds the size cap (exports
  MAX_RESPONSE_BYTES so the test references the exact threshold).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@joker23
Copy link
Copy Markdown
Contributor Author

joker23 commented Jun 1, 2026

@cursor review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 26389 bytes
Compressed size limit: 29000
Uncompressed size: 129320 bytes

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 38768 bytes
Compressed size limit: 39000
Uncompressed size: 212567 bytes

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 32002 bytes
Compressed size limit: 34000
Uncompressed size: 114243 bytes

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 179554 bytes
Compressed size limit: 200000
Uncompressed size: 831422 bytes

cursor[bot]

This comment was marked as resolved.

@joker23
Copy link
Copy Markdown
Contributor Author

joker23 commented Jun 1, 2026

@cursor review

@joker23
Copy link
Copy Markdown
Contributor Author

joker23 commented Jun 1, 2026

@cursor review

cursor[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

@joker23 joker23 marked this pull request as ready for review June 1, 2026 17:56
@joker23 joker23 requested a review from a team as a code owner June 1, 2026 17:56
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 6 additional findings.

Open in Devin Review

try {
await fs.writeFile(this._tempFile, content, { encoding: 'utf8', mode: 0o600 });
try {
await fs.unlink(this._tempFile);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume the file being missing isn't the only reason it cannot be deleted. For example if it was created by a different user or with different permissions.

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.

yea that would also cause issues, but the exception will be caught further down.

joker23 added 2 commits June 1, 2026 17:00
This is a larger problem that needs to be resolved in a separate PR
this is not standard for our sdks
@joker23 joker23 requested a review from kinyoklion June 1, 2026 21:25
Comment thread packages/sdk/node-client/src/platform/NodeStorage.ts Outdated
await handle.close();
handle = undefined;
await fs.rename(this._tempFile, this._storageFile);
} catch (error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It does feel like we probably should log something in this error handler.

Co-authored-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
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