Skip to content

Enforce secure renderer password defaults for production-like envs#2829

Merged
justin808 merged 26 commits intomainfrom
jg/2795-secure-renderer-pw
Mar 29, 2026
Merged

Enforce secure renderer password defaults for production-like envs#2829
justin808 merged 26 commits intomainfrom
jg/2795-secure-renderer-pw

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Mar 24, 2026

Summary

  • [Pro] Require explicit RENDERER_PASSWORD when using NodeRenderer in production-like environments (anything other than development or test). Both the Ruby configuration and the Node.js buildConfig now raise/throw on startup if no password is set.
  • Keep dev/test convenience: no password required, no authentication enforced.
  • Error messages include actionable setup examples and an environment matrix.
  • Documentation updated in docs/pro/node-renderer.md and docs/oss/building-features/node-renderer/js-configuration.md.

Closes #2795

Test plan

  • Ruby: 35 configuration specs pass (cd react_on_rails_pro && bundle exec rspec spec/react_on_rails_pro/configuration_spec.rb) — 8 new specs covering production/staging enforcement, dev/test bypass, ExecJS exemption, and URL-embedded password
  • Node.js: 8 configBuilder tests pass (jest tests/configBuilder.test.ts) — 6 new specs covering production/staging enforcement, dev/test bypass, env var and config-object password
  • RuboCop: zero offenses
  • Prettier: all files formatted
  • Pre-commit and pre-push hooks pass

🤖 Generated with Claude Code


Note

High Risk
Introduces fail-fast startup validation for NodeRenderer password in production-like environments, which is a breaking change that can prevent staging/production deployments from booting if misconfigured.

Overview
Enforces secure defaults for React on Rails Pro NodeRenderer authentication. The Node renderer now refuses to start in any non-development/test environment (including when NODE_ENV/RAILS_ENV are unset) unless a truthy RENDERER_PASSWORD is provided, with clearer diagnostics and masking of password values in logs.

Rails-side Pro configuration adds matching validation: when using NodeRenderer, it raises during configuration if renderer_password is missing/blank in production-like environments, and clarifies that the initializer must explicitly assign config.renderer_password = ENV.fetch("RENDERER_PASSWORD").

Docs and release notes are updated to describe the new environment matrix and setup steps; tests are expanded on both Node and Ruby to cover the new enforcement and logging behavior, and link-check config excludes an intermittently timing-out PDF URL.

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

Summary by CodeRabbit

  • Documentation

    • Clarified renderer password behavior: optional in development/test, required in staging/production, plus guidance for securely configuring Rails↔Node passwords and local dev conveniences.
  • Chores

    • Enforced environment-based startup validation so production-like deployments fail fast when no renderer password is provided.
    • Improved diagnostics: masked default passwords in logs and added warnings when an undefined config preserves env/default values.
  • Tests

    • Expanded tests to cover password requirements, error behavior, and logging across environments and renderer types.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 24, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Node renderer and Rails now enforce renderer password in production-like environments: password is optional in development/test, but Node will exit on startup and Rails will raise if a password is missing in non-dev/test environments. Docs, tests, and changelog updated accordingly.

Changes

Cohort / File(s) Summary
Documentation
docs/oss/building-features/node-renderer/js-configuration.md, docs/pro/node-renderer.md, CHANGELOG.md
Documented environment-dependent RENDERER_PASSWORD requirements, added examples and guidance; added changelog entry describing masking and warnings.
Node renderer: implementation
packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts
Derive runtime envs at runtime, preserve late-bound defaults, change replayServerAsyncOperationLogs default resolution, add validatePasswordForProduction that logs a multi-line error and calls process.exit(1) when password is missing in production-like envs; sanitize logging to mask module-load defaults.
Node renderer: tests
packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts
Snapshot/restore env vars, capture logger error/warn, spy process.exit, add tests asserting fail-closed startup in production-like envs, handling of explicit vs env-provided vs empty passwords, and replayServerAsyncOperationLogs defaulting.
Rails configuration
react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
Populate renderer_password from renderer_url when present; add validate_renderer_password_for_production to raise ReactOnRailsPro::Error for NodeRenderer in non-dev/test when password is missing.
Rails specs
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb
Expanded specs to cover raise/no-raise behavior across development, test, staging, production for NodeRenderer and ExecJS, including embedded-password and explicit-password cases.

Sequence Diagram(s)

sequenceDiagram
  participant Launcher as "Launcher"
  participant Node as "NodeRenderer.buildConfig()"
  participant Env as "process.env"
  participant Proc as "process (exit)"

  Launcher->>Node: start renderer
  Node->>Env: read NODE_ENV, RAILS_ENV, RENDERER_PASSWORD, REPLAY_SERVER_ASYNC_OPERATION_LOGS
  Node->>Node: recompute runtime defaults, merge config (filter undefined)
  Node->>Node: log sanitized config (mask module-load defaults)
  Node->>Node: validatePasswordForProduction()
  alt password present OR env is development/test
    Node->>Launcher: return Config (startup continues)
  else missing password in non-dev/test
    Node->>Launcher: log multi-line error with env matrix and instructions
    Node->>Proc: process.exit(1)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibbled through envs both calm and stern,
Kept devs carefree and made prod learn.
Where test is gentle, a default may stay,
But production demands a guarded way.
I guard the key — hop secure, I say.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: enforcing secure renderer password defaults in production-like environments.
Linked Issues check ✅ Passed All objectives from #2795 are met: RENDERER_PASSWORD required in production/staging, dev/test convenience preserved, error messages improved, environment matrix documented.
Out of Scope Changes check ✅ Passed All changes are directly related to enforcing password requirements across environments; no unrelated or extraneous modifications detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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/2795-secure-renderer-pw

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 24, 2026

Greptile Summary

This PR enforces a secure-by-default renderer password policy for NodeRenderer in production-like environments: both the Ruby Configuration and the TypeScript buildConfig now raise/throw at startup if no password is provided and NODE_ENV / Rails.env is anything other than development or test. Dev and test environments are unchanged — no password required, no breaking change for local setups.

Key changes:

  • Ruby (configuration.rb): new private validate_renderer_password_for_production method called from setup_renderer_password; correctly skips ExecJS, skips dev/test, accepts password from URL or direct attribute.
  • TypeScript (configBuilder.ts): new validatePasswordForProduction function inserted just before log.level is set in buildConfig; uses the module-level NODE_ENV constant (defaults to 'production' when unset, which is the safer default).
  • Tests: 8 Ruby specs and 6 Jest tests cover all branches of the matrix. The Jest afterEach correctly restores NODE_ENV/RENDERER_PASSWORD and calls jest.resetModules() so each test gets a fresh module with its own captured NODE_ENV.
  • Docs: environment matrix table and setup examples added to both documentation pages.

Minor items: the inline comment on the password field in the TypeScript Config interface was not updated and still says "no authentication will be required" (inaccurate for production). The node_renderer? Ruby helper references ReactOnRailsPro.configuration.server_renderer rather than server_renderer directly, which is functionally equivalent but slightly roundabout.

Confidence Score: 5/5

  • Safe to merge — the new validation is additive and fail-fast at startup, existing dev/test workflows are unaffected, and test coverage is thorough.
  • Both sides of the stack (Ruby + Node) implement the same guard correctly. All relevant branches are exercised by new specs. The only findings are a stale comment and a minor stylistic indirection in a helper method — neither affects runtime behavior. No data-loss or regression risk.
  • No files require special attention beyond the two minor P2 style comments on configBuilder.ts and configuration.rb.

Important Files Changed

Filename Overview
packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Adds validatePasswordForProduction which throws at startup when NODE_ENV is not development/test and no password is configured. Logic is sound; the module-level NODE_ENV constant (`env.NODE_ENV
react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Adds validate_renderer_password_for_production called from setup_renderer_password. Guards are correct: skips if password is already present, skips for non-NodeRenderer, skips in development/test. The node_renderer? helper uses an indirect ReactOnRailsPro.configuration.server_renderer reference instead of server_renderer directly, which is functional but slightly circular.
packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts Six new tests cover the full validation matrix (production/staging throw, dev/test don't throw, env-var vs config-object password). The afterEach correctly restores NODE_ENV and RENDERER_PASSWORD and calls jest.resetModules() so that the module-level NODE_ENV constant is re-evaluated on each fresh import.
react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb Eight new specs cover production/staging enforcement, dev/test bypass, URL-embedded password, and ExecJS exemption. The existing "blank if not provided" test was updated to mock a development environment, keeping the test intent correct.
docs/pro/node-renderer.md New "Renderer Password Security" section with a clear environment matrix table and code examples. Accurate and consistent with implementation.
docs/oss/building-features/node-renderer/js-configuration.md Updated password option description to call out the dev/test vs production-like environment distinction. Clear and correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ReactOnRailsPro.configure / buildConfig called] --> B{renderer_password\nalready set directly?}
    B -- Yes --> Z[Continue startup normally]
    B -- No --> C[Extract password from renderer_url]
    C --> D{Password found\nin URL?}
    D -- Yes --> Z
    D -- No --> E{node_renderer? /\nNodeRenderer in use?}
    E -- No ExecJS --> Z
    E -- Yes --> F{Rails.env /\nNODE_ENV}
    F -- development or test --> Z
    F -- staging / production\nor NODE_ENV unset --> G[🚨 Raise / Throw error\nREREERER_PASSWORD must be set]
    G --> H[App refuses to start]
Loading

Comments Outside Diff (2)

  1. packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts, line 59-61 (link)

    P2 Stale inline comment on password field

    The JSDoc comment on the password property in the Config interface still reads // If no password is set, no authentication will be required., which was true before this PR. Now that validatePasswordForProduction enforces a required password in non-dev/test environments, the comment is inaccurate. It should reflect the new environment-gated behavior.

  2. react_on_rails_pro/lib/react_on_rails_pro/configuration.rb, line 183-185 (link)

    P2 Indirect self-reference in node_renderer?

    node_renderer? calls ReactOnRailsPro.configuration.server_renderer which resolves to self when invoked from within setup_config_values. This works, but a direct reference to the attribute is clearer and removes the circular lookup:

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "Enforce secure renderer password default..." | Re-trigger Greptile

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

PR Review: Enforce secure renderer password defaults for production-like envs

Overall, this is a well-structured security improvement. The fail-fast approach (raising at configuration/startup time rather than at request time) is the right pattern, the dev/test bypass is appropriate, and the error messages are actionable. Test coverage is solid. A few things worth flagging:


Medium: Validation can be bypassed via explicit renderer_password= assignment

The spec test "does not raise when password is explicitly set in production" passes, but not because validate_renderer_password_for_production evaluates the password and finds it valid — validation is never called at all. setup_renderer_password early-returns before reaching it:

```ruby
def setup_renderer_password
return if renderer_password.present? # validation skipped entirely here
...
validate_renderer_password_for_production
end
```

This means any code path that pre-sets renderer_password (direct setter, re-configure, initializer keyword arg) bypasses the validator. The current behavior is safe because the password is set in those cases, but the security guarantee depends on caller discipline rather than the validator itself.

Consider calling validate_renderer_password_for_production unconditionally from setup_config_values (it already has its own return if renderer_password.present? guard), or at least add a comment explaining why the early-return path is still secure.


Low: node_renderer? accesses configuration through the class method

node_renderer? is an instance method on Configuration but calls ReactOnRailsPro.configuration.server_renderer — a round-trip through the class accessor that returns self. Using server_renderer == "NodeRenderer" directly would be clearer and avoids any potential issue if this is called during a transitional state.


Low: No JS test for custom NODE_ENV values

The TypeScript tests cover production, staging, development, and test, but not values like ci, qa, or review. These would also trigger the error (intentionally), but an explicit test would make the contract visible and guard against future accidental relaxation.


Informational: defined?(Rails) is a correct fail-secure guard

return if defined?(Rails) && (Rails.env.development? || Rails.env.test?) will raise if Rails is somehow not defined, rather than silently skipping validation. Good safe-default pattern.


Docs nit

The local-dev convenience example in docs/pro/node-renderer.md uses "devPassword" as the fallback default. That string looks plausible enough that a developer might accidentally ship it to staging. A more obviously non-production value like "dev-only-not-for-production" or dropping the default entirely (relying on the no-auth-in-dev behavior) would be safer.

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: 8c5d1acd93

ℹ️ 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 packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 24, 2026

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 62.63 KB (0%)
react-on-rails/client bundled (gzip) (time) 62.63 KB (0%)
react-on-rails/client bundled (brotli) 53.7 KB (0%)
react-on-rails/client bundled (brotli) (time) 53.7 KB (0%)
react-on-rails-pro/client bundled (gzip) 63.65 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 63.65 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.67 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 54.67 KB (0%)
registerServerComponent/client bundled (gzip) 127.46 KB (0%)
registerServerComponent/client bundled (gzip) (time) 127.46 KB (0%)
registerServerComponent/client bundled (brotli) 61.65 KB (0%)
registerServerComponent/client bundled (brotli) (time) 61.65 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 122.02 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 122.02 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 56.77 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 56.77 KB (0%)

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
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.

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 `@packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts`:
- Around line 251-269: validatePasswordForProduction currently only checks
NODE_ENV; update it to consider both NODE_ENV and RAILS_ENV so password
enforcement matches Rails usage: compute nodeEnv = NODE_ENV and railsEnv =
process.env.RAILS_ENV, treat the environment as "production-like" if either env
is not 'development' or 'test' (e.g., 'staging'/'production'), and require a
password in that case inside validatePasswordForProduction(Config).
Additionally, detect and fail-closed on a mixed env mismatch (one env
production-like and the other development/test) by throwing an explicit error
explaining the mismatch so the caller can align RAILS_ENV and NODE_ENV or
provide RENDERER_PASSWORD; reference validatePasswordForProduction, NODE_ENV,
and RAILS_ENV when making these changes.
🪄 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: 556bcce9-9556-4be6-9dcd-c8b73b811d0e

📥 Commits

Reviewing files that changed from the base of the PR and between c8267da and 8c5d1ac.

📒 Files selected for processing (6)
  • docs/oss/building-features/node-renderer/js-configuration.md
  • docs/pro/node-renderer.md
  • packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts
  • packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts
  • react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
  • react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb

Comment thread packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
Aligns validatePasswordForProduction with master.ts, which already checks
both NODE_ENV and RAILS_ENV for production detection. Previously only
NODE_ENV was checked, so RAILS_ENV=production with NODE_ENV=development
would skip password enforcement while the master ran in production mode.

The new logic also fails closed when neither env var is set, matching the
existing default of NODE_ENV defaulting to 'production'.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Comment thread packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

Review: Enforce secure renderer password defaults

Overall this is a well-motivated security hardening PR with solid test coverage. The fail-closed approach (require password in all non-dev/test environments, including when neither env var is set) is the right default. A few issues worth addressing before merge:

Missing CHANGELOG entry

react_on_rails_pro/CHANGELOG.md has no entry for this change. This is a breaking change for any existing user who deploys to a staging or production environment without RENDERER_PASSWORD set — they will get a startup failure on upgrade. It should be called out prominently in the changelog with a clear migration path (e.g., "set RENDERER_PASSWORD or silence the check by explicitly opting into no-auth").

Breaking change: no deprecation path

Users upgrading react-on-rails-pro who use NodeRenderer in staging/production without a password will get an immediate hard failure on boot. There's no warning-before-error phase. Depending on your semver policy this may be fine, but it should at minimum be:

  1. Documented in the CHANGELOG as a breaking change
  2. Ideally gated on a minor version bump (or a major if the Pro gem follows semver strictly)

Inline comments posted on:

  • configBuilder.ts:351throw vs process.exit(1) inconsistency with other fatal errors in buildConfig
  • configuration.rb:243 — the defined?(Rails) guard is misleading (fail-closed when Rails isn't defined, wrong error message in that edge case)
  • configuration.rb:237validate_renderer_password_for_production is only reachable through setup_renderer_password when no password was pre-set; consider calling it unconditionally from setup_config_values

What's good

  • The fail-closed logic in TypeScript (runtimeEnvs.length > 0 && runtimeEnvs.every(...)) correctly handles the "neither env set" case
  • Checking both NODE_ENV and RAILS_ENV in the Node.js path is a good safeguard against mismatched environments
  • ExecJS is correctly exempted from the validation on the Ruby side
  • Test coverage is comprehensive and well-structured

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: d742d39edf

ℹ️ 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 packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
@justin808
Copy link
Copy Markdown
Member Author

Replying to #2829 (comment)

I reviewed the remaining points and am leaving them as-is for this PR:

  • The renderer_password early-return path is intentionally safe because a present password already satisfies the security requirement; moving validation to run unconditionally would be speculative future-proofing rather than a correctness fix.
  • The node_renderer? class-method round-trip is an existing implementation detail, but changing it here would be a style-only refactor with no behavior change.
  • The JS contract is already covered by the existing staging test plus the new RAILS_ENV cases, so I am not adding another equivalent non-dev/test case in this PR.
  • The devPassword docs example matches the existing local-development setup pattern in this repo, so I am leaving that example unchanged here.

The only remaining optional nit I may still address is the stale inline TypeScript comment on the password field.

@justin808
Copy link
Copy Markdown
Member Author

Replying to #2829 (comment)

On the node_renderer? note, I am leaving the current code as-is for this PR because switching that lookup to server_renderer == "NodeRenderer" would be a style-only refactor with no behavior change.

The stale password field comment is the only remaining optional nit I am still considering separately.

@justin808
Copy link
Copy Markdown
Member Author

Replying to #2829 (comment)

Addressed the remaining optional password comment nit in commit fc33e93c3.

Updated the inline TypeScript comment in packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts so it now matches the current behavior: optional in development/test, required for production-like environments.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

Good security improvement overall — enforcing a password for NodeRenderer in non-dev/test environments is the right call, and the test coverage is solid.

Breaking change

This will break any existing production/staging deployment using NodeRenderer without RENDERER_PASSWORD. The default renderer is ExecJS, so existing NodeRenderer users are the only affected group, but this is worth calling out explicitly in the changelog. A soft landing (warn in the current release, error in the next major) would reduce upgrade friction.

Documentation gap: coverage is broader than the table implies

The environment matrix shows only staging and production as required. But the code logic is anything-not-development-or-test — so custom environments like qa, preview, uat, sandbox, demo, etc. also require the password. The table should reflect this with an 'other' row or a note about all non-development/test environments.

Error handling inconsistency in Node.js

validatePasswordForProduction throws an Error, but all other validations in buildConfig call process.exit(1). Throwing is better for testability, but it means a misconfigured renderer crashes with an unhandled rejection rather than a clean logged exit. Consider wrapping the throw in a try/catch in buildConfig that logs and exits cleanly, consistent with the rest of the file.

Minor: missing Node.js edge-case test

The test suite covers NODE_ENV=development + RAILS_ENV=production (correctly throws) but not NODE_ENV=test + RAILS_ENV=production. Since test is an explicitly allowed value in the logic, that combination deserves a test confirming it still throws when RAILS_ENV is production.

Comment thread docs/pro/node-renderer.md Outdated
Comment thread packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 25, 2026

Review: Enforce secure renderer password defaults

Overall this is a solid security improvement with a well-designed fail-closed approach and comprehensive test coverage. A few issues worth addressing.

Logic correctness

The `validatePasswordForProduction` logic is correct — it requires all set environment variables to be safe (dev/test), not just one of them. This correctly rejects misconfigurations like `RAILS_ENV=production` + `NODE_ENV=development`. The Ruby side correctly uses `Rails.env` as authoritative without needing to cross-check `NODE_ENV`. Tests are thorough and the fail-closed behavior when neither env var is set is explicitly covered.

Issues

1. Dead code in `defaultConfig` — `replayServerAsyncOperationLogs`

`defaultConfig.replayServerAsyncOperationLogs` is computed once at module load time but is always overridden by the same expression inside `runtimeDefaultConfig` in `buildConfig()`. The `{ ...defaultConfig, replayServerAsyncOperationLogs: ... }` spread means the `defaultConfig` value is never used. Harmless but confusing.

2. `logSanitizedConfig` logs stale `defaultConfig.password`

`logSanitizedConfig` includes `'Default settings': defaultConfig`. Since `defaultConfig.password` is evaluated at module load time, a late-loaded `RENDERER_PASSWORD` (set after import but before `buildConfig()` is called) will appear as `undefined` in the defaults log even though the actual runtime default is correct. Minor observability inaccuracy.

3. Missing mixed-env test case

There is a test for `NODE_ENV=development` + `RAILS_ENV=production` (throws), but no test for the symmetric case: `NODE_ENV=staging` + `RAILS_ENV=development` (should also throw). Both directions of a mixed-env mismatch should be exercised to protect against future logic regressions.

4. Ruby `setup_renderer_password` early-return skips validation for pre-set passwords

When `renderer_password` is already present, `setup_renderer_password` returns at line 232 before `validate_renderer_password_for_production` is ever reached. In the singleton `configure` pattern this is fine — but a second `configure` call that changes `server_renderer` to `NodeRenderer` while a password from the first call is still live would skip validation entirely. Low risk given the singleton usage pattern, but the constraint is implicit rather than structurally enforced.

Comment thread packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts 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 (1)
packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts (1)

79-206: Comprehensive test coverage for password validation logic.

The test suite covers all critical scenarios:

  • Production/staging environments require password
  • Password via env or config bypasses validation
  • Development/test environments don't require password
  • Mixed env cases (RAILS_ENV vs NODE_ENV conflicts) fail closed
  • Neither env set fails closed
  • Late-loaded password works

Consider adding a symmetric test case for RAILS_ENV=development with NODE_ENV=production to fully exercise the mixed-env logic (should require password). This would verify the reverse of the existing test at line 138-148.

🧪 Optional: Add symmetric mixed-env test case
+    it('throws when NODE_ENV is production even if RAILS_ENV is development', () => {
+      process.env.NODE_ENV = 'production';
+      process.env.RAILS_ENV = 'development';
+      delete process.env.RENDERER_PASSWORD;
+      const processExit = mockProcessExit();
+
+      const { buildConfig } = loadConfigBuilderWithMockedLogger();
+
+      expect(() => buildConfig()).toThrow('process.exit: 1');
+      expect(processExit).toHaveBeenCalledWith(1);
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts` around
lines 79 - 206, Add a symmetric unit test to assert that when
RAILS_ENV='development' and NODE_ENV='production' without RENDERER_PASSWORD the
password validation still requires a password (i.e., buildConfig() should throw
and process.exit should be called with 1); locate the tests using
loadConfigBuilderWithMockedLogger() and buildConfig() in the existing "password
validation in production-like environments" describe block and mirror the
structure of the existing mixed-env test at the
RAILS_ENV=production/NODE_ENV=development case to set
process.env.RAILS_ENV='development', process.env.NODE_ENV='production', delete
process.env.RENDERER_PASSWORD, call mockProcessExit(), then expect buildConfig()
to throw and processExit toHaveBeenCalledWith(1).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts`:
- Around line 79-206: Add a symmetric unit test to assert that when
RAILS_ENV='development' and NODE_ENV='production' without RENDERER_PASSWORD the
password validation still requires a password (i.e., buildConfig() should throw
and process.exit should be called with 1); locate the tests using
loadConfigBuilderWithMockedLogger() and buildConfig() in the existing "password
validation in production-like environments" describe block and mirror the
structure of the existing mixed-env test at the
RAILS_ENV=production/NODE_ENV=development case to set
process.env.RAILS_ENV='development', process.env.NODE_ENV='production', delete
process.env.RENDERER_PASSWORD, call mockProcessExit(), then expect buildConfig()
to throw and processExit toHaveBeenCalledWith(1).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69e4ea1d-aefa-4f1c-9af6-67917d9b614f

📥 Commits

Reviewing files that changed from the base of the PR and between fc33e93 and 572b0ad.

📒 Files selected for processing (4)
  • docs/pro/node-renderer.md
  • packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts
  • packages/react-on-rails-pro-node-renderer/tests/configBuilder.test.ts
  • react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
✅ Files skipped from review due to trivial changes (1)
  • docs/pro/node-renderer.md

@justin808
Copy link
Copy Markdown
Member Author

Thanks for the thorough review. Addressed in a968c82:

Security — Ruby/Node fail-closed asymmetry: Fixed. validate_renderer_password_for_production now checks ENV["RAILS_ENV"] explicitly instead of Rails.env (which defaults to "development" when RAILS_ENV is unset). When RAILS_ENV is unset, Ruby now fails closed — matching the Node-side behavior. Added a test for the unset case and updated the error message environment matrix to document it.

Code quality — duplicate condition: Fixed. Extracted the hasOwnProperty+undefined check into a named explicitUndefinedPassword boolean before the spread.

Minor — node_renderer? singleton access: Declining. This works correctly since setup_config_values is only called on the singleton, and changing it to self.server_renderer would be a refactor unrelated to the password validation feature.

Minor — replayServerAsyncOperationLogs asymmetry: Declining. The password check reads both envs as a security measure (fail-closed), while replay-logs is a convenience default where NODE_ENV alone is the natural choice. Adding a comment explaining this asymmetry would be over-documenting an intentional design difference.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 28, 2026

Review: Enforce Secure Renderer Password Defaults

Solid security hardening. The fail-closed invariant (require both NODE_ENV and RAILS_ENV to be dev/test before allowing a missing password) is well-reasoned, consistently applied on both sides, and the test coverage is thorough. A few things to address before merge:

Issues

1. node_renderer? is a public method used only by private validation logic

node_renderer? (line 183 of configuration.rb) is defined before the private keyword, making it public API on Configuration. It's only called from the private validate_renderer_password_for_production. This is a low-severity style inconsistency — if it's not intentionally public, it should move below private.

2. explicitUndefinedPassword warning fires in dev/test (noisy false positive)

In buildConfig, the log.warn(...) for buildConfig({ password: undefined }) fires unconditionally regardless of environment. In development/test with no RENDERER_PASSWORD set, this will emit a warning for perfectly normal usage. The warning is only meaningful in production-like envs where it would soon be followed by a process.exit(1) anyway. Consider gating it on !runtimeEnvsAllowDevelopmentDefaults().

3. defaultReplayServerAsyncOperationLogs only checks NODE_ENV, unlike runtimeEnvsAllowDevelopmentDefaults which checks both

Password enforcement requires both NODE_ENV and RAILS_ENV to be dev/test (fail-closed). But defaultReplayServerAsyncOperationLogs defaults to verbose logging when only NODE_ENV=development, even if RAILS_ENV=production. This asymmetry means a developer running NODE_ENV=development RAILS_ENV=production will get verbose replay logs but also need a password. Not a security issue — just a surprising inconsistency that should be explained in a comment.

4. ENV.fetch("RENDERER_PASSWORD") in docs raises KeyError in local console sessions

The recommended snippet in docs/pro/node-renderer.md:

config.renderer_password = ENV.fetch("RENDERER_PASSWORD")

...will raise KeyError (not ReactOnRailsPro::Error) if RENDERER_PASSWORD is absent when running rails console locally without the env var set. The error message will be less actionable than the one carefully crafted in validate_renderer_password_for_production. A note or the ENV.fetch("RENDERER_PASSWORD", nil) pattern for dev initializers would reduce confusion.

5. Breaking change migration risk: Ruby doesn't auto-read RENDERER_PASSWORD

Already documented in the PR, but worth surfacing in the review: users who set RENDERER_PASSWORD in their environment but forget the Ruby initializer assignment will see the Node Renderer start (it reads the env var directly) but Rails will raise — or fail authentication on every request. The error message at line 271–272 of configuration.rb calls this out clearly, which is good.

Minor / Non-blocking

  • The double-guard in validate_renderer_password_for_production (return if renderer_password.present? at line 245, called "defense-in-depth") is fine but adds cognitive overhead given the only caller (setup_renderer_password) already short-circuits at line 234.
  • Log label 'Default settings at module load (env-backed values may lag current runtime)' is accurate and appreciated.

Overall

The core logic is correct. The PR improves security posture meaningfully and the error messages are actionable. The main things to fix before merge are the noisy explicitUndefinedPassword warning (Issue 2) and the undocumented defaultReplayServerAsyncOperationLogs asymmetry (Issue 3). Issues 1 and 4 are minor.

Comment thread docs/pro/node-renderer.md
… test

- Only emit the explicitUndefinedPassword warning in production-like
  environments where it is actionable; suppress it in dev/test where
  the missing password is harmless and the warning is noise.
- Add test confirming buildConfig() does not throw when only RAILS_ENV
  is development and NODE_ENV is unset.
- Add test confirming the warning is suppressed in development.

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

claude Bot commented Mar 28, 2026

Review: Enforce secure renderer password defaults for production-like envs

Overall this is a solid security improvement with good test coverage. A few issues worth addressing before merge.

CRITICAL: Ruby/Node environment check asymmetry

The Ruby side only checks RAILS_ENV, but the Node side checks both NODE_ENV and RAILS_ENV with fail-closed logic. Split-brain scenario: RAILS_ENV=development + NODE_ENV=production causes Node to refuse to start requiring a password, but Ruby does not raise and never configures one. The result is a Node renderer refusing all requests after boot while Rails happily serves traffic. This should either be explicitly documented or Ruby should mirror the Node-side both-envs check.

WARNING MESSAGE DEAD END

In buildConfig, when password: undefined is passed in production, the warning suggests passing an empty string to explicitly clear the password. But empty string also fails validation in production-like environments. There is no way to clear the password in production -- which is correct security behavior -- but the warning should say so directly rather than pointing to a path that also fails.

MINOR: node_renderer? re-enters configuration during validation

validate_renderer_password_for_production calls ReactOnRailsPro.configuration.server_renderer on an object still being configured inside configure. This works because server_renderer is set before validate runs, but a comment noting the ordering dependency would prevent future regressions.

NIT: defaultReplayServerAsyncOperationLogs only reads NODE_ENV

This is inconsistent with runtimeEnvsAllowDevelopmentDefaults which reads both envs. For a debug logging feature this is probably fine, but a brief comment explaining why only NODE_ENV matters here would prevent future confusion.

Comment thread react_on_rails_pro/lib/react_on_rails_pro/configuration.rb
Comment thread packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Outdated
The warning fired in production-like environments suggesting users pass
an empty string to clear the password, then immediately noted that empty
strings fail validation in production. Simplified to clearly state that
a password is always required and cannot be cleared.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@justin808 justin808 merged commit af78376 into main Mar 29, 2026
23 of 24 checks passed
@justin808 justin808 deleted the jg/2795-secure-renderer-pw branch March 29, 2026 04:16
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 29, 2026

Code Review

The PR correctly implements fail-closed security defaults for NodeRenderer. The core logic is sound: checking both NODE_ENV and RAILS_ENV, handling the explicit-undefined-password semantics, and mirroring behavior between Node and Ruby sides. Tests are comprehensive and cover the key cross-env combinations.

A few observations worth considering:

Diagnostic gap in envValuesUsed()

The RENDERER_PASSWORD entry uses a short-circuit expression:

RENDERER_PASSWORD: userConfig.password === undefined && env.RENDERER_PASSWORD && '<MASKED>',

If RENDERER_PASSWORD is set to an empty string in the environment, env.RENDERER_PASSWORD && '<MASKED>' evaluates to '' (falsy), so the diagnostic log shows false rather than indicating an empty-string password was attempted. The sanitizedSettings function handles this correctly via an explicit === '' check — envValuesUsed should be consistent. The validation itself catches empty strings correctly so this is a diagnostics-quality issue only.

Asymmetry between replayServerAsyncOperationLogs and password enforcement

defaultReplayServerAsyncOperationLogs() only consults NODE_ENV, while runtimeEnvsAllowDevelopmentDefaults() requires all present envs to be dev/test. With NODE_ENV=development plus RAILS_ENV=production, a password is required (production behavior) but replayServerAsyncOperationLogs defaults to true (development behavior). The test "defaults to true when NODE_ENV is development even if RAILS_ENV is production" documents this design choice explicitly — a brief inline comment noting this intentionally differs from password enforcement semantics would help future maintainers.

Missing test: empty-string RENDERER_PASSWORD env var

Tests cover password: undefined in buildConfig and empty-string explicit config assignments, but there is no test for process.env.RENDERER_PASSWORD = ''. In production this should fail since empty string is falsy in the if (aConfig.password) check, but it is a subtle edge case worth a regression test given that sanitizedSettings has a dedicated branch for the empty-string case.

Minor: runtimeEnvsAllowDevelopmentDefaults() called twice in buildConfig

Called once for the explicitUndefinedPassword warning and again inside validatePasswordForProduction. Both are cheap env-var reads so no perf concern, but capturing the result in a local variable would make the intent clearer.


Overall this is a well-crafted security feature. The fail-closed defaults, Node/Ruby behavioral mirroring, and detailed error messages are all solid. The diagnostic inconsistency in envValuesUsed and the missing empty-string env test are the main items worth addressing.

RENDERER_WORKERS_COUNT: !userConfig.workersCount && env.RENDERER_WORKERS_COUNT,
RENDERER_PASSWORD: !userConfig.password && env.RENDERER_PASSWORD && '<MASKED>',
// Explicit password overrides, including empty strings, intentionally suppress the env-derived value here.
RENDERER_PASSWORD: userConfig.password === undefined && env.RENDERER_PASSWORD && '<MASKED>',
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.

If RENDERER_PASSWORD='' (empty string) is set in the environment, env.RENDERER_PASSWORD && '<MASKED>' evaluates to '' (falsy), so this diagnostic entry logs as false rather than indicating an empty value was attempted. sanitizedSettings handles this correctly with an explicit === '' check. Consider applying the same pattern here:

RENDERER_PASSWORD: userConfig.password === undefined && (
  env.RENDERER_PASSWORD === '' ? '<EMPTY STRING>' : env.RENDERER_PASSWORD ? '<MASKED>' : false
),

return truthy(env.REPLAY_SERVER_ASYNC_OPERATION_LOGS);
}

return env.NODE_ENV?.toLowerCase() === 'development';
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.

This intentionally only checks NODE_ENV (not RAILS_ENV) so that replay logs follow the Node-side development experience regardless of RAILS_ENV. This differs from runtimeEnvsAllowDevelopmentDefaults() which requires all present envs to be dev/test for the fail-open password path. Worth a brief comment here noting the asymmetry is intentional, so future maintainers don't align it with the password enforcement logic.

justin808 added a commit that referenced this pull request Mar 29, 2026
…2829)

Adds password enforcement for the Node renderer and Rails Pro configuration
so that production-like environments (staging, production, qa, etc.) require
RENDERER_PASSWORD to be set, while development and test environments remain
passwordless for convenience.

Key changes:
- Node renderer: validatePasswordForProduction checks both NODE_ENV and RAILS_ENV,
  fails closed when neither is set, uses log.error + process.exit(1) for consistency
- Rails Pro: validate_renderer_password_for_production checks ENV["RAILS_ENV"] directly
  (not Rails.env) to avoid silent skip when RAILS_ENV is unset
- buildConfig refreshes runtime env-derived defaults on each call so late env
  initialization (e.g. dotenv) is picked up
- password:undefined in buildConfig preserves env/default rather than clearing
- Docs updated with environment matrix and breaking change noted in CHANGELOG

Breaking change: Missing RENDERER_PASSWORD now causes a boot error in
production-like environments. Existing production deployments that already
set RENDERER_PASSWORD are unaffected.
justin808 added a commit that referenced this pull request Mar 29, 2026
…e-repo

* origin/main:
  Improve create-react-on-rails-app fresh app onboarding (#2849)
  Add Docker deployment guide for Kamal, Kubernetes, and Control Plane (#2837)
  Reframe RSC migration docs around React on Rails patterns (#2661)
  Enforce secure renderer password defaults for production-like envs (#2829)
justin808 added a commit that referenced this pull request Apr 12, 2026
## Summary

Addresses all three follow-up items from PR #2829:

- **Ruby-side NODE_ENV checking**:
`validate_renderer_password_for_production` now checks both `RAILS_ENV`
and `NODE_ENV`, mirroring the Node-side
`runtimeEnvsAllowDevelopmentDefaults()`. Surfaces misconfigurations
(e.g. `NODE_ENV=production` + `RAILS_ENV=development`) at Rails boot
time instead of at Node request time.
- **Clarifying comment**: Added comment to
`defaultReplayServerAsyncOperationLogs()` explaining the intentional
asymmetry — it only checks `NODE_ENV` because async log replay is a JS
debugging concern, not a security boundary.
- **Unconditional validator call**: Moved
`validate_renderer_password_for_production` from inside
`setup_renderer_password` to `setup_config_values`, making enforcement
unconditional and resilient to future refactors of the password
resolution logic.

Closes #2887

## Test plan

- [x] All 51 Ruby configuration specs pass (including 4 new cross-env
tests)
- [x] All 31 Node renderer configBuilder tests pass
- [x] RuboCop clean
- [x] ESLint + Prettier clean
- [ ] CI passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Tightens production-like startup validation for the Node renderer
password, which can cause previously misconfigured deployments to fail
fast at Rails boot. Changes are localized to configuration/validation
paths with expanded spec coverage.
> 
> **Overview**
> Ensures `RENDERER_PASSWORD` enforcement is **fail-closed and
consistent across Ruby and Node** by validating against both `RAILS_ENV`
and `NODE_ENV`, including rejecting mixed-env setups (e.g.
`NODE_ENV=production` + `RAILS_ENV=development`).
> 
> Moves `validate_renderer_password_for_production` to run
unconditionally during Rails `setup_config_values`, updates the error
message docs/matrix accordingly, and expands Ruby specs to cover the new
cross-env scenarios.
> 
> Adds a clarifying comment in the Node `configBuilder` that
`defaultReplayServerAsyncOperationLogs()` intentionally keys only off
`NODE_ENV` (debugging behavior, not a security boundary).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5a01f45. 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

* **Bug Fixes**
* Strengthened production validation for the Node renderer to prevent
misconfiguration in mixed or production envs.

* **Documentation**
* Clarified default server operation logging behavior and updated
environment-related messaging.

* **Tests**
* Expanded test coverage for environment-variable combinations to ensure
consistent behavior across deployment and development scenarios.
<!-- 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

Addresses all three follow-up items from PR #2829:

- **Ruby-side NODE_ENV checking**:
`validate_renderer_password_for_production` now checks both `RAILS_ENV`
and `NODE_ENV`, mirroring the Node-side
`runtimeEnvsAllowDevelopmentDefaults()`. Surfaces misconfigurations
(e.g. `NODE_ENV=production` + `RAILS_ENV=development`) at Rails boot
time instead of at Node request time.
- **Clarifying comment**: Added comment to
`defaultReplayServerAsyncOperationLogs()` explaining the intentional
asymmetry — it only checks `NODE_ENV` because async log replay is a JS
debugging concern, not a security boundary.
- **Unconditional validator call**: Moved
`validate_renderer_password_for_production` from inside
`setup_renderer_password` to `setup_config_values`, making enforcement
unconditional and resilient to future refactors of the password
resolution logic.

Closes #2887

## Test plan

- [x] All 51 Ruby configuration specs pass (including 4 new cross-env
tests)
- [x] All 31 Node renderer configBuilder tests pass
- [x] RuboCop clean
- [x] ESLint + Prettier clean
- [ ] CI passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Tightens production-like startup validation for the Node renderer
password, which can cause previously misconfigured deployments to fail
fast at Rails boot. Changes are localized to configuration/validation
paths with expanded spec coverage.
> 
> **Overview**
> Ensures `RENDERER_PASSWORD` enforcement is **fail-closed and
consistent across Ruby and Node** by validating against both `RAILS_ENV`
and `NODE_ENV`, including rejecting mixed-env setups (e.g.
`NODE_ENV=production` + `RAILS_ENV=development`).
> 
> Moves `validate_renderer_password_for_production` to run
unconditionally during Rails `setup_config_values`, updates the error
message docs/matrix accordingly, and expands Ruby specs to cover the new
cross-env scenarios.
> 
> Adds a clarifying comment in the Node `configBuilder` that
`defaultReplayServerAsyncOperationLogs()` intentionally keys only off
`NODE_ENV` (debugging behavior, not a security boundary).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5a01f45. 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

* **Bug Fixes**
* Strengthened production validation for the Node renderer to prevent
misconfiguration in mixed or production envs.

* **Documentation**
* Clarified default server operation logging behavior and updated
environment-related messaging.

* **Tests**
* Expanded test coverage for environment-variable combinations to ensure
consistent behavior across deployment and development scenarios.
<!-- 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

Addresses all three follow-up items from PR #2829:

- **Ruby-side NODE_ENV checking**:
`validate_renderer_password_for_production` now checks both `RAILS_ENV`
and `NODE_ENV`, mirroring the Node-side
`runtimeEnvsAllowDevelopmentDefaults()`. Surfaces misconfigurations
(e.g. `NODE_ENV=production` + `RAILS_ENV=development`) at Rails boot
time instead of at Node request time.
- **Clarifying comment**: Added comment to
`defaultReplayServerAsyncOperationLogs()` explaining the intentional
asymmetry — it only checks `NODE_ENV` because async log replay is a JS
debugging concern, not a security boundary.
- **Unconditional validator call**: Moved
`validate_renderer_password_for_production` from inside
`setup_renderer_password` to `setup_config_values`, making enforcement
unconditional and resilient to future refactors of the password
resolution logic.

Closes #2887

## Test plan

- [x] All 51 Ruby configuration specs pass (including 4 new cross-env
tests)
- [x] All 31 Node renderer configBuilder tests pass
- [x] RuboCop clean
- [x] ESLint + Prettier clean
- [ ] CI passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Tightens production-like startup validation for the Node renderer
password, which can cause previously misconfigured deployments to fail
fast at Rails boot. Changes are localized to configuration/validation
paths with expanded spec coverage.
> 
> **Overview**
> Ensures `RENDERER_PASSWORD` enforcement is **fail-closed and
consistent across Ruby and Node** by validating against both `RAILS_ENV`
and `NODE_ENV`, including rejecting mixed-env setups (e.g.
`NODE_ENV=production` + `RAILS_ENV=development`).
> 
> Moves `validate_renderer_password_for_production` to run
unconditionally during Rails `setup_config_values`, updates the error
message docs/matrix accordingly, and expands Ruby specs to cover the new
cross-env scenarios.
> 
> Adds a clarifying comment in the Node `configBuilder` that
`defaultReplayServerAsyncOperationLogs()` intentionally keys only off
`NODE_ENV` (debugging behavior, not a security boundary).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5a01f45. 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

* **Bug Fixes**
* Strengthened production validation for the Node renderer to prevent
misconfiguration in mixed or production envs.

* **Documentation**
* Clarified default server operation logging behavior and updated
environment-related messaging.

* **Tests**
* Expanded test coverage for environment-variable combinations to ensure
consistent behavior across deployment and development scenarios.
<!-- 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.

Track D: enforce secure renderer password defaults for production-like envs

1 participant