Skip to content

Auto-resolve renderer password from ENV in Rails Pro#2921

Merged
justin808 merged 6 commits intomainfrom
jg/renderer-env-default
Apr 3, 2026
Merged

Auto-resolve renderer password from ENV in Rails Pro#2921
justin808 merged 6 commits intomainfrom
jg/renderer-env-default

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Apr 2, 2026

Summary

Align React on Rails Pro Ruby-side NodeRenderer password behavior with the Node renderer by falling back to RENDERER_PASSWORD when neither config.renderer_password nor a URL-embedded password is provided, while preserving fail-closed checks for production-like environments and explicit blank-password failures. This PR also updates configuration specs to cover env fallback, URL precedence, and blank-password behavior, and updates Pro docs to document the new password precedence and setup expectations.

Pull Request checklist

  • Add/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file

Other Information

Validated with targeted RuboCop + RSpec for the changed Pro files and Prettier checks for the updated docs.


Note

Medium Risk
Changes NodeRenderer authentication configuration resolution on the Rails side, which can affect production startup/SSR connectivity if environments relied on previous blank-password behavior.

Overview
Aligns Rails Pro NodeRenderer password resolution with the Node renderer by having setup_renderer_password fall back to ENV["RENDERER_PASSWORD"] when neither config.renderer_password nor a URL-embedded password is provided, with blank values treated as unset.

Updates production-like validation messaging and expands RSpec coverage for precedence (config → URL → ENV) and blank-password cases, and refreshes docs/changelog with the new setup guidance plus additional renderer network-security warnings (including RENDERER_HOST/0.0.0.0 implications).

Written by Cursor Bugbot for commit 9bc630a. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • Documentation

    • Clarified password resolution precedence: configured password → URL-embedded password → environment variable; removed a documented hardcoded fallback and advise relying on ENV unless overridden.
    • Added network-security guidance: renderer defaults to localhost, warns it executes JS in a VM context, and advises always using a password and private networking when binding to 0.0.0.0; introduced RENDERER_HOST docs.
  • Improvements

    • Blank or empty password values now fall through to URL/ENV resolution, enabling ENV-based fallback.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

Walkthrough

Code, tests, and docs align password resolution and security guidance for the Node Renderer: effective password resolution order is config.renderer_password (blank treated as missing) → password embedded in config.renderer_url → ENV["RENDERER_PASSWORD"]. Documentation adds host/network security guidance and REPL/VM RCE warnings.

Changes

Cohort / File(s) Summary
Pro docs
docs/pro/installation.md, docs/pro/node-renderer.md
Removed the hardcoded "changeme" fallback in initializer docs; clarified that omitting config.renderer_password allows Rails to auto-read ENV["RENDERER_PASSWORD"] and documented the resolution precedence (config → URL → ENV).
OSS docs — Node Renderer
docs/oss/building-features/node-renderer/basics.md, docs/oss/building-features/node-renderer/container-deployment.md, docs/oss/building-features/node-renderer/js-configuration.md
Added RENDERER_HOST to env list; introduced a “Network Security” note describing RCE risk from Node vm.runInContext(); tightened guidance for binding to 0.0.0.0 (advise private networking/firewalls and require RENDERER_PASSWORD).
Configuration Logic
react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
setup_renderer_password now treats nil and "" as blank, attempts URL-derived password then falls back to ENV["RENDERER_PASSWORD"]; updated production validation message to describe the resolution order.
Configuration Tests
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb
Added tests asserting ENV-sourced password resolution when config and URL lack a password; adjusted stubs to include ENV.fetch("RENDERER_PASSWORD", nil) and updated production-related expectations.

Sequence Diagram(s)

sequenceDiagram
  participant Rails as Rails App
  participant Resolver as Password Resolver
  participant URL as Renderer URL
  participant ENV as ENV
  participant Node as Node Renderer

  Rails->>Resolver: provide `config.renderer_password` and `config.renderer_url`
  Resolver->>Resolver: if config.password present and non-blank → use it
  Resolver->>URL: parse password from `config.renderer_url` if config blank
  URL-->>Resolver: return URL password (or blank)
  alt URL blank
    Resolver->>ENV: read `ENV["RENDERER_PASSWORD"]`
    ENV-->>Resolver: return ENV password (or blank)
  end
  Resolver->>Rails: return effective password
  Rails->>Node: connect using effective password
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐇 I hopped through configs, sniffed the thread,

config then URL, then ENV instead.
I warned of vm's curious might,
bound localhost and screened the light.
Tests green — carrots for the night! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding automatic ENV fallback for renderer password resolution in Rails Pro.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg/renderer-env-default

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
Comment thread docs/pro/installation.md Outdated
Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 371fb88df6

ℹ️ 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".

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 2, 2026

Review: Auto-resolve renderer password from ENV in Rails Pro

The intent is solid and the test coverage is good. A few things worth addressing before merge:

Error message contradicts new behavior

The validate_renderer_password_for_production error message still instructs users to explicitly assign config.renderer_password = ENV.fetch("RENDERER_PASSWORD") in their initializer. With this PR, that assignment is now optional — just setting the env var is enough. A user who hits this error in production and follows the 'To fix this' guidance will add an unnecessary initializer line. See the inline comment at line 281.

Installation doc comment is self-contradicting

The added comment 'Optional: if omitted, Rails falls back to ENV...' sits above a line that still assigns ENV["RENDERER_PASSWORD"] || "changeme". If a user keeps that line with the 'changeme' fallback, the new auto-read logic never fires — renderer_password is already set to a non-blank string before setup_renderer_password reaches the ENV check. The doc snippet should either drop the line entirely or remove the || "changeme" fallback. See the inline comment at docs/pro/installation.md:302.

CHANGELOG is unchecked

The PR checklist marks 'Update CHANGELOG file' as unchecked. Per the project's contribution guidelines this should be filled in before merging.

Positive notes

The three-step precedence (config, URL, ENV) is cleanly implemented and aligns with Node-side behavior. The explicit_blank_password guard correctly prevents a bare env read when the user intentionally sets renderer_password = "", while still letting production validation raise. Test coverage is thorough: env-fallback success, explicit-blank-still-raises, URL-takes-precedence-over-env, and development passthrough are all covered.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 2, 2026

Greptile Summary

This PR aligns the Rails-side NodeRenderer password resolution with the Node Renderer's behavior by auto-resolving RENDERER_PASSWORD from ENV when neither config.renderer_password nor a URL-embedded password is supplied. It also updates configuration specs and documentation to cover the new precedence rules.

Key changes:

  • setup_renderer_password in configuration.rb now falls back to ENV["RENDERER_PASSWORD"] after failing to extract a password from the URL, mirroring Node-side behavior.
  • An explicit_blank_password guard prevents the ENV fallback when the user has explicitly assigned an empty string — keeping production fail-closed for intentional misconfigurations.
  • Three new/updated specs cover: ENV fallback resolution, URL-password precedence over ENV, explicit-blank-still-raises-in-production, and the new "env password satisfies production validation" path.
  • docs/pro/installation.md adds a comment indicating the renderer_password assignment is now optional, but still retains a hardcoded OR-fallback that silently bypasses production validation when RENDERER_PASSWORD is unset — this is a P1 concern.
  • docs/pro/node-renderer.md updates the precedence list and removes the note that ENV alone was insufficient, but the ENV.fetch("RENDERER_PASSWORD") (no default) code example will raise KeyError in development where the password is intentionally absent — also a P1 concern.
  • The documented precedence list states that an empty-string password is "treated as missing" (implying it falls through to ENV), but the implementation specifically blocks the ENV fallback for explicit blank passwords while still allowing the URL fallback — this asymmetry is undocumented.

Confidence Score: 2/5

  • Not safe to merge as-is: the updated docs example in installation.md retains a hardcoded OR-fallback that silently bypasses production validation, and the ENV.fetch example in node-renderer.md will raise KeyError in development environments.
  • The Ruby logic in configuration.rb is largely correct and the new specs provide good coverage. However, both documentation files introduce issues that can cause real-world failures: a hardcoded literal fallback that masks misconfiguration in production, and a strict ENV.fetch that breaks development boots. There is also a documented-vs-implemented inconsistency around explicit blank passwords and ENV fallback.
  • docs/pro/installation.md (hardcoded OR-fallback bypasses validation) and docs/pro/node-renderer.md (strict ENV.fetch example breaks development).

Important Files Changed

Filename Overview
react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Core logic change: ENV fallback added to setup_renderer_password; the explicit_blank_password flag correctly prevents ENV resolution for explicit "" assignments, but its documented behavior is inconsistent with the stated precedence list.
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb Good new coverage for ENV fallback, URL precedence, production ENV-password acceptance, and explicit-blank fail-closed; existing production-env context properly stubbed to avoid false negatives from real env values.
docs/pro/node-renderer.md Updated password precedence section is clear, but the ENV.fetch("RENDERER_PASSWORD") example (no default) will raise KeyError in development where the password is intentionally absent.
docs/pro/installation.md Added "Optional" comment is misleading: the `

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[setup_renderer_creds called] --> B{renderer_creds.present?}
    B -- Yes --> Z[Return early — already set]
    B -- No --> C{renderer_creds is explicit empty string?}
    C -- Yes --> D[explicit_blank = true]
    C -- No --> E[explicit_blank = false]
    D --> F[Extract creds from renderer_url URI]
    E --> F
    F --> G{URL creds found?}
    G -- Yes --> H[Use URL-embedded creds]
    G -- No --> I{explicit_blank?}
    I -- Yes --> J[Skip ENV — fail-closed for explicit blank]
    I -- No --> K[Resolve creds from ENV variable]
    H --> L[validate_creds_for_production]
    J --> L
    K --> L
    L --> M{creds present?}
    M -- Yes --> N[Valid — proceed]
    M -- No --> O{NodeRenderer in use?}
    O -- No --> N
    O -- Yes --> P{RAILS_ENV is dev or test?}
    P -- Yes --> N
    P -- No --> Q[Raise error — creds required in production]
Loading

Comments Outside Diff (1)

  1. docs/pro/node-renderer.md, line 94-97 (link)

    P1 ENV.fetch without a default raises KeyError in development

    The code block uses ENV.fetch("RENDERER_PASSWORD") (no default). In development environments where RENDERER_PASSWORD is intentionally absent, this will raise a KeyError on boot. The documentation immediately following this snippet explains that the assignment is now optional — Rails auto-resolves the password from ENV["RENDERER_PASSWORD"] — making this strict fetch pattern potentially dangerous for developers copying it verbatim.

    Consider using ENV.fetch("RENDERER_PASSWORD", nil) and adding a comment that a strict fetch (no default) is only appropriate when you are certain the variable is always set (i.e., production-only initializer). Alternatively, remove this snippet and refer readers to the updated precedence explanation below it.

Reviews (1): Last reviewed commit: "Align Rails password fallback with Node ..." | Re-trigger Greptile

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
Comment thread docs/pro/installation.md Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb (1)

152-162: Use named subjects for the new examples.

These new specs are good, but they should follow the repo RSpec convention by introducing named subjects for the configured result under test.

As per coding guidelines, "Use named subjects in RSpec tests (e.g., subject(:method_result) { ... } instead of unnamed subject { ... })."

Also applies to: 217-229, 253-264

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb` around
lines 152 - 162, Introduce a named RSpec subject for the configured value
instead of relying on implicit/unnamed subjects: after the
ReactOnRailsPro.configure block, add a subject like
subject(:configured_renderer_password) {
ReactOnRailsPro.configuration.renderer_password } and change the expectation to
use that named subject (e.g., expect(configured_renderer_password).to
eq("env-password")). Apply the same pattern to the other examples mentioned (the
examples around the other ranges) so each test exposes the result under test via
a subject(:name) { ... } referencing ReactOnRailsPro.configuration or the
specific method under test.
react_on_rails_pro/lib/react_on_rails_pro/configuration.rb (1)

278-283: Tighten precedence wording for explicit empty-string override.

Line 283 says empty-string assignment “will raise in production-like environments,” but with a URL-embedded password it won’t raise. Clarify that empty string blocks only the ENV fallback path.

✏️ Suggested wording update
-        Rails resolves the password in this order:
-          1) config.renderer_password (except empty string, which counts as missing)
-          2) Password embedded in config.renderer_url (for example, https://:password@host:3800)
-          3) ENV["RENDERER_PASSWORD"]
-
-        An empty-string assignment still counts as missing and will raise in production-like environments.
+        Rails resolves the password in this order:
+          1) config.renderer_password (except empty string, which is treated as unset)
+          2) Password embedded in config.renderer_url (for example, https://:password@host:3800)
+          3) ENV["RENDERER_PASSWORD"] (unless renderer_password was explicitly set to an empty string)
+
+        An explicit empty-string assignment disables ENV fallback and will raise in production-like environments
+        when no URL password is present.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/lib/react_on_rails_pro/configuration.rb` around lines 278
- 283, The doc comment in Configuration about password resolution is misleading:
change the sentence that currently reads “An empty-string assignment still
counts as missing and will raise in production-like environments.” to clarify
that assigning an empty string only prevents falling back to
ENV["RENDERER_PASSWORD"], but does not override a password embedded in
config.renderer_url; i.e., explicitly state that an empty-string
renderer_password blocks the ENV fallback path while a URL-embedded password in
config.renderer_url still takes precedence over ENV.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@react_on_rails_pro/lib/react_on_rails_pro/configuration.rb`:
- Around line 278-283: The doc comment in Configuration about password
resolution is misleading: change the sentence that currently reads “An
empty-string assignment still counts as missing and will raise in
production-like environments.” to clarify that assigning an empty string only
prevents falling back to ENV["RENDERER_PASSWORD"], but does not override a
password embedded in config.renderer_url; i.e., explicitly state that an
empty-string renderer_password blocks the ENV fallback path while a URL-embedded
password in config.renderer_url still takes precedence over ENV.

In `@react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb`:
- Around line 152-162: Introduce a named RSpec subject for the configured value
instead of relying on implicit/unnamed subjects: after the
ReactOnRailsPro.configure block, add a subject like
subject(:configured_renderer_password) {
ReactOnRailsPro.configuration.renderer_password } and change the expectation to
use that named subject (e.g., expect(configured_renderer_password).to
eq("env-password")). Apply the same pattern to the other examples mentioned (the
examples around the other ranges) so each test exposes the result under test via
a subject(:name) { ... } referencing ReactOnRailsPro.configuration or the
specific method under test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5c424df-278e-45ec-9632-7289ee31e92d

📥 Commits

Reviewing files that changed from the base of the PR and between 4c0f5bc and 371fb88.

📒 Files selected for processing (4)
  • docs/pro/installation.md
  • docs/pro/node-renderer.md
  • react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
  • react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb

@justin808
Copy link
Copy Markdown
Member Author

@claude review this PR

justin808 and others added 2 commits April 2, 2026 18:11
The Node Renderer executes arbitrary JavaScript via vm.runInContext(),
making it a remote code execution service by design. The vm module is
explicitly not a security boundary per the Node.js docs. The localhost
default follows PostgreSQL's model: secure by default at the network
layer, with authentication as a second layer for production environments.

Add a Network Security section to basics.md explaining the threat model,
the PostgreSQL analogy, and when/how to safely bind to 0.0.0.0.
Strengthen the security cautions in js-configuration.md and
container-deployment.md to reference the actual RCE risk rather than
generic "don't expose services" warnings. Add RENDERER_HOST to the
env var list in basics.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- installation.md: comment out renderer_password line in example so the
  "optional" comment is no longer contradicted by a hardcoded "changeme"
  fallback that prevents ENV auto-read from firing
- configuration.rb error message: lead with the simpler fix (just set
  ENV) instead of instructing both ENV + initializer assignment
- Clarify explicit-blank-password asymmetry: docs and error message now
  state that empty string skips the ENV fallback specifically, not all
  subsequent resolution steps

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@justin808
Copy link
Copy Markdown
Member Author

Review follow-up summary (773ba27)

Addressed 4 review comments, replied with rationale to 2 skipped items, and resolved all 6 threads.

Fixed

  1. installation.md — Commented out the renderer_password line in the example so the "Optional" guidance is no longer contradicted by a hardcoded || "changeme" fallback that prevents ENV auto-read from firing.

  2. configuration.rb error message — "To fix this" now leads with the simpler option (export RENDERER_PASSWORD=...) and presents the initializer assignment as an optional alternative.

  3. Precedence asymmetry — Updated docs and error message to explicitly state that empty string skips the ENV fallback specifically, not all subsequent resolution steps. The wording now reads: "empty string is treated as missing and skips the ENV fallback below".

Skipped with rationale

  1. Readability nit (simplify condition to renderer_password.nil?) — Current form with explicit_blank_password makes intent clearer.
  2. Whitespace-only passwords — Extremely unlikely edge case; current behavior (treating as blank) is reasonable.

Note: The missing CHANGELOG entry was flagged separately in an earlier review pass.

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
Comment thread docs/pro/node-renderer.md
Comment thread react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 3, 2026

Review: Auto-resolve renderer password from ENV in Rails Pro

The direction is right — aligning Ruby-side behavior with the Node renderer defaults reduces boilerplate and removes a common misconfiguration footgun. The security documentation additions are also a net positive. A few issues worth addressing before merge:

Logic gap: explicit empty string + URL-embedded password

The most significant issue is in setup_renderer_password. Because the early return only guards on renderer_password.present?, an explicit empty string (config.renderer_password = "") falls through to URL extraction (line 238), which can silently overwrite the empty string with the URL password. This means explicit_blank_password = true prevents ENV fallback but does not prevent URL override — the documented precedence (config → URL → ENV) doesn't hold for the empty-string case.

See inline comment on configuration.rb:236 for a suggested fix.

Documentation wording is self-contradictory

The precedence list in node-renderer.md says "empty string is treated as missing and skips the ENV fallback" — "treated as missing" implies falling through to ENV, which the second clause then contradicts. This could mislead an admin into thinking config.renderer_password = "" is equivalent to not setting it (which would pick up ENV). It is not.

See inline comment on docs/pro/node-renderer.md.

Missing test for empty-string + URL-embedded-password interaction

There's no test covering renderer_password = "" combined with a URL that has an embedded password. Until the intended behavior for that edge case is decided and tested, the test suite doesn't fully specify the contract.

See inline comment on configuration_spec.rb:253.

Changelog not updated

The PR checklist has "Update CHANGELOG file" unchecked. Per project conventions this should be filled in before merge.


The ENV fallback logic itself (lines 242–244) is clean, the new tests for the happy path and production fail-closed behavior are correct, and the security documentation additions are accurate and useful.

justin808 and others added 3 commits April 2, 2026 20:13
…sword

An empty-string `config.renderer_password` now falls through to URL
and ENV resolution just like nil, instead of blocking the ENV fallback.
This simplifies the mental model: blank = not set.

- Remove explicit_blank_password variable and guard
- Update precedence docs and error message to remove empty-string special case
- Change test: "" + ENV now resolves from ENV instead of raising
- Add test: "" + URL-embedded password resolves from URL

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Remove Ruby code block with bare ENV.fetch("RENDERER_PASSWORD") that
  would raise KeyError in development where the password is intentionally
  absent. The bash export example and precedence list below are sufficient.
- Replace jargon "truthy password" with "non-empty password".

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

# Mirror Node-side defaults: if Rails config and URL are both missing a password,
# use RENDERER_PASSWORD from env.
self.renderer_password = ENV.fetch("RENDERER_PASSWORD", nil) if renderer_password.blank?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ENV.fetch("RENDERER_PASSWORD", nil) and ENV["RENDERER_PASSWORD"] are functionally identical — ENV[] already returns nil for missing keys. The fetch form adds no value here and may look like it implies a meaningful difference from a plain lookup.

Suggested change
self.renderer_password = ENV.fetch("RENDERER_PASSWORD", nil) if renderer_password.blank?
self.renderer_password = ENV["RENDERER_PASSWORD"] if renderer_password.blank?

@@ -195,6 +214,20 @@ def self.fetch(*)
end.to raise_error(ReactOnRailsPro::Error, /RENDERER_PASSWORD must be set/)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There's no test covering the case where RENDERER_PASSWORD is set to an empty string in the environment in production. Since "" is also blank, validate_renderer_password_for_production should still raise. Worth adding to confirm the fail-closed path holds when ENV["RENDERER_PASSWORD"] = "":

it "raises when RENDERER_PASSWORD env var is blank in production" do
  allow(ENV).to receive(:[]).with("RAILS_ENV").and_return("production")
  allow(ENV).to receive(:fetch).with("RENDERER_PASSWORD", nil).and_return("")

  expect do
    ReactOnRailsPro.configure do |config|
      config.server_renderer = "NodeRenderer"
      config.renderer_url = "https://localhost:3800"
    end
  end.to raise_error(ReactOnRailsPro::Error, /RENDERER_PASSWORD must be set/)
end

end.to raise_error(ReactOnRailsPro::Error, /RENDERER_PASSWORD must be set/)
end.not_to raise_error

expect(ReactOnRailsPro.configuration.renderer_password).to eq("secure-password")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Heads-up on the semantic shift this test represents: previously config.renderer_password = "" in production was an error (the old test was named "raises when renderer_password is explicitly set to blank in production"). Now it silently falls through to ENV["RENDERER_PASSWORD"].

This is probably the right design — treating blank the same as unset is consistent and the resolution chain is clearly documented. But it's worth being aware that any callers who relied on renderer_password = "" to disable authentication (prevent any password from being used) will now silently pick up the env var instead. Worth a note in the CHANGELOG or migration guide for anyone upgrading from the old fail-closed behavior.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 3, 2026

Review

The overall approach is solid — aligning Ruby-side password resolution with the Node Renderer's three-tier chain (config → URL → ENV) removes the footgun of needing an explicit initializer assignment, and the security documentation additions are a meaningful improvement.

Things that look good:

  • Removal of the hardcoded || "changeme" default from docs/pro/installation.md is an important security hygiene fix.
  • The Network Security section in basics.md clearly explains the RCE risk from vm.runInContext() and when binding to 0.0.0.0 is appropriate.
  • The fail-closed behavior (unset RAILS_ENV treated as production-like) is correctly preserved.
  • The error message now documents the resolution order, which will help with debugging.

Minor issues flagged inline:

  1. ENV.fetch("RENDERER_PASSWORD", nil) — functionally identical to ENV["RENDERER_PASSWORD"], the fetch form adds visual noise without semantic benefit.
  2. Missing test: a blank RENDERER_PASSWORD env var ("") in production should still raise — confirm the fail-closed path holds at the ENV layer too.
  3. Semantic shift for explicit renderer_password = "": this used to unconditionally raise in production; now it silently falls through to the env var. The behavior change is probably correct, but it's a subtle breaking change for anyone who used a blank explicit assignment as a way to ensure no password was applied.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb (1)

253-280: Consider adding the blank-without-ENV negative case.

You now test blank renderer_password resolving from ENV and URL, but there isn’t an explicit example asserting it still raises in production-like env when both are absent. Adding that case would fully pin fail-closed behavior for the new blank path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb` around
lines 253 - 280, Add a negative test that ensures blank renderer_password still
fails when neither ENV nor URL provide one: stub ENV["RAILS_ENV"] to
"production", stub ENV.fetch("RENDERER_PASSWORD", nil) to return nil, set
config.renderer_password = "" and config.renderer_url to a URL without an
embedded password, then wrap ReactOnRailsPro.configure block and assert it
raises (use expect { ReactOnRailsPro.configure { ... } }.to raise_error) and
that ReactOnRailsPro.configuration.renderer_password is not set to a value; this
uses the existing ReactOnRailsPro.configure and
ReactOnRailsPro.configuration.renderer_password symbols referenced in the other
specs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb`:
- Around line 253-280: Add a negative test that ensures blank renderer_password
still fails when neither ENV nor URL provide one: stub ENV["RAILS_ENV"] to
"production", stub ENV.fetch("RENDERER_PASSWORD", nil) to return nil, set
config.renderer_password = "" and config.renderer_url to a URL without an
embedded password, then wrap ReactOnRailsPro.configure block and assert it
raises (use expect { ReactOnRailsPro.configure { ... } }.to raise_error) and
that ReactOnRailsPro.configuration.renderer_password is not set to a value; this
uses the existing ReactOnRailsPro.configure and
ReactOnRailsPro.configuration.renderer_password symbols referenced in the other
specs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fdd2dc00-5343-4e47-8c59-f3cc2db3ccc5

📥 Commits

Reviewing files that changed from the base of the PR and between 773ba27 and 9bc630a.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/pro/node-renderer.md
  • react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
  • react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb
✅ Files skipped from review due to trivial changes (2)
  • docs/pro/node-renderer.md
  • CHANGELOG.md

@justin808 justin808 merged commit ea72c13 into main Apr 3, 2026
42 checks passed
@justin808 justin808 deleted the jg/renderer-env-default branch April 3, 2026 08:35
justin808 added a commit that referenced this pull request Apr 8, 2026
…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
justin808 added a commit that referenced this pull request Apr 8, 2026
…lacement-2835-main

* origin/main: (44 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:
#	CHANGELOG.md
@justin808 justin808 mentioned this pull request Apr 8, 2026
2 tasks
justin808 added a commit that referenced this pull request Apr 8, 2026
### Summary

Adds missing changelog entries to the `[Unreleased]` section for PRs
merged since `v16.6.0.rc.0`. Analyzed 19 commits on `origin/main` since
the last tag, identified 1 missing user-visible PR (#3069), and skipped
10 non-user-visible PRs (docs, tests, internal refactors).

**New entries added:**
- **Added**: `[Pro] Configurable HTTP keep-alive timeout for node
renderer connections` (PR #3069)
- **Fixed**: `[Pro] Fixed SSR failures from stale persistent HTTP/2
connections` (PR #3069)

**Entries already present** (added in prior changelog updates): PRs
#2834, #2881, #2918, #2921, #2923, #2932, #3063, #3068, #3070.

**Skipped** (not user-visible): #2893 (docs), #2916 (docs), #2922 (test
fix), #2923 (test fix), #2925 (internal refactor), #3064 (docs), #3065
(docs), #3066 (docs), #3067 (docs), #3072 (docs).

### Pull Request checklist

- [x] ~Add/update test to cover these changes~
- [x] ~Update documentation~
- [x] Update CHANGELOG file

### Other Information

No code changes — CHANGELOG.md only.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because this PR only changes documentation (`CHANGELOG.md`)
and does not modify runtime code.
> 
> **Overview**
> Updates `CHANGELOG.md` *[Unreleased]* to include missing Pro release
notes for PR `#3069`, documenting the new
`renderer_http_keep_alive_timeout` config and the associated fix for SSR
failures from stale persistent HTTP/2 connections to the node renderer.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8d1a480. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Interactive mode selection prompt for CLI tool when no explicit mode
is specified
* Configurable keep-alive timeout setting for Pro users (default 30
seconds)

* **Bug Fixes**
  * Enhanced validation and error handling for invalid request payloads
  * Improved template literal handling in code generation
  * Better HTTP connection stability with enhanced diagnostic messaging

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
### Summary

Align React on Rails Pro Ruby-side NodeRenderer password behavior with
the Node renderer by falling back to `RENDERER_PASSWORD` when neither
`config.renderer_password` nor a URL-embedded password is provided,
while preserving fail-closed checks for production-like environments and
explicit blank-password failures. This PR also updates configuration
specs to cover env fallback, URL precedence, and blank-password
behavior, and updates Pro docs to document the new password precedence
and setup expectations.

### Pull Request checklist

- [x] Add/update test to cover these changes
- [x] Update documentation
- [ ] Update CHANGELOG file

### Other Information

Validated with targeted RuboCop + RSpec for the changed Pro files and
Prettier checks for the updated docs.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes NodeRenderer authentication configuration resolution on the
Rails side, which can affect production startup/SSR connectivity if
environments relied on previous blank-password behavior.
> 
> **Overview**
> Aligns Rails Pro `NodeRenderer` password resolution with the Node
renderer by having `setup_renderer_password` fall back to
`ENV["RENDERER_PASSWORD"]` when neither `config.renderer_password` nor a
URL-embedded password is provided, with blank values treated as unset.
> 
> Updates production-like validation messaging and expands RSpec
coverage for precedence (config → URL → ENV) and blank-password cases,
and refreshes docs/changelog with the new setup guidance plus additional
renderer network-security warnings (including `RENDERER_HOST`/`0.0.0.0`
implications).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9bc630a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Clarified password resolution precedence: configured password →
URL-embedded password → environment variable; removed a documented
hardcoded fallback and advise relying on ENV unless overridden.
* Added network-security guidance: renderer defaults to localhost, warns
it executes JS in a VM context, and advises always using a password and
private networking when binding to 0.0.0.0; introduced RENDERER_HOST
docs.

* **Improvements**
* Blank or empty password values now fall through to URL/ENV resolution,
enabling ENV-based fallback.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
### Summary

Adds missing changelog entries to the `[Unreleased]` section for PRs
merged since `v16.6.0.rc.0`. Analyzed 19 commits on `origin/main` since
the last tag, identified 1 missing user-visible PR (#3069), and skipped
10 non-user-visible PRs (docs, tests, internal refactors).

**New entries added:**
- **Added**: `[Pro] Configurable HTTP keep-alive timeout for node
renderer connections` (PR #3069)
- **Fixed**: `[Pro] Fixed SSR failures from stale persistent HTTP/2
connections` (PR #3069)

**Entries already present** (added in prior changelog updates): PRs
#2834, #2881, #2918, #2921, #2923, #2932, #3063, #3068, #3070.

**Skipped** (not user-visible): #2893 (docs), #2916 (docs), #2922 (test
fix), #2923 (test fix), #2925 (internal refactor), #3064 (docs), #3065
(docs), #3066 (docs), #3067 (docs), #3072 (docs).

### Pull Request checklist

- [x] ~Add/update test to cover these changes~
- [x] ~Update documentation~
- [x] Update CHANGELOG file

### Other Information

No code changes — CHANGELOG.md only.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because this PR only changes documentation (`CHANGELOG.md`)
and does not modify runtime code.
> 
> **Overview**
> Updates `CHANGELOG.md` *[Unreleased]* to include missing Pro release
notes for PR `#3069`, documenting the new
`renderer_http_keep_alive_timeout` config and the associated fix for SSR
failures from stale persistent HTTP/2 connections to the node renderer.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8d1a480. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Interactive mode selection prompt for CLI tool when no explicit mode
is specified
* Configurable keep-alive timeout setting for Pro users (default 30
seconds)

* **Bug Fixes**
  * Enhanced validation and error handling for invalid request payloads
  * Improved template literal handling in code generation
  * Better HTTP connection stability with enhanced diagnostic messaging

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
### Summary

Align React on Rails Pro Ruby-side NodeRenderer password behavior with
the Node renderer by falling back to `RENDERER_PASSWORD` when neither
`config.renderer_password` nor a URL-embedded password is provided,
while preserving fail-closed checks for production-like environments and
explicit blank-password failures. This PR also updates configuration
specs to cover env fallback, URL precedence, and blank-password
behavior, and updates Pro docs to document the new password precedence
and setup expectations.

### Pull Request checklist

- [x] Add/update test to cover these changes
- [x] Update documentation
- [ ] Update CHANGELOG file

### Other Information

Validated with targeted RuboCop + RSpec for the changed Pro files and
Prettier checks for the updated docs.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes NodeRenderer authentication configuration resolution on the
Rails side, which can affect production startup/SSR connectivity if
environments relied on previous blank-password behavior.
> 
> **Overview**
> Aligns Rails Pro `NodeRenderer` password resolution with the Node
renderer by having `setup_renderer_password` fall back to
`ENV["RENDERER_PASSWORD"]` when neither `config.renderer_password` nor a
URL-embedded password is provided, with blank values treated as unset.
> 
> Updates production-like validation messaging and expands RSpec
coverage for precedence (config → URL → ENV) and blank-password cases,
and refreshes docs/changelog with the new setup guidance plus additional
renderer network-security warnings (including `RENDERER_HOST`/`0.0.0.0`
implications).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9bc630a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Clarified password resolution precedence: configured password →
URL-embedded password → environment variable; removed a documented
hardcoded fallback and advise relying on ENV unless overridden.
* Added network-security guidance: renderer defaults to localhost, warns
it executes JS in a VM context, and advises always using a password and
private networking when binding to 0.0.0.0; introduced RENDERER_HOST
docs.

* **Improvements**
* Blank or empty password values now fall through to URL/ENV resolution,
enabling ENV-based fallback.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
### Summary

Adds missing changelog entries to the `[Unreleased]` section for PRs
merged since `v16.6.0.rc.0`. Analyzed 19 commits on `origin/main` since
the last tag, identified 1 missing user-visible PR (#3069), and skipped
10 non-user-visible PRs (docs, tests, internal refactors).

**New entries added:**
- **Added**: `[Pro] Configurable HTTP keep-alive timeout for node
renderer connections` (PR #3069)
- **Fixed**: `[Pro] Fixed SSR failures from stale persistent HTTP/2
connections` (PR #3069)

**Entries already present** (added in prior changelog updates): PRs
#2834, #2881, #2918, #2921, #2923, #2932, #3063, #3068, #3070.

**Skipped** (not user-visible): #2893 (docs), #2916 (docs), #2922 (test
fix), #2923 (test fix), #2925 (internal refactor), #3064 (docs), #3065
(docs), #3066 (docs), #3067 (docs), #3072 (docs).

### Pull Request checklist

- [x] ~Add/update test to cover these changes~
- [x] ~Update documentation~
- [x] Update CHANGELOG file

### Other Information

No code changes — CHANGELOG.md only.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because this PR only changes documentation (`CHANGELOG.md`)
and does not modify runtime code.
> 
> **Overview**
> Updates `CHANGELOG.md` *[Unreleased]* to include missing Pro release
notes for PR `#3069`, documenting the new
`renderer_http_keep_alive_timeout` config and the associated fix for SSR
failures from stale persistent HTTP/2 connections to the node renderer.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8d1a480. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Interactive mode selection prompt for CLI tool when no explicit mode
is specified
* Configurable keep-alive timeout setting for Pro users (default 30
seconds)

* **Bug Fixes**
  * Enhanced validation and error handling for invalid request payloads
  * Improved template literal handling in code generation
  * Better HTTP connection stability with enhanced diagnostic messaging

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
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.

1 participant