Consolidate CSP nonce sanitization into shared module#2828
Conversation
The sanitizeNonce logic was duplicated in the OSS RenderUtils.ts and Pro utils.ts. Extract it into a dedicated react-on-rails/sanitizeNonce module so both packages share a single implementation. Add comprehensive tests for the sanitize-then-validate policy. Malformed nonces are silently dropped rather than rejected or logged. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughConsolidates CSP nonce sanitization into a new OSS-exported Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 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)
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 |
size-limit report 📦
|
Greptile SummaryThis PR eliminates a duplicated CSP nonce sanitization implementation by extracting it into a single shared
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["RenderUtils.ts (OSS)"]
B["injectRSCPayload.ts (Pro)"]
C["transformRSCStreamAndReplayConsoleLogs.ts (Pro)"]
D["sanitizeNonce.ts\n(react-on-rails/sanitizeNonce)"]
subgraph Before
A1["RenderUtils.ts\n(inline regex logic)"]
B1["injectRSCPayload.ts\nimports from utils.ts"]
C1["transformRSCStream…\nimports from utils.ts"]
U["utils.ts (Pro)\nexports sanitizeNonce"]
B1 --> U
C1 --> U
end
subgraph After
A --> D
B --> D
C --> D
end
Reviews (1): Last reviewed commit: "Update CHANGELOG with actual PR number (..." | Re-trigger Greptile |
Review: Consolidate CSP nonce sanitization into shared moduleOverall this is a clean, well-structured refactor. The extraction eliminates real duplication, the test coverage is solid (11 cases covering the key paths), and the Pro package correctly imports from the shared OSS module. A few points worth addressing: Docstring accuracy: The JSDoc says 'If the sanitized value does not match, undefined is returned and no nonce attribute will be emitted'. This overstates the drop guarantee. The function can return a sanitized-but-garbage value when stripped remnants of malformed input happen to match the validation regex. Input Misleading test case: The test 'strips dangerous characters from injection attempts' and its comment 'After stripping non-base64 chars, the remaining alphanumeric string is valid' reads as if returning a garbage nonce is expected/desirable. In practice Public export surface: Minor: The The core change is correct and the existing tests confirm security-critical paths work as intended. The above are documentation and API surface concerns rather than functional bugs. |
|
Overall: Clean, well-motivated refactor that eliminates the keep-in-sync comment by actually sharing code. Tests cover the core scenarios well. One security observation worth calling out: the sanitize-then-validate approach means certain injection-looking strings can pass through rather than being rejected. The test at line 38 of sanitizeNonce.test.ts documents this edge case. After stripping non-base64 characters from a script-tag payload, the remaining string Two small improvements worth considering: (1) The test name "strips dangerous characters from injection attempts" implies the function rejects the input, but it actually accepts the stripped result. A clearer name like "produces stripped nonce from base64-passable injection string" matches the assertion. (2) The module JSDoc says malformed nonces are dropped, which is only partially true. Nonces that produce a valid base64-like string after stripping are NOT dropped. One sentence acknowledging this edge case would prevent future confusion. Minor nit: the test "returns undefined for a nonce that is only padding characters" passes "===". Since = is preserved by the strip regex but only allowed at the end of the validate regex, this test relies on the interaction of both steps. A brief inline comment explaining why === returns undefined (validate requires at least one non-padding char before any =) would help readers understand the two-step logic. Everything else looks correct and consistent with the pre-existing regex. Changelog entry is accurate and the package.json exports entry follows the existing pattern. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
CHANGELOG.md (1)
37-40: Please avoid changelog entries for refactors with unchanged behavior.Line 39 describes internal consolidation and explicitly says behavior is unchanged. Per changelog policy, this should be omitted (or rewritten only if there is a user-visible behavior change).
Suggested edit
-#### Changed - -- **Consolidated CSP nonce sanitization**: Extracted the duplicate `sanitizeNonce` logic from `RenderUtils.ts` (OSS) and `utils.ts` (Pro) into a single shared `sanitizeNonce` module in the OSS package (`react-on-rails/sanitizeNonce`). The Pro package now imports from the OSS package instead of maintaining its own copy. Behavior is unchanged: malformed nonces are silently dropped (sanitize-then-validate policy). [PR 2828](https://github.com/shakacode/react_on_rails/pull/2828) by [justin808](https://github.com/justin808). Fixes [Issue 2582](https://github.com/shakacode/react_on_rails/issues/2582).As per coding guidelines, update
/CHANGELOG.mdfor user-visible changes only and exclude refactoring.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@CHANGELOG.md` around lines 37 - 40, The CHANGELOG entry about consolidating `sanitizeNonce` is a refactor with no user-visible behavior change and should be removed or rewritten; edit the `CHANGELOG.md` section containing the "Consolidated CSP nonce sanitization" bullet so that you either delete this bullet entirely or replace it with a note only if there is a user-facing change, ensuring no internal-refactor-only text remains (refer to the exact "Consolidated CSP nonce sanitization" bullet and its mention of `sanitizeNonce`, `RenderUtils.ts`, and `utils.ts` to locate the text).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@CHANGELOG.md`:
- Around line 37-40: The CHANGELOG entry about consolidating `sanitizeNonce` is
a refactor with no user-visible behavior change and should be removed or
rewritten; edit the `CHANGELOG.md` section containing the "Consolidated CSP
nonce sanitization" bullet so that you either delete this bullet entirely or
replace it with a note only if there is a user-facing change, ensuring no
internal-refactor-only text remains (refer to the exact "Consolidated CSP nonce
sanitization" bullet and its mention of `sanitizeNonce`, `RenderUtils.ts`, and
`utils.ts` to locate the text).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 69f4ddca-280d-43da-aff1-31f956a2c50e
📒 Files selected for processing (8)
CHANGELOG.mdpackages/react-on-rails-pro/src/injectRSCPayload.tspackages/react-on-rails-pro/src/transformRSCStreamAndReplayConsoleLogs.tspackages/react-on-rails-pro/src/utils.tspackages/react-on-rails/package.jsonpackages/react-on-rails/src/RenderUtils.tspackages/react-on-rails/src/sanitizeNonce.tspackages/react-on-rails/tests/sanitizeNonce.test.ts
💤 Files with no reviewable changes (1)
- packages/react-on-rails-pro/src/utils.ts
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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 `@CHANGELOG.md`:
- Around line 68-71: The new CHANGELOG entry adds a duplicate "#### Changed"
header and documents an internal refactor (consolidation of sanitizeNonce) as a
user-visible change; either remove the entry entirely or convert it to an
internal note per policy. Edit CHANGELOG.md to delete or relocate the passage
about extracting sanitizeNonce (references: sanitizeNonce, RenderUtils.ts,
utils.ts, react-on-rails/sanitizeNonce) so the changelog contains only
user-visible changes—if you keep a note, mark it clearly as an internal/refactor
note under an appropriate internal/dev-only section rather than a top-level
"Changed" heading.
🪄 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: CHILL
Plan: Pro
Run ID: 8e397bb5-2bed-42a0-a2b5-250f8c3c7c16
📒 Files selected for processing (2)
CHANGELOG.mdpackages/react-on-rails/package.json
✅ Files skipped from review due to trivial changes (1)
- packages/react-on-rails/package.json
|
Overall this is a clean, well-scoped refactor. The regex is preserved exactly from both call sites so behaviour is genuinely unchanged, coverage is thorough, and the TypeScript narrowing in create-app.ts is a nice improvement. Three things worth addressing: API surface (medium): sanitizeNonce is exported at the public subpath react-on-rails/sanitizeNonce, but Pro already uses react-on-rails/@internal/base/client and react-on-rails/@internal/base/full for cross-package utilities not part of the user-facing API. sanitizeNonce is the same kind of internal utility — using @internal/sanitizeNonce would be consistent with that convention and avoids locking in a public path for an implementation detail. See inline comment on package.json. Missing edge-case test (minor): The strip regex allows = anywhere, but the validate regex only permits trailing = padding. A nonce like 'abc=def' will silently return undefined. A test for this would make the contract explicit and guard against future regex edits. See inline comment on sanitizeNonce.ts. Partially-stripped injection result (documentation): The test confirming '><script>alert(1)</script>' returns 'scriptalert1/script' is correct and safe, but the comment should explain why it is safe: the returned value can never match a server-issued nonce, so CSP still blocks the script regardless. Without that context a future reader might flag it as a security hole. See inline comment on the test file. |
…olve-2828 * origin/main: Bump version to 16.5.1 Update CHANGELOG.md for 16.5.1 (#2873) fix: include lib/tasks/ in pro gem so rake tasks are available (#2872) docs: clarify how React on Rails compares to alternatives (#2856) docs: fix published setup guidance gaps (#2860) docs: refresh setup and runtime guidance (#2857) docs: refresh pro upgrade examples (#2859) docs: modernize dependency update commands (#2864) Update spec/dummy Gemfile.lock for async >= 2.29 (#2870) # Conflicts: # CHANGELOG.md
There was a problem hiding this comment.
♻️ Duplicate comments (1)
CHANGELOG.md (1)
64-68:⚠️ Potential issue | 🟡 MinorRemove the duplicated/invalid changelog block under 16.5.0.
This block repeats the PR 2832 entry, introduces a duplicate
#### Changedheading, and adds a refactor-only note (“behavior is unchanged”), which should not be listed as a user-visible changelog item. Also, use[2828](...)style instead of[PR 2828](...)for any retained entry.Suggested edit
-#### Changed - -- **[Pro]** **Migrated from `Async::Variable` to `Async::Promise`**: The streaming helper internals now use `Async::Promise` for async v2.29+ compatibility while preserving pre-first-chunk error propagation behavior. [PR 2832](https://github.com/shakacode/react_on_rails/pull/2832) by [justin808](https://github.com/justin808). Fixes [Issue 2563](https://github.com/shakacode/react_on_rails/issues/2563). - -- **Consolidated CSP nonce sanitization**: Extracted the duplicate `sanitizeNonce` logic from `RenderUtils.ts` (OSS) and `utils.ts` (Pro) into a single shared `sanitizeNonce` module in the OSS package (`react-on-rails/sanitizeNonce`). The Pro package now imports from the OSS package instead of maintaining its own copy. Behavior is unchanged: sanitize-then-validate is applied, and values that still fail nonce-pattern validation after sanitization are omitted. [PR 2828](https://github.com/shakacode/react_on_rails/pull/2828) by [justin808](https://github.com/justin808). Fixes [Issue 2582](https://github.com/shakacode/react_on_rails/issues/2582).As per coding guidelines: “Update
/CHANGELOG.mdfor user-visible changes only ... exclude ... refactoring ...” and “Format CHANGELOG entries as[PR NUMBER](url) by [username](url)without hash before PR number.”🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@CHANGELOG.md` around lines 64 - 68, Remove the duplicated/invalid changelog block under version 16.5.0: delete the repeated PR 2832 entry and the duplicate "#### Changed" heading, strip the refactor-only note ("behavior is unchanged") so the changelog only contains user-visible changes, and for any retained consolidation entry convert the PR link format from "[PR 2828](...)" to "[2828](...)" and keep the wording concise (mentioning sanitizeNonce and that it consolidated logic from RenderUtils.ts and utils.ts into the OSS package).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@CHANGELOG.md`:
- Around line 64-68: Remove the duplicated/invalid changelog block under version
16.5.0: delete the repeated PR 2832 entry and the duplicate "#### Changed"
heading, strip the refactor-only note ("behavior is unchanged") so the changelog
only contains user-visible changes, and for any retained consolidation entry
convert the PR link format from "[PR 2828](...)" to "[2828](...)" and keep the
wording concise (mentioning sanitizeNonce and that it consolidated logic from
RenderUtils.ts and utils.ts into the OSS package).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2e2dbe67-efaf-4823-8932-8c3066d7de11
📒 Files selected for processing (2)
CHANGELOG.mdpackages/react-on-rails/package.json
✅ Files skipped from review due to trivial changes (1)
- packages/react-on-rails/package.json
Code Review — PR #2828: Consolidate CSP nonce sanitizationOverall this is a clean, well-structured refactor. The new 🔴 CHANGELOG structural bug — duplicate
|
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 `@CHANGELOG.md`:
- Around line 64-66: Remove the duplicated "#### Changed" heading and the
repeated changelog entry that starts with "**[Pro]** **Migrated from
`Async::Variable` to `Async::Promise`**: The streaming helper internals..." (the
duplicate that repeats the PR 2832 and Issue 2563 references); keep the original
single entry earlier in the file and delete this second occurrence so the MD024
duplicate-heading rule and the duplicate entry are eliminated.
🪄 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: Consolidate CSP nonce sanitization into shared moduleOverall: Clean refactor, good test coverage. One CHANGELOG issue and one behavioural question worth addressing before merge. Summary of changesThe extraction of duplicate nonce sanitization logic into Issues found1. CHANGELOG duplicate / wrong PR — needs fix The 2. Sanitize-then-validate: mangled injection inputs can still emit a nonce
Minor observations (no action required)
|
|
Code Review: Clean refactoring of CSP nonce sanitization. Behavior preserved exactly from both source files. Three observations: (1) The sanitize-then-validate approach can emit a stripped but non-matching nonce (e.g. scriptalert1/script from injection input) which is attribute-safe but still causes CSP nonce mismatch - script is blocked, but the nonce attr in HTML may confuse debugging. (2) No test covers equals-sign in middle position (abc=def) - strip keeps it, validation rejects it, returns undefined, which is correct but undocumented. (3) Minor: regex accepts mixed base64 and base64url chars simultaneously (harmless superset). Overall: solid work - well-documented, tests thorough, no behavioral change. |
ReviewOverall: clean consolidation, good test coverage — a few security-policy questions worth settling before merge. What's good
Concerns1. Sanitize-then-validate policy leaves a silent-accept path uncovered by tests The strip regex and validate regex are intentionally asymmetric: stripping is permissive (keeps Example: 2. The XSS-payload test produces a non-empty output
3. Hybrid base64 / base64url acceptance Both Minor: the new |
…e-dedup * origin/main: (51 commits) Fix Content-Length mismatch and null renderingRequest errors in node renderer (#3069) Improve memory debugging docs with simpler heap snapshot approach (#3072) Enforce strict version matching in doctor and recommend doctor on errors (#3070) Remove immediate_hydration feature from codebase (#2834) Fix infinite fork loop when node renderer worker fails to bind port (#2881) Fix TanStack Router SSR hydration mismatch in Pro async path (#2932) Improve node renderer error messages for malformed render requests (#3068) Add interactive mode prompt to create-react-on-rails-app (#3063) docs: replace hardcoded version numbers with unversioned install commands (#2893) Remove Contributing section from docs sidebar (#3064) Consolidate docs comparison pages into single evaluation entry (#3065) Docs route cleanup: canonicalize worst verbose URL slugs (#3067) Add agent summary blocks to high-value docs pages (#3066) Fix brittle positional assertions in create-app tests (#2923) Auto-resolve renderer password from ENV in Rails Pro (#2921) Standardize bundle env vars from =yes to =true (#2925) Fix Pro generator multiline and template-literal rewrites (#2918) Fix spec/dummy Procfile.dev SERVER_BUNDLE_ONLY to match template convention (#2922) Add llms docs entry points (#2916) Bump version to 16.6.0.rc.0 ... # Conflicts: # packages/create-react-on-rails-app/src/create-app.ts
Review: Consolidate CSP nonce sanitization into shared moduleOverall: Good consolidation of duplicate logic — the implementation is functionally identical to what it replaces, the test coverage is a clear improvement, and the Security concern: sanitize-then-validate vs. validate-then-rejectThe core function (inline comment on
The mutation path is attribute-injection-safe (no Behavior parity confirmed ✓The new Minor:
|
|
Address-review checkpoint posted at Scan window: full PR history ( Mattered
Skipped
Follow-up issue: none created (no deferred must-fix items). Future full-PR scans should start after this comment unless |
…ages * origin/main: (44 commits) Consolidate CSP nonce sanitization into shared module (#2828) Add comprehensive --rsc-pro generator tests (#3098) fix: cross-env validation and docs for renderer password (#3090) Improve package metadata and Pro upgrade CTAs (#3112) docs: standardize warning syntax to GFM alert format (#3115) docs: improve react-intl documentation for React Server Components (#3085) Fix generator CI SSR regression on main (#3110) Refocus GitHub README on docs navigation (#3113) Add manual dev environment testing checklist for coding agents (#3074) Bump version to 16.6.0 Update CHANGELOG.md for 16.6.0 (#3078) fix: node-renderer diagnostic improvements (#3086) fix: pin third-party npm deps in generator to prevent peer dep conflicts (#3083) chore(deps): bump lodash from 4.17.23 to 4.18.1 in the npm-security group across 1 directory (#2920) fix: refactor formatExceptionMessage to accept generic request context (#2877) Bump version to 16.6.0.rc.1 Update CHANGELOG.md for 16.6.0.rc.1 (#3079) Update CHANGELOG.md unreleased section (#3077) Fix Content-Length mismatch and null renderingRequest errors in node renderer (#3069) Improve memory debugging docs with simpler heap snapshot approach (#3072) ... # Conflicts: # docs/pro/home-pro.md # docs/pro/react-on-rails-pro.md # docs/sidebars.ts
Summary
sanitizeNoncelogic from OSSRenderUtils.tsand Proutils.tsinto a singlereact-on-rails/sanitizeNoncemoduleFixes #2582
Test plan
sanitizeNonce.test.ts— 11 tests passbuildConsoleReplay.test.ts— still passes (useswrapInScriptTagswhich now imports the shared module)injectRSCPayload.test.ts— nonce sanitization and valid nonce tests passtransformRSCStreamAndReplayConsoleLogs.test.ts— nonce tests passpnpm run buildsucceedspnpm run type-checkpasses🤖 Generated with Claude Code
Note
Medium Risk
Touches CSP nonce handling used to generate/attach
<script>nonces; mistakes could weaken CSP protections or break script execution. Scope is small and behavior is now unit-tested, reducing regression risk.Overview
Centralizes CSP nonce sanitization by introducing
packages/react-on-rails/src/sanitizeNonce.ts, wiringwrapInScriptTagsto use it, and exporting it asreact-on-rails/@internal/sanitizeNoncefor reuse.Removes the duplicated
sanitizeNonceimplementation fromreact-on-rails-pro/src/utils.tsand updates Pro RSC helpers (injectRSCPayload,transformRSCStreamAndReplayConsoleLogs) to import the shared sanitizer. Adds a new Jest suite covering nonce edge cases/injection attempts, and includes small maintenance updates to.lychee.tomlexclusions and a formatting fix inPROJECTS.md.Reviewed by Cursor Bugbot for commit 37d18b4. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
Bug Fixes
Chores
Tests