Add rsc-guardrails agent skill + payload-escaping regression test + advisory hook#4599
Conversation
…ory hook Ship an agent-facing guardrail for React Server Components work in this repo, derived from the RSC security audit (issues #4595 / #4596 / #4597). - .agents/skills/rsc-guardrails/SKILL.md: the security + cross-request-isolation invariants RSC changes must not regress (payload escaping, no per-request module state, module-resolution allow-list, entrypoint auth, secrets/PII in logs, the node-renderer trust boundary), plus a PR review checklist and red flags. - packages/react-on-rails-pro/tests/injectRSCPayload.test.ts: a regression test locking in that escapeScript neutralizes </script> and <!-- so a user-controlled RSC payload chunk cannot break out of the inline hydration script. - .claude/hooks/rsc-guardrails-check.sh + settings wiring: a non-blocking PostToolUse warning when a Pro RSC source builds an inline <script>/HTML string outside the sanctioned escaping helpers. Zero false positives on the current tree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
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:
WalkthroughAdds documented RSC security invariants, an advisory post-edit scan for unsafe script sinks, hook wiring, and regression coverage for escaping ChangesRSC security guardrails
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ClaudeCode
participant GuardrailHook
participant EditedFile
ClaudeCode->>GuardrailHook: PostToolUse Edit/Write file path
GuardrailHook->>EditedFile: Scan script and HTML sink patterns
GuardrailHook-->>ClaudeCode: Emit advisory warning or no warning
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
Greptile SummaryThis PR adds RSC guardrails for agents and tests. The main changes are:
Confidence Score: 5/5This looks safe to merge with a small guardrail coverage cleanup.
.claude/hooks/rsc-guardrails-check.sh
|
| Filename | Overview |
|---|---|
| .agents/skills/rsc-guardrails/SKILL.md | Adds agent-facing RSC guidance for escaping, request isolation, module resolution, auth boundaries, logging, and renderer trust boundaries. |
| .claude/hooks/rsc-guardrails-check.sh | Adds a non-blocking advisory hook for risky inline script and HTML patterns, with a narrow TypeScript-only scan scope. |
| .claude/settings.json | Registers the new advisory hook after Edit and Write tool use. |
| packages/react-on-rails-pro/tests/injectRSCPayload.test.ts | Adds a regression test for escaping script-breaking sequences in streamed RSC payload chunks. |
Reviews (1): Last reviewed commit: "Add rsc-guardrails skill, payload-escapi..." | Re-trigger Greptile
size-limit report 📦
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.claude/hooks/rsc-guardrails-check.sh (1)
26-27: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winUse absolute path for grep to avoid cwd dependency.
grepon line 44 uses"$REL_PATH"(relative), but if the hook is invoked from a working directory other thanREPO_ROOT, the file won't be found and the check silently skips. SinceREPO_ROOTis already resolved, grepping"$FILE"(absolute) would be more robust.♻️ Proposed fix
-MATCHES="$(grep -nE "$PATTERN" "$REL_PATH" 2>/dev/null | grep -vE '^[0-9]+:[[:space:]]*(\*|//|/\*)' || true)" +MATCHES="$(grep -nE "$PATTERN" "$FILE" 2>/dev/null | grep -vE '^[0-9]+:[[:space:]]*(\*|//|/\*)' || true)"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/hooks/rsc-guardrails-check.sh around lines 26 - 27, Update the grep invocation in rsc-guardrails-check.sh to use the absolute FILE path instead of REL_PATH, ensuring the check works regardless of the hook’s current working directory. Keep REL_PATH for any other purposes where the repository-relative path is required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.claude/hooks/rsc-guardrails-check.sh:
- Around line 26-27: Update the grep invocation in rsc-guardrails-check.sh to
use the absolute FILE path instead of REL_PATH, ensuring the check works
regardless of the hook’s current working directory. Keep REL_PATH for any other
purposes where the repository-relative path is required.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2bcbd0c9-0e83-45f9-b0e5-c955cbbc0a06
📒 Files selected for processing (4)
.agents/skills/rsc-guardrails/SKILL.md.claude/hooks/rsc-guardrails-check.sh.claude/settings.jsonpackages/react-on-rails-pro/tests/injectRSCPayload.test.ts
ReviewOverview. This PR adds a purely agent/reviewer-facing RSC security guardrail package: a new Regression test (
|
…ust) git rev-parse --show-toplevel canonicalizes symlinks (e.g. /var -> /private/var on macOS), so stripping it from a non-canonical file_path could leave an absolute path that the relative case patterns never matched — silently skipping the warning. Match and grep on the absolute path with */-anchored patterns instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ReviewOverview: Small, low-risk PR adding agent-facing tooling for RSC security: a Correctness
Minor nits (posted inline on the hook script)
Coverage/quality
Security: No new attack surface — this PR only adds documentation, an advisory dev-tool hook, and a test that locks in existing escaping behavior. No secrets, no new runtime code paths. Overall: solid, well-scoped addition. No blocking issues found. |
Address-review summaryScan scope: full review history through final head Mattered
Optional or duplicate signal
Thread dispositionAll 18 exact review threads received evidence-based replies before resolution. Four late correctness findings (compound assignment coverage, equality false positives, missing Late-thread roots:
Verification
Outcome
|
|
+ci-status |
|
+ci-run-hosted |
CI StatusHead SHA: Only the required gate is active unless hosted CI is requested. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3470143b01
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
ReviewSolid, low-risk addition: an agent-facing RSC security skill, a real regression test for the Code quality / correctness
Coverage gap worth notingThe hook (and the only automated test) cover invariant 1 only (inline script/HTML escaping) for Minor nitThe comment-line filter in the hook ( Everything else
Overall: good, well-scoped defensive tooling. No blocking issues. |
|
+ci-status |
|
+ci-run-hosted |
CI StatusHead SHA: Optimized hosted CI is enabled for this PR. |
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26e4a86778
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c0739f7672
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Review SummaryOverview: Adds an agent-facing Strengths
Issues raised inline
Other observations (non-blocking)
Overall: solid, low-risk addition. The three inline points are polish/maintainability nits rather than blockers. |
…ding, brittleness note, test relocation Resolves the 4 remaining unresolved review threads on PR #4599: - hook: exclude type-only `dangerouslySetInnerHTML` declarations and destructuring aliases from the raw-HTML sink scan. The `:` object-property branch now requires a `{ ... __html }` object value (drops `{ dangerouslySetInnerHTML: forwarded }`), and a new exclude_type_only_dangerously_set_inner_html filter drops TypeScript type members whose __html value is a bare `string`/`TrustedHTML` type token (e.g. `type Props = { dangerouslySetInnerHTML: { __html: string } }`). - hook: replace the off-topic "browser-performance-mark helper" sentence in the Ruby stream warning with an on-topic reminder about the json/html escaping invariant. - hook: document the SAFE_*_LINE exact-match MAINTENANCE CONTRACT — why exact byte-for-byte matching is chosen over a looser structural signature, and that the strings must be kept in sync with injectRSCPayload.ts. - tests: move the `rsc-guardrails hook` describe block (+ subprocess/fs helpers and imports) out of injectRSCPayload.test.ts into a dedicated tests/rscGuardrailsHook.test.ts, keeping the payload-escaping suite pure-JS. The new file is selected by the test:non-rsc suite (suite-selection guard green). Adds regression cases for the type-only and destructuring-alias exclusions. Validation: shellcheck + bash -n clean; jest rscGuardrailsHook.test.ts 16/16; jest injectRSCPayload.test.ts 77/77; test:suite-selection all 50 files selected; prettier + settings.json JSON valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e2d857feaa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Review: Add rsc-guardrails agent skill + payload-escaping regression test + advisory hookOverall this is a well-scoped, low-risk PR: it adds documentation and tests, and a non-blocking advisory hook — no production runtime code changes. I verified the diff ( What it does
Verification performed
Observations (non-blocking)
No blocking issues found. Nothing here affects production runtime behavior (docs + tests + advisory-only local dev tooling). |
Review: Add rsc-guardrails agent skill + payload-escaping regression test + advisory hookOverviewSolid, well-scoped tooling PR: an agent-facing skill doc ( Strengths
Issues / Suggestions
Security
Test coverageGood — both the payload-escaping regression and the hook's regex behavior are covered with edge cases. No blocking gaps found. Overall: a well-executed, low-risk, advisory-only addition. The two items worth a maintainer's attention before merge are #1 (coverage gap vs. the skill's stated scope) and #2 (brittle exact-line matching interacting with the autofix hook ordering) — neither is a blocker given the hook is non-blocking and well-tested, but both are worth a conscious "yes, we accept this" rather than being missed. |
…ML sinks Addresses the new codex P2 review thread on PR #4599: the line-oriented sink scan missed object/JSX dangerouslySetInnerHTML sinks whose `{ ... __html }` literal is split across lines (a shape prettier commonly produces), because the property line no longer contains `__html`. Adds a bounded multiline detector (detect_multiline_dangerously_set_inner_html): for a property/JSX line that opens an object literal (ends with `{`/`{{`) with no same-line `__html`, it scans up to 5 following lines for the `__html:` value and warns only when that value is a real raw-HTML sink — a variable/expression — honoring the same exemptions as the single-line path: TypeScript type tokens (`string`/`TrustedHTML` and unions) and non-interpolated string/template literals, which are not user-controlled. The property line is flagged. Kept shallow to avoid false positives; destructuring aliases (no object value) and same-line sinks (already covered) are excluded. Regression tests in rscGuardrailsHook.test.ts cover split object + JSX sinks (warn), and split type-only, unions, string/template literals, and destructuring aliases (no warning). Validation: shellcheck + bash -n clean; hook probe matrix 16/16; jest rscGuardrailsHook.test.ts 19/19; jest injectRSCPayload.test.ts 77/77; test:suite-selection all 50 files; prettier + settings.json JSON valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf059d2a86
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Review summaryThis PR ships an advisory-only, well-tested piece of agent tooling: an RSC-guardrails skill doc, a payload-escaping regression test, and a non-blocking Strengths
Gap worth addressing (left as inline comments)
No other correctness, security, or performance issues found. This is documentation/tooling-only with no runtime behavior change, so the "no CHANGELOG entry" call is reasonable. |
…; document base-package escaper Final advisory-hook review pass on PR #4599: - hook: fix the multiline detector's literal exemption. It exempted any value whose first character was a quote/backtick, so `__html: '<b>' + userHtml` (literal prefix + user concat) slipped through. Now only a SINGLE self-contained literal is exempt — anchored ^...$ matches for whole-value single/double-quoted strings and non-interpolated template literals — so a value that starts with a literal but concatenates or interpolates more still warns. - hook: add `document.writeln(` to the raw-HTML sink patterns alongside `document.write(` (`document\.write(ln)?\(`). - SKILL.md: add the base package's escaper `packages/react-on-rails/src/scriptSanitizedVal.ts` (used via `wrapInScriptTags` in `RenderUtils.ts`, consumed by helper.rb console-replay) to invariant 1's owner-file list, noting the deliberate `</script`-only vs `escapeScript`'s `</script`+`<!--` asymmetry. Documentation only; no glob change. Regression tests in rscGuardrailsHook.test.ts: literal-prefix/concat/interpolation sinks (warn), pure self-contained literals (quiet), and document.writeln/write (warn). Validation: shellcheck + bash -n clean; hook probe matrix 18/18; jest rscGuardrailsHook.test.ts 22/22; jest injectRSCPayload.test.ts 77/77; test:suite-selection all 50 files; prettier + settings.json JSON valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review summaryThis PR ships documentation + tooling for RSC security guardrails: a SKILL.md invariant doc, a regression test for Overview
Findings (left as inline comments, all low severity — none block merge)
None of these affect correctness of the shipped |
…t-policy * origin/main: (30 commits) Fix SSR crash on unpaired UTF-16 surrogates from JS JSON output (#4710) (#4726) Remove false Doctor pack-tag pairing warnings (fixes #4619) (#4724) Fix Pro renderer artifact cache identity (#4701) [Pro] Skip stream caches for error-containing renders (fixes #4581) (#4722) docs: mark 16.2.0 immediate_hydration override note as historical (fixes #4639) (#4725) Redact RSC rendering error details from client DOM in production (#4631) Fix fragile envSpecific gsub silently leaving lazy compilation on (#4632) Docs: node-renderer default setup requires Node.js 20+ (Fastify 5) (#4733) [Pro] Harden loadable-stats success-cache test; route worker tests through formAutoContent shim (partially addresses #4506) (#4721) Add rsc-guardrails agent skill + payload-escaping regression test + advisory hook (#4599) Regenerate llms-full references (#4728) CI: make hosted dispatch exact-head idempotent (#4692) Docs: normalize version floors, release metadata, and branch links (#4709) Docs: fix node-renderer startup, versions, and missing config options (#4707) Docs: fix Shakapacker build & migration recipes (#4703) (#4708) Docs: document Pro ExecJS profiling prerequisites & missing cached helpers (#4706) docs: correct OSS helper & API-reference examples (broken/stale snippets) (#4637) Docs: correct immediate_hydration removal details (#4638) (#4640) CI: route gem generator specs by changed paths (#4691) Prevent oversized GitHub release failures (#4714) ...
What
Ships an agent-facing guardrail for React Server Components (RSC) work in this repo, so the security and cross-request-isolation footguns surfaced in the recent RSC security audit don't silently regress. This is the framework-side half of a two-PR effort; the downstream app-installer (rake task that installs an RSC-usage skill + hook into consuming apps) is a follow-up PR.
Why
A focused RSC security audit (issues #4595, #4596, #4597) found the RSC stack solid, but identified a handful of invariants whose quiet regression would reintroduce XSS / cross-user-leak / auth footguns. This encodes those invariants where agents and reviewers will see them, and hard-locks the one mechanical invariant (inline-script escaping) with a test — per the "automate mechanical constraints, document judgment calls" principle.
Changes
.agents/skills/rsc-guardrails/SKILL.md— the invariants RSC changes must not regress: payload/script escaping, no per-request module-level state on server-render paths, module-resolution allow-list, client-reachable-entrypoint auth, no secrets/PII in logs, and the node-renderer trust boundary. Includes a PR review checklist and a red-flags list. Auto-available via the existing.claude/skills→.agents/skillssymlink.packages/react-on-rails-pro/tests/injectRSCPayload.test.ts— a regression test proving a user-controlled RSC payload chunk containing</script>/<!--is neutralized (</\script,<\!--) and cannot break out of the inline hydration script..claude/hooks/rsc-guardrails-check.sh+.claude/settings.json— a non-blockingPostToolUse(Edit|Write) warning when a Pro RSC source builds an inline<script>/HTML string outside the sanctionedescapeScript/createScriptTaghelpers. Always exits 0; comment-line filtered; zero false positives on the current tree.Verification
injectRSCPayload.test.ts: 77/77 pass (React 19.2.7). The new case's assertions were independently confirmed against the realescapeScriptoutput.injectRSCPayload.ts) / non-RSC paths; warns on a hand-built<script>probe.shellcheckclean.prettier --checkclean;settings.jsonvalid JSON; branch-lint + markdown-links pass.No user-facing runtime change; no CHANGELOG entry.
🤖 Generated with Claude Code
Summary by CodeRabbit