- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 639
Unify release scripts and add strict version validation #1881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Unified release task for all packages (core + pro) with synchronized versioning - Supports semver bump types (patch/minor/major) and explicit versions - Publishes all packages: react-on-rails, react-on-rails-pro NPM packages, react_on_rails gem, react_on_rails_pro gem, and node-renderer package - Verdaccio mode now publishes all NPM packages for complete local testing - Removed release-it dependency in favor of direct yarn publish - react_on_rails_pro.gemspec now dynamically references ReactOnRails::VERSION - Uses gem bump for both core and pro version updates (no manual file writing) - Deprecated separate pro release script, redirects to unified task - Preserves dry-run, verdaccio testing, and skip-push options Examples: rake release[patch] # Bump patch version rake release[16.2.0] # Set explicit version rake release[patch,true] # Dry run rake release[16.2.0,false,verdaccio] # Test with Verdaccio 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Detects required Ruby version using 'bundle platform --ruby' - Automatically switches to required version before bundle install - Uses Open3.capture3 for safe command execution with proper error handling - Supports pre-release versions (rc, preview, dev, alpha, beta) - Requires exact version match (as enforced by Bundler) - Supports rvm, rbenv, and asdf version managers - Configurable via RUBY_VERSION_MANAGER environment variable - Falls back gracefully if version detection fails This prevents bundle install failures due to Ruby version mismatches during the release process, especially when releasing pro packages that require different Ruby versions than the system default. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed approach: run version switch and bundle install in single command - RVM: Use 'rvm VERSION do bundle install' to run in version context - rbenv: Use RBENV_VERSION environment variable - asdf: Chain commands with && to maintain shell context - Removed separate switch_ruby_version method (doesn't persist across subshells) - Simplified bundle_install_in to detect version and call appropriate method This ensures Ruby version switching actually takes effect for bundle install. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This reverts commit f55c485.
- Implement bundle_install_in() to detect and auto-switch Ruby versions - Use 'bundle platform --ruby' to detect required Ruby version from Gemfile - Support rvm, rbenv, and asdf version managers (via RUBY_VERSION_MANAGER env var) - Run detection in unbundled environment to avoid conflicts - Automatically switch Ruby version when needed during bundle install - Skip version switching when no Ruby version is specified in Gemfile - Handle pre-release versions (rc, alpha, beta) This enables the release script to work across directories with different Ruby version requirements (e.g., pro dummy app requires Ruby 3.3.7).
Use word boundary (\b) in regex to ensure we only match VERSION constant, not PROTOCOL_VERSION. This prevents accidentally updating the protocol version when bumping the package version.
…se files Documentation updates: - Update root releasing.md with all 5 packages and 4 parameters - Add comprehensive requirements section (NPM, RubyGems, GitHub Packages auth) - Add Ruby version management documentation - Add Testing with Verdaccio section - Update version synchronization to include all files - Clarify public vs private package publishing - Update pro CONTRIBUTING.md to reference root release task - Replace pro releasing.md with redirect to root documentation - Delete deprecated pro rakelib/release.rake - Delete deprecated pro script/release All release documentation now correctly reflects unified versioning and the single release script at repository root.
When using skip_push parameter, we should also skip git pull since the branch might not have upstream tracking (e.g., during testing).
This reverts commit 18ff99c.
This commit implements fail-fast validation for package.json configuration to prevent runtime errors and ensure proper package/gem compatibility. Changes: - Add new validation method that raises errors instead of logging warnings - Validate package.json file exists before checking versions - Detect conflicting package installations (both base and Pro) - Enforce exact version matching (no semver wildcards) - Validate Pro gem/package compatibility - Remove deprecated log_if_gem_and_node_package_versions_differ method Implementation details: - Created validate_version_and_package_compatibility! method with 4 validations: 1. validate_package_json_exists! - Ensures package.json is present 2. validate_package_gem_compatibility! - Checks Pro/base package conflicts 3. validate_exact_version! - Enforces exact versions (no ^, ~, >, <, *) 4. validate_version_match! - Ensures gem and package versions match - Added package detection methods (react_on_rails_package?, react_on_rails_pro_package?) - Applied DRY principle with shared package_installed? helper - Integrated validation into Rails engine initializer (config.after_initialize) - Added comprehensive test coverage (53 tests, all passing) - Included helpful error messages with package.json location Fixes #1876 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| WalkthroughUnifies release into a single, unified-version rake task for five packages; enforces strict boot-time gem↔npm compatibility via a new validator that raises on misconfiguration; adds package-manager-aware install/remove helpers and Ruby-version-aware bundle install; removes pro-specific release automation; updates docs, fixtures, and tests. Changes
 Sequence Diagram(s)sequenceDiagram
    participant Rails as Rails Init
    participant Engine as ReactOnRails::Engine
    participant VC as VersionChecker
    participant App as Application Boot
    Rails->>Engine: config.after_initialize
    Engine->>VC: VersionChecker.build.validate_version_and_package_compatibility!
    rect #F3F7FF
      VC->>VC: validate_package_json_exists!
      alt package.json missing
        VC-->>App: raise ReactOnRails::Error (install guidance)
      else
        VC->>VC: validate_package_gem_compatibility!
        alt conflict detected
          VC-->>App: raise ReactOnRails::Error (conflict remediation)
        else
          VC->>VC: validate_exact_version!
          alt semver wildcard found
            VC-->>App: raise ReactOnRails::Error (use exact version)
          else
            VC->>VC: validate_version_match!
            alt gem/npm mismatch
              VC-->>App: raise ReactOnRails::Error (sync versions)
            else
              VC-->>Engine: validation passed
            end
          end
        end
      end
    end
sequenceDiagram
    participant Dev as Developer
    participant Rake as Rake Release Task
    participant Helper as TaskHelpers
    participant RubyMgr as Ruby Manager
    participant Registry as NPM/GH/Gem Registries
    Dev->>Rake: rake release[version,dry_run,registry,skip_push]
    Rake->>Helper: bundle_install_in(dir)
    Helper->>Helper: detect_bundler_ruby_version(dir)
    alt ruby mismatch
      Helper->>RubyMgr: bundle_install_with_ruby_version(...)
    else
      Helper->>Rake: run bundle install normally
    end
    Rake->>Rake: update unified version across gems & npm packages
    Rake->>Registry: publish npm packages (npmjs / GH / Verdaccio)
    alt publishing public
      Rake->>Registry: publish RubyGems
    end
    Rake-->>Dev: release summary / dry-run output
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 
 Possibly related PRs
 Suggested reviewers
 Poem
 Pre-merge checks and finishing touches❌ Failed checks (1 warning)
 ✅ Passed checks (4 passed)
 ✨ Finishing touches🧪 Generate unit tests (beta)
 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
 🧰 Additional context used📓 Path-based instructions (1)**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}📄 CodeRabbit inference engine (CLAUDE.md) 
 Files: 
 🧠 Learnings (2)📚 Learning: 2025-10-23T17:22:01.064ZApplied to files: 
 📚 Learning: 2025-02-18T13:08:01.477ZApplied to files: 
 ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
 🔇 Additional comments (4)
 Comment  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (2)
rakelib/task_helpers.rb (1)
97-101: Optional: tolerate Ruby patchlevel suffixesBundler may output
ruby 3.2.1p20. Current regex captures3.2.1, which works for equality againstRUBY_VERSION; if you want to preserve prerelease and ignore optionalp\d+, consider:- match = output.strip.match(/ruby\s+([\d.]+(?:-[a-zA-Z0-9.]+)?)/) + match = output.strip.match(/ruby\s+([\d.]+)(?:p\d+)?(?:-([a-zA-Z0-9.]+))?/) + version = match && [match[1], match[2]].compact.join("-") + versiondocs/contributor-info/releasing.md (1)
3-211: Comprehensive documentation of the unified release process.The documentation clearly explains the 5-package unified release workflow, including:
- Command usage with practical examples
- Public vs private package distinctions
- Authentication requirements for multiple registries
- Verdaccio testing workflow
This aligns well with the PR objectives of simplifying the release process.
As per coding guidelines, consider adding language specifiers to the fenced code blocks at lines 153 and 169 to address the markdownlint warnings:
For line 153 (
.npmrccontent):- ``` + ```ini //npm.pkg.github.com/:_authToken=<TOKEN>For line 169 (
.gem/credentialscontent):- ``` + ```yaml :github: Bearer <GITHUB_TOKEN>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
- react_on_rails_pro/spec/dummy/Gemfile.lockis excluded by- !**/*.lock
- react_on_rails_pro/yarn.lockis excluded by- !**/yarn.lock,- !**/*.lock
📒 Files selected for processing (15)
- docs/contributor-info/releasing.md(3 hunks)
- lib/react_on_rails/engine.rb(1 hunks)
- lib/react_on_rails/version_checker.rb(4 hunks)
- rakelib/release.rake(9 hunks)
- rakelib/task_helpers.rb(2 hunks)
- react_on_rails_pro/CONTRIBUTING.md(1 hunks)
- react_on_rails_pro/docs/contributors-info/releasing.md(1 hunks)
- react_on_rails_pro/package.json(0 hunks)
- react_on_rails_pro/rakelib/release.rake(0 hunks)
- react_on_rails_pro/react_on_rails_pro.gemspec(2 hunks)
- react_on_rails_pro/script/release(0 hunks)
- spec/react_on_rails/fixtures/both_packages.json(1 hunks)
- spec/react_on_rails/fixtures/pro_package.json(1 hunks)
- spec/react_on_rails/fixtures/pro_semver_caret_package.json(1 hunks)
- spec/react_on_rails/version_checker_spec.rb(4 hunks)
💤 Files with no reviewable changes (3)
- react_on_rails_pro/package.json
- react_on_rails_pro/script/release
- react_on_rails_pro/rakelib/release.rake
🧰 Additional context used
📓 Path-based instructions (2)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- lib/react_on_rails/engine.rb
- rakelib/release.rake
- rakelib/task_helpers.rb
- react_on_rails_pro/react_on_rails_pro.gemspec
- spec/react_on_rails/version_checker_spec.rb
- lib/react_on_rails/version_checker.rb
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
- spec/react_on_rails/fixtures/both_packages.json
- spec/react_on_rails/fixtures/pro_package.json
- docs/contributor-info/releasing.md
- react_on_rails_pro/CONTRIBUTING.md
- react_on_rails_pro/docs/contributors-info/releasing.md
- spec/react_on_rails/fixtures/pro_semver_caret_package.json
🧠 Learnings (3)
📚 Learning: 2025-10-23T17:22:01.064Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Applied to files:
- lib/react_on_rails/engine.rb
- react_on_rails_pro/react_on_rails_pro.gemspec
- spec/react_on_rails/version_checker_spec.rb
- lib/react_on_rails/version_checker.rb
📚 Learning: 2025-02-12T16:38:06.537Z
Learnt from: Romex91
PR: shakacode/react_on_rails#1697
File: package-scripts.yml:28-28
Timestamp: 2025-02-12T16:38:06.537Z
Learning: The file `node_package/lib/ReactOnRails.full.js` is autogenerated during the build process and should not be present in the repository.
Applied to files:
- spec/react_on_rails/fixtures/pro_package.json
- react_on_rails_pro/react_on_rails_pro.gemspec
📚 Learning: 2025-09-15T21:24:48.207Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1781
File: node_package/src/ClientSideRenderer.ts:82-95
Timestamp: 2025-09-15T21:24:48.207Z
Learning: In React on Rails, the force_load feature includes both explicit `data-force-load="true"` usage and the ability to hydrate components during the page loading state (`document.readyState === 'loading'`). Both capabilities require a Pro license, so the condition `!railsContext.rorPro && (isComponentForceLoaded || document.readyState === 'loading')` correctly gates both scenarios.
Applied to files:
- react_on_rails_pro/react_on_rails_pro.gemspec
🧬 Code graph analysis (3)
lib/react_on_rails/engine.rb (1)
lib/react_on_rails/version_checker.rb (3)
build(12-14)
build(173-175)
validate_version_and_package_compatibility!(28-33)
spec/react_on_rails/version_checker_spec.rb (2)
spec/react_on_rails/support/version_test_helpers.rb (1)
stub_gem_version(3-5)lib/react_on_rails/version_checker.rb (8)
validate_version_and_package_compatibility!(28-33)
build(12-14)
build(173-175)
raw(185-207)
react_on_rails_package?(209-211)
react_on_rails_pro_package?(213-215)
package_name(217-221)
semver_wildcard?(223-228)
lib/react_on_rails/version_checker.rb (1)
lib/react_on_rails/utils.rb (1)
react_on_rails_pro?(215-223)
🪛 GitHub Actions: Lint JS and Ruby
rakelib/task_helpers.rb
[error] 91-91: RuboCop: Style/NumericPredicate - Use exit_status.zero? instead of exit_status == 0. (autocorrectable). Command failed: bundle exec rubocop
🪛 markdownlint-cli2 (0.18.1)
docs/contributor-info/releasing.md
153-153: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
169-169: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
react_on_rails_pro/CONTRIBUTING.md
304-304: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
309-309: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: claude-review
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: markdown-link-check
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22)
- GitHub Check: lint-js-and-ruby
🔇 Additional comments (18)
react_on_rails_pro/react_on_rails_pro.gemspec (1)
41-41: Implement exact version pinning for unified versioning.Replacing the hardcoded version constraint with
ReactOnRails::VERSIONenforces an exact version match between the core package and Pro gem, eliminating version mismatch risks. This is a key requirement for the unified release workflow described in the PR objectives.spec/react_on_rails/fixtures/pro_semver_caret_package.json (1)
1-10: Fixture correctly exercises caret-range violationLooks good for asserting the “no semver ranges” rule against react-on-rails-pro.
Please confirm VersionChecker only enforces exact versions for our packages (react-on-rails, react-on-rails-pro) and not all deps/devDeps. If broader, add/adjust tests accordingly.
spec/react_on_rails/fixtures/pro_package.json (1)
1-10: Happy-path fixture LGTMExact pin for react-on-rails-pro with permissive versions elsewhere makes sense for pass-case.
react_on_rails_pro/CONTRIBUTING.md (1)
316-328: Release commands align with rake signatureCommands match task args: version, dry_run, registry, skip_push. No action needed.
rakelib/release.rake (4)
131-153: Version propagation to all package.json files looks correctRoot, workspace packages, and pro node-renderer updated; pro depends on core with exact version. Good.
198-208: Workspace publish flow LGTMPublishing core and pro via Yarn workspaces with
--new-versionaligns with unified versioning.
82-90: Review comment is based on incorrect assumptions about the repository structure.The verification output shows only 2 gemspec files exist (root and react_on_rails_pro directory). The
findcommands with-mindepth 2and-mindepth 3are correctly scoped—they don't match either existing file and won't delete anything. The code is working as intended; there is no safety risk.Likely an incorrect or invalid review comment.
253-277: Review suggestion assumes unified versioning, but codebase uses split pro versioningThe suggested verification script would fail in the current state. The pro package maintains independent versions (4.0.0) while main uses 16.1.1, with partial misalignment between pro Ruby gem and NPM packages.
Before implementing the sync check suggested, clarify whether:
- Pro should track main versions (unify to 16.1.1), or
- Pro maintains intentional independent versioning (current state needs alignment fixes within pro track itself)
The current dry-run message lists pro version.rb as updateable but uses single version variables, suggesting potential release logic gaps for dual-versioning scenarios.
lib/react_on_rails/version_checker.rb (5)
20-33: LGTM! Well-structured validation orchestration.The new validation flow clearly separates concerns into four distinct checks, each with targeted error messages. The fail-fast approach aligns with the project's goal of early error detection.
37-55: Clear and actionable error message for missing package.json.The error message provides excellent guidance with expected location, explanation, and fix commands. Using
gem_versionin the fix ensures version consistency.
57-113: Comprehensive package/gem compatibility validation with clear remediation steps.The three misconfig scenarios (both packages, pro gem + base package, pro package without gem) are handled with detailed, actionable error messages. The use of
package_json_locationhelper maintains DRY principles.
185-207: LGTM! Pro package correctly takes precedence.The precedence logic (checking
react-on-rails-probeforereact-on-rails) aligns with the unified versioning strategy and prevents ambiguity when both packages are present.
209-221: Clean public API for package detection.The new helper methods (
react_on_rails_package?,react_on_rails_pro_package?,package_name) provide a clear interface for determining which package is installed, improving readability throughout the validation logic.lib/react_on_rails/engine.rb (1)
7-15: LGTM! Well-placed fail-fast validation.The
after_initializetiming ensures Rails is fully loaded before validation runs, while still failing fast enough to prevent runtime issues. The info-level logging provides good visibility without being verbose.spec/react_on_rails/fixtures/both_packages.json (1)
1-11: LGTM! Fixture correctly simulates conflicting package installation.This fixture appropriately tests the scenario where both
react-on-railsandreact-on-rails-proare installed, which should trigger the validation error invalidate_package_gem_compatibility!.react_on_rails_pro/docs/contributors-info/releasing.md (1)
1-40: LGTM! Clear redirection to unified release documentation.The documentation appropriately redirects users to the centralized release process while providing quick-reference commands. The prominent outdated notice prevents confusion.
spec/react_on_rails/version_checker_spec.rb (2)
16-207: LGTM! Comprehensive test coverage for validation scenarios.The test suite thoroughly covers all validation paths:
- Package/gem compatibility checks (both packages, mismatches)
- Version validation (exact, wildcard, local paths)
- Missing package.json handling
- Pro gem and package combinations
All tests use proper mocking and clear expectations.
394-496: Excellent coverage of package detection logic.The Pro package detection tests verify:
- Base-only, Pro-only, and both-packages scenarios
- Precedence rules (Pro takes priority)
- Semver wildcard detection
- Default behavior when no packages found
Adds validation to ensure the React on Rails Pro gem version matches
the node renderer package version for best compatibility.
**Changes:**
- **Ruby side** (`lib/react_on_rails_pro/utils.rb`):
  - Add `railsEnv` to `common_form_data` method to send Rails environment
    to the node renderer
- **Node renderer** (`packages/node-renderer/src/worker/checkProtocolVersionHandler.ts`):
  - Add gem version validation logic with environment-aware behavior
  - Create `normalizeVersion()` function to handle version format differences:
    - Ruby gem format: `4.0.0.rc.1` → NPM format: `4.0.0-rc.1`
    - Case-insensitive comparison (e.g., `4.0.0-RC.1` == `4.0.0-rc.1`)
    - Whitespace trimming
  - **Development**: Throw 412 error when versions don't match
  - **Production**: Log warning but allow request to proceed
- **Tests** (`packages/node-renderer/tests/worker.test.ts`):
  - Update 11 existing tests to include `railsEnv` field
  - Add 6 new comprehensive tests for gem version validation:
    - Matching versions test
    - Development environment mismatch rejection
    - Production environment mismatch allowance
    - Version normalization tests (dot format, case-insensitive, whitespace)
**Edge cases handled:**
- ✅ Prerelease format differences (4.0.0.rc.1 vs 4.0.0-rc.1)
- ✅ Case sensitivity (4.0.0-RC.1 vs 4.0.0-rc.1)
- ✅ Whitespace trimming
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
    | Pull Request Review: Unify release scripts and add strict version validationSummaryThis is an excellent PR that significantly improves the React on Rails release process and runtime validation. The changes are well-structured, thoroughly tested, and address real pain points in version management. 🎯 Strengths1. Unified Release Process ✅
 2. Strict Version Validation ✅
 3. Test Coverage ✅
 4. Code Quality ✅
 🔍 Code Quality ObservationsVersion Checker (lib/react_on_rails/version_checker.rb)Excellent: 
 Minor suggestions: 
 Release Script (rakelib/release.rake)Excellent: 
 Observations: 
 🔒 Security ✅
 ⚡ Performance ✅
 🐛 Potential IssuesCritical: None ✅ Minor: 
 📚 Documentation Quality ✅Outstanding: 
 🧪 Testing RecommendationsConsider adding: 
 🎨 Best Practices ✅Follows CLAUDE.md requirements and Rails/Ruby conventions perfectly. 🚀 Migration ImpactPotentially breaking for misconfigured setups, but: 
 Recommendation: Consider temporary ENV flag (REACT_ON_RAILS_SKIP_VERSION_CHECK) for smoother migration. 📊 Overall Assessment
 ✅ Recommendation: APPROVE with minor suggestionsThis PR is a significant quality improvement. The implementation is clean, well-tested, and thoroughly documented. Optional improvements:
 Before merge:
 Great work! This will make releases much more reliable and user configurations much safer. Review generated by Claude Code | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
react_on_rails_pro/lib/react_on_rails_pro/utils.rb (1)
175-182: Avoid sending nulls; omit nil-valued fieldsWhen RSC support is disabled, dependencyBundleTimestamps is nil. Prefer omitting nil entries to keep the payload clean and future‑proof.
Apply this minimal change:
{ "gemVersion" => ReactOnRailsPro::VERSION, "protocolVersion" => ReactOnRailsPro::PROTOCOL_VERSION, "password" => ReactOnRailsPro.configuration.renderer_password, - "dependencyBundleTimestamps" => dependencies, - "railsEnv" => Rails.env.to_s - } + "dependencyBundleTimestamps" => dependencies, + "railsEnv" => Rails.env.to_s + }.compactreact_on_rails_pro/packages/node-renderer/tests/worker.test.ts (1)
332-470: Great coverage; consider two small additions
- Add a test for missing railsEnv to confirm behavior defaults (dev should 412, prod should allow with warning).
- Add a test for prerelease without dot (e.g., 4.0.0.rc1) to lock down normalization.
Would you like me to draft these two Jest cases?
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (3)
7-10: Don’t default NODE_ENV to 'production'Defaulting to 'production' can silently allow version mismatches when railsEnv is absent. Let it be undefined and rely on explicit railsEnv or the actual environment.
-const NODE_ENV = process.env.NODE_ENV || 'production'; +const NODE_ENV = process.env.NODE_ENV;
11-29: Broaden prerelease normalization (optional)Your normalization misses cases like 4.0.0.rc1. A small regex tweak keeps scope tight while covering this common variant.
- // Replace the first dot after major.minor.patch with a hyphen to handle Ruby gem format - // Examples: "4.0.0.rc.1" -> "4.0.0-rc.1", "4.0.0.alpha.1" -> "4.0.0-alpha.1" - normalized = normalized.replace(/^(\d+\.\d+\.\d+)\.([a-z]+)/, '$1-$2'); + // Handle Ruby gem prerelease forms: + // "4.0.0.rc.1" -> "4.0.0-rc.1", "4.0.0.alpha.1" -> "4.0.0-alpha.1", "4.0.0.rc1" -> "4.0.0-rc.1" + normalized = normalized + .replace(/^(\d+\.\d+\.\d+)\.([a-z]+)\.(\d+)$/, '$1-$2.$3') + .replace(/^(\d+\.\d+\.\d+)\.([a-z]+)(\d+)$/, '$1-$2.$3');Consider adding a unit test for "rc1".
54-81: Env-aware mismatch handling looks correct; minor DX polishConsider appending the evaluated environment (railsEnv/NODE_ENV) to the message to aid debugging when behavior differs between dev and prod.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
- react_on_rails_pro/spec/dummy/Gemfile.lockis excluded by- !**/*.lock
📒 Files selected for processing (5)
- react_on_rails_pro/lib/react_on_rails_pro/utils.rb(1 hunks)
- react_on_rails_pro/lib/react_on_rails_pro/version.rb(1 hunks)
- react_on_rails_pro/package.json(1 hunks)
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts(2 hunks)
- react_on_rails_pro/packages/node-renderer/tests/worker.test.ts(10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- react_on_rails_pro/package.json
🧰 Additional context used
📓 Path-based instructions (3)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- react_on_rails_pro/lib/react_on_rails_pro/version.rb
- react_on_rails_pro/lib/react_on_rails_pro/utils.rb
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
- react_on_rails_pro/packages/node-renderer/tests/worker.test.ts
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JS/TS code (lint via rake lint or yarn lint)
Files:
- react_on_rails_pro/packages/node-renderer/tests/worker.test.ts
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
🧬 Code graph analysis (1)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (1)
react_on_rails_pro/packages/node-renderer/src/worker/types.ts (1)
FastifyRequest(11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: claude-review
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: markdown-link-check
- GitHub Check: lint-js-and-ruby
🔇 Additional comments (3)
react_on_rails_pro/lib/react_on_rails_pro/version.rb (1)
4-4: Version update verified across all packages.All six version locations are correctly synchronized to 16.1.1, confirming successful implementation of the unified versioning strategy. PROTOCOL_VERSION remains appropriately unchanged at 2.0.0.
react_on_rails_pro/lib/react_on_rails_pro/utils.rb (1)
179-181: railsEnv addition looks goodIncluding Rails.env in the payload matches the new protocol and tests. No issues.
react_on_rails_pro/packages/node-renderer/tests/worker.test.ts (1)
29-31: railsEnv plumbed through tests coherentlyThe tests now include railsEnv where protocol/gem checks apply. This aligns with handler logic.
Also applies to: 47-55, 75-85, 118-122, 145-149, 172-176, 200-203, 291-299, 315-323
Optimize version validation by caching comparison results to avoid repeated normalization on every rendering request. **Changes:** - Add `versionCache` Map to store version comparison results - Cache is checked before performing normalization (key: gemVersion) - Normalization only runs on cache miss - Production logging is now conditional on cache miss (logs only once) **Performance benefits:** - Eliminates repeated string operations (trim, toLowerCase, regex) on every request - Prevents log spam in production (warning logged only once per unique version) - Minimal memory overhead (few cached version strings) **Cache behavior:** - Cache key: gemVersion string - Cache value: boolean (true if versions match, false if mismatch) - If key exists, comparison result is used directly - Production warning only logs when version is first encountered (justCached flag) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| Pull Request Review: Unified Release Scripts and Strict Version ValidationOverall AssessmentThis is an excellent and comprehensive PR that significantly improves the React on Rails release process and runtime validation. The changes are well-architected, thoroughly tested, and will prevent many common configuration issues. Recommendation: ✅ Approve with minor suggestions Part 1: Unified Release Script - EXCELLENT ⭐Strengths
 Code Quality Highlights
 Suggestions
 Part 2: Strict Version Validation - EXCELLENT ⭐Strengths
 Suggestions
 Part 3: Node Renderer Version Validation - VERY GOOD ⭐Strengths
 Suggestions
 Part 4: Ruby Version Auto-Switching - VERY GOOD ⭐Strengths
 Suggestions
 Summary ScoresSecurity: ✅ No Issues Final RecommendationsMust Address
 Should Consider
 Nice to Have
 SummaryThis PR represents a significant improvement to React on Rails: ✅ Eliminates version mismatches at multiple levels Code quality is high, architecture is sound, implementation is thorough. Great work! 🎉 Review by Claude Code per CLAUDE.md guidelines | 
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JS/TS code (lint via rake lint or yarn lint)
Files:
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
🧬 Code graph analysis (1)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (2)
react_on_rails_pro/spec/dummy/client/node-renderer.js (1)
process(5-5)react_on_rails_pro/packages/node-renderer/src/worker/types.ts (1)
FastifyRequest(11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22)
- GitHub Check: claude-review
- GitHub Check: markdown-link-check
- GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: lint-js-and-ruby
- GitHub Check: build-dummy-app-webpack-test-bundles
🔇 Additional comments (5)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (5)
7-8: LGTM!The log import is correctly added to support the production warning behavior introduced later in the file.
9-14: LGTM!The version cache is a good optimization that prevents repeated normalization and avoids log spam for duplicate version checks. In typical deployments, the cache will only contain 1-2 entries, so unbounded growth is not a practical concern.
16-34: LGTM!The normalization function correctly handles the Ruby gem prerelease format conversion (e.g.,
4.0.0.rc.1→4.0.0-rc.1). The regex is well-targeted for the documented use case, and the lowercase/trim operations ensure robust comparison.
36-40: LGTM!The RequestBody interface provides clear type safety for the destructured request body fields.
59-75: LGTM with the production detection caveat!The gem version validation logic is well-implemented:
- The caching strategy correctly avoids repeated normalization and prevents log spam by using the
justCachedflag to log warnings only once per unique gem version.- Error messages are clear and actionable, guiding users to update either the gem or the node renderer package.
- The environment-aware behavior (warning in production vs. 412 error in development) provides a good balance between strict validation during development and operational flexibility in production.
Assuming the production detection logic at line 76 is corrected, this implementation achieves the PR objective of strict version validation with appropriate environment-sensitive handling.
Also applies to: 77-100
        
          
                react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
          
            Show resolved
            Hide resolved
        
      | 📋 Best Practices and Final VerdictBest Practices Assessment✅ Follows repository conventions (per CLAUDE.md): 
 ✅ Ruby best practices: 
 ✅ TypeScript best practices: 
 RecommendationsMust Fix: None - code is production-ready as-is. Should Consider: 
 Nice to Have: 
 Code Metrics
 Net negative lines is excellent - code is getting simpler despite adding features! ✨ Final VerdictThis PR is exemplary work. It demonstrates: 
 The unified versioning approach significantly improves maintainability, the strict validation prevents user errors, and the node renderer validation adds runtime safety. Approved pending linting/CI checks. 🚀 cc: @AbanoubGhadban Review performed by Claude Code following CLAUDE.md conventions | 
| # Install and Release | ||
|  | ||
| We're releasing this as a combined Ruby gem plus two NPM packages. We keep the version numbers in sync across all packages. | ||
| We're releasing this as a unified release with 5 packages total. We keep the version numbers in sync across all packages using unified versioning. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like "using unified versioning" means something in addition to "We keep the version numbers in sync across all packages" but if so it isn't clear what.
Detect package manager (yarn/pnpm/bun/npm) and show correct commands in error messages instead of hardcoding yarn commands. Detection strategy: 1. Check packageManager field in package.json (Node.js Corepack standard) 2. Fall back to lock file detection (yarn.lock, pnpm-lock.yaml, etc.) 3. Default to yarn for backward compatibility Changes: - Add Utils.detect_package_manager method - Add Utils.package_manager_install_exact_command method - Add Utils.package_manager_remove_command method - Update all 6 error messages in VersionChecker to use dynamic commands - Add 22 comprehensive specs with 100% coverage Supported package managers: - yarn: yarn add package@1.0.0 --exact - pnpm: pnpm add package@1.0.0 --save-exact - bun: bun add package@1.0.0 --exact - npm: npm install package@1.0.0 --save-exact 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
lib/react_on_rails/version_checker.rb (1)
60-124: Missing validation: base gem without npm package installation.The method validates Pro gem/package compatibility but doesn't ensure the base gem has a corresponding npm package installed. If
has_base_packageandhas_pro_packageare both false withis_pro_gem = false(base gem scenario), all three conditional blocks skip and validation passes.Impact: Users with the base gem but missing the
react-on-railsnpm package will pass validation, causing runtime failures later.Add validation after line 63:
is_pro_gem = ReactOnRails::Utils.react_on_rails_pro? + +# Error: No package installed +if !has_base_package && !has_pro_package + base_install_cmd = ReactOnRails::Utils.package_manager_install_exact_command("react-on-rails", gem_version) + pro_install_cmd = ReactOnRails::Utils.package_manager_install_exact_command("react-on-rails-pro", gem_version) + + raise ReactOnRails::Error, <<~MSG.strip + **ERROR** ReactOnRails: No React on Rails package found in package.json dependencies. + + React on Rails requires either 'react-on-rails' or 'react-on-rails-pro' package installed. + + Fix: + Run: #{base_install_cmd} + + Or if using React on Rails Pro: + Run: #{pro_install_cmd} + + #{package_json_location} + MSG +end
Note: A past review comment suggested using an inline guard clause style for line 103. The current
return unlesspattern is acceptable, but you may consider the alternative for consistency with error-first patterns.
🧹 Nitpick comments (2)
lib/react_on_rails/utils.rb (1)
286-319: Consider consolidating duplicate package manager detection logic.The file
lib/generators/react_on_rails/generator_messages.rb(lines 182-192) has a similardetect_package_managermethod that only checks lock files without checking the packageManager field. This creates maintenance overhead and potential inconsistency.Consider refactoring generator_messages.rb to use
ReactOnRails::Utils.detect_package_managerinstead:# In lib/generators/react_on_rails/generator_messages.rb def detect_package_manager ReactOnRails::Utils.detect_package_manager.to_s endThis ensures consistent detection logic across the codebase.
lib/react_on_rails/version_checker.rb (1)
181-183: Optional: Simplify namespace reference.Since this method is already inside the
VersionCheckermodule, you can simplify line 182.def package_json_location - "Package.json location: #{VersionChecker::NodePackageVersion.package_json_path}" + "Package.json location: #{NodePackageVersion.package_json_path}" end
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
- lib/react_on_rails/utils.rb(1 hunks)
- lib/react_on_rails/version_checker.rb(4 hunks)
- spec/react_on_rails/utils_spec.rb(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- lib/react_on_rails/utils.rb
- spec/react_on_rails/utils_spec.rb
- lib/react_on_rails/version_checker.rb
🧠 Learnings (2)
📚 Learning: 2025-02-18T13:08:01.477Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
1. Pro version check in `run_stream_inside_fiber`
2. RSC support check during pack generation via `ReactOnRailsPro.configuration.enable_rsc_support`
3. RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.
Applied to files:
- spec/react_on_rails/utils_spec.rb
📚 Learning: 2025-10-23T17:22:01.064Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Applied to files:
- lib/react_on_rails/version_checker.rb
🧬 Code graph analysis (3)
lib/react_on_rails/utils.rb (3)
lib/generators/react_on_rails/generator_messages.rb (1)
detect_package_manager(183-193)lib/react_on_rails/version_checker.rb (1)
package_json_path(192-194)lib/react_on_rails/configuration.rb (1)
configuration(14-57)
spec/react_on_rails/utils_spec.rb (2)
lib/react_on_rails/version_checker.rb (1)
package_json_path(192-194)lib/react_on_rails/utils.rb (3)
detect_package_manager(291-294)
package_manager_install_exact_command(327-340)
package_manager_remove_command(346-359)
lib/react_on_rails/version_checker.rb (1)
lib/react_on_rails/utils.rb (3)
package_manager_install_exact_command(327-340)
react_on_rails_pro?(215-223)
package_manager_remove_command(346-359)
🪛 ast-grep (0.39.6)
spec/react_on_rails/utils_spec.rb
[warning] 704-704: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 704-704: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 720-720: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 720-720: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 728-728: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 728-728: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 729-729: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 729-729: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 737-737: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 737-737: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 738-738: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 738-738: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 739-739: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 739-739: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 747-747: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 747-747: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 748-748: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 748-748: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 749-749: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 749-749: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 750-750: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "package-lock.json")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 750-750: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "package-lock.json"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 758-758: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 758-758: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 759-759: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 759-759: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 760-760: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 760-760: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 761-761: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "package-lock.json")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 761-761: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "package-lock.json"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 775-775: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 775-775: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 788-788: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 788-788: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 789-789: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(true)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
[warning] 789-789: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml"))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html
(hardcoded-secret-rsa-passphrase-ruby)
🪛 GitHub Actions: Lint JS and Ruby
spec/react_on_rails/utils_spec.rb
[error] 671-671: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 670. (autocorrectable)
[error] 679-679: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 678. (autocorrectable)
[error] 687-687: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 686. (autocorrectable)
[error] 695-695: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 694. (autocorrectable)
[error] 704-704: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 703. (autocorrectable)
[error] 715-715: RuboCop: Layout/MultilineMethodCallIndentation: Align .and_return with .with on line 714. (autocorrectable)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: claude-review
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: lint-js-and-ruby
- GitHub Check: markdown-link-check
- GitHub Check: build-dummy-app-webpack-test-bundles
🔇 Additional comments (11)
spec/react_on_rails/utils_spec.rb (2)
658-795: Excellent test coverage for package manager detection.The test suite comprehensively covers all detection scenarios:
- packageManager field parsing for all supported managers (yarn, pnpm, bun, npm)
- Fallback to lock file detection
- Edge cases (parsing failures, missing package.json, unknown managers)
- Proper mocking strategy with
and_call_originalto avoid interference
797-897: Command generation tests look solid.Tests verify correct command syntax for install and remove operations across all package managers, including proper handling of unknown managers with sensible yarn defaults.
lib/react_on_rails/utils.rb (2)
286-319: Well-designed package manager detection with proper fallbacks.The implementation follows best practices:
- Prioritizes Corepack standard (packageManager field in package.json)
- Falls back to lock file detection
- Sensible yarn default when all detection fails
- Proper error handling for JSON parsing failures
327-359: Command syntax verified correct for all package managers.The install and remove command generation properly handles manager-specific syntax:
- Exact version flags:
--exact(yarn, bun),--save-exact(pnpm, npm)- Remove commands:
remove(yarn, pnpm, bun),uninstall(npm)lib/react_on_rails/version_checker.rb (7)
20-33: LGTM! Clear validation orchestration.The fail-fast validation sequence is well-structured and follows a logical order: existence → compatibility → exactness → version match.
37-58: LGTM! Clear error messaging with actionable remediation.The validation properly checks file existence and provides user-friendly install commands for both base and Pro packages.
126-148: LGTM! Exact version enforcement with clear remediation.The early return (line 127) relies on prior validations to ensure
rawis not nil when a package should be present. This reinforces the importance of comprehensive checks invalidate_package_gem_compatibility!.
150-171: LGTM! Version matching validation with actionable fix.The exact version comparison ensures gem and npm package versions are synchronized, with clear commands to resolve mismatches.
224-236: LGTM! Clean package detection helpers.The helper methods provide clear abstractions with appropriate Pro-first precedence in
package_name. These support the validation logic effectively.
265-270: LGTM! Safe package detection implementation.The method correctly handles missing files and uses safe navigation (
dig) to check dependencies, preventing errors if the structure is unexpected.
276-278: LGTM! Efficient JSON parsing with memoization.The two-level memoization pattern (file contents → parsed JSON) ensures efficient access without redundant I/O or parsing.
- Fix RuboCop indentation violations in utils_spec.rb - Fix RSpec mock issues in version_checker_spec.rb by properly mocking Rails.root as Pathname - Add validation to require at least one package (react-on-rails or react-on-rails-pro) to be installed - Add test coverage for missing package validation - Add pre-release version examples to documentation (releasing.md and release.rake) All tests now pass with 0 failures and 0 RuboCop offenses. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Extract validation logic into separate private methods to satisfy: - Metrics/AbcSize - Metrics/CyclomaticComplexity - Metrics/MethodLength Changes: - Split validate_package_gem_compatibility! into 4 focused validation methods: - validate_packages_installed! - Ensures at least one package is installed - validate_no_duplicate_packages! - Prevents both packages being installed - validate_pro_gem_uses_pro_package! - Enforces Pro gem uses Pro package - validate_pro_package_has_pro_gem! - Enforces Pro package requires Pro gem - Remove rubocop:disable and rubocop:enable comments - Maintain same functionality and test coverage (54 specs pass) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| Pull Request Review: Unified Release Scripts and Strict Version ValidationOverviewThis is an excellent PR that addresses critical pain points in the React on Rails release and version management process. The changes are well-structured, comprehensive, and demonstrate strong software engineering practices. ✅ Strengths1. Code Quality & Best Practices
 2. Architecture & Design
 3. Testing & Reliability
 4. Documentation
 🔍 Issues & SuggestionsHigh Priority1. Security: Potential command injection in package manager detection Location: lib/react_on_rails/utils.rb:327-340 and :346-358 The package_manager_install_exact_command and package_manager_remove_command methods directly interpolate package_name and version into shell commands. If these values come from untrusted sources (e.g., parsed from a malicious package.json), this could lead to command injection. Recommendation: Add input validation or use proper shell escaping with Shellwords.escape 2. Error handling: JSON parsing without rescue Location: lib/react_on_rails/version_checker.rb:300 The parsed_package_contents method parses JSON but doesn't handle malformed JSON gracefully. Add rescue JSON::ParserError => e block with clear error message. Medium Priority3. Performance: Boot-time validation impact Location: lib/react_on_rails/engine.rb:9-11 The validation runs on config.after_initialize, which means it runs on every Rails boot. For large applications, repeatedly parsing package.json and checking files could add milliseconds to boot time. Consider caching or adding a configuration option to disable in production. 4. Regex edge cases in version normalization Location: lib/react_on_rails/version_checker.rb:10 The VERSION_PARTS_REGEX uses a non-anchored pattern that could match invalid versions like "foo 1.2.3 bar". Consider adding anchors: /\A(\d+).(\d+).(\d+)(?:-.)?\z/ 5. Redundant validation checks Consider combining the file existence check with the "no packages installed" check to avoid redundancy. Low Priority6. RuboCop disable comments Location: lib/react_on_rails/version_checker.rb:60,147 Consider refactoring validate_package_gem_compatibility! into smaller methods to avoid disabling RuboCop cops. 7. Missing test for edge cases Consider adding tests for: 
 🔒 Security ConsiderationsOverall: Low Risk The PR primarily deals with build-time tooling rather than runtime user data, which limits security exposure. However: 
 ⚡ Performance Considerations
 Recommendation: Add telemetry to track validation duration and consider optimization if it exceeds 50ms. 📊 Test CoverageExcellent - The PR mentions: 
 📚 Documentation QualityOutstanding - The documentation is comprehensive and well-structured with clear examples, migration notes, troubleshooting guidance, and visual formatting. 🎯 Breaking ChangesThe switch from warnings to errors is technically a breaking change. Applications with version mismatches will now fail to boot. However, given that version mismatches cause runtime issues anyway, failing fast is arguably the right choice. Error messages provide clear fix instructions. 🏁 Final RecommendationAPPROVE with minor changes This is a high-quality PR that significantly improves the developer experience and reduces the likelihood of version-related bugs. The implementation is solid, well-tested, and thoroughly documented. Before Merging:
 Post-Merge Follow-ups:
 📝 Adherence to CLAUDE.md✅ The PR follows the project's conventions: 
 Excellent work! This PR demonstrates thoughtful engineering and will make React on Rails more reliable and easier to maintain. | 
| Pull Request Review: Unified Release Scripts and Strict Version ValidationOverall AssessmentVerdict: Excellent work! 🎉 This is a comprehensive, well-architected PR that significantly improves the React on Rails release process and version management. The implementation is thorough, well-tested, and follows best practices throughout. Recommendation: APPROVE with minor suggestions 🌟 Strengths1. Exceptional Code Quality
 2. Outstanding User Experience
 3. Robust Testing
 4. Excellent Documentation
 📋 Detailed AnalysisPart 1: Unified Release Scriptrakelib/release.rake:128 pro_version_content.gsub\!(/\bVERSION = ".+"/, "VERSION = \"#{actual_gem_version}\"")✅ Excellent use of word boundary ( rakelib/release.rake:92 sh_in_dir(gem_root, "git pull --rebase") unless is_dry_run || skip_push✅ Smart conditional - Skips pull in dry-run and skip_push modes Suggestions: 
 Part 2: Version Validationlib/react_on_rails/version_checker.rb:28-33 def validate_version_and_package_compatibility\!
  validate_package_json_exists\!
  validate_package_gem_compatibility\!
  validate_exact_version\!
  validate_version_match\!
end✅ Perfect method composition - Clear, readable, well-ordered validations lib/react_on_rails/version_checker.rb:240-244 # Check for react-on-rails-pro first (Pro takes precedence)
return @raw = deps["react-on-rails-pro"] if deps.key?("react-on-rails-pro")
# Fall back to react-on-rails
return @raw = deps["react-on-rails"] if deps.key?("react-on-rails")✅ Smart precedence handling - Pro package correctly takes priority lib/react_on_rails/utils.rb:296-310 def self.detect_package_manager
  manager = detect_package_manager_from_package_json || detect_package_manager_from_lock_files
  manager || :yarn # Default to yarn if no detection succeeds
end✅ Excellent implementation - Follows Node.js Corepack standard first, then fallback to lock files Potential Issue: lib/react_on_rails/version_checker.rb:272 raw.blank? || raw.start_with?(/[~^><*]/) || raw.include?(" - ") || raw.include?(" || ")
 Part 3: Node Renderer Validationpackages/node-renderer/src/worker/checkProtocolVersionHandler.ts:24-34 function normalizeVersion(version: string): string {
  if (\!version) return "";
  
  let normalized = version.trim().toLowerCase();
  
  // Replace the first dot after major.minor.patch with a hyphen
  normalized = normalized.replace(/^(\d+\.\d+\.\d+)\.([a-z]+)/, "$1-$2");
  
  return normalized;
}✅ Clean normalization logic - Handles Ruby gem vs NPM format differences elegantly checkProtocolVersionHandler.ts:11-14 const versionCache = new Map<string, boolean>();✅ Smart caching - Prevents repeated logging for same version mismatches checkProtocolVersionHandler.ts:76 const isProduction = railsEnv === "production" || NODE_ENV === "production";✅ Dual environment detection - Considers both Rails and Node environments Suggestion: 🔒 Security Considerations✅ No security concerns identified 
 ⚡ Performance Considerations✅ Good performance characteristics: 
 Minor optimization opportunity: 
 🧪 Test CoverageExcellent test coverage: 
 Missing test (minor): 
 📝 Documentation Quality✅ Outstanding documentation: 
 Minor suggestion: 
 🎯 Best Practices Followed✅ Repository conventions (from CLAUDE.md): 
 ✅ Code organization: 
 🐛 Potential Issues & SuggestionsMinor Issues
 Suggestions for Future Enhancements
 🎓 What I Learned from This PRThis is a masterclass in: 
 ✅ Checklist
 Final RecommendationAPPROVE - This PR is production-ready with only minor suggestions for future improvements. The unified versioning approach is excellent and will significantly reduce maintenance overhead while improving reliability. Great work, @AbanoubGhadban! This is exactly the kind of comprehensive improvement that makes maintaining a project easier. 🚀 Review generated by Claude Code | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️  Outside diff range comments (2)
rakelib/release.rake (1)
200-210: Avoid tag/commit churn: add --no-git-tag-version to yarn publishYou already pre-write versions and create the git tag. yarn publish with --new-version can re-tag/commit. Align with node‑renderer publish and add --no-git-tag-version.
Apply:
- sh_in_dir(gem_root, "yarn workspace react-on-rails publish --new-version #{actual_npm_version} #{npm_publish_args}") + sh_in_dir(gem_root, "yarn workspace react-on-rails publish --new-version #{actual_npm_version} --no-git-tag-version #{npm_publish_args}") - sh_in_dir(gem_root, - "yarn workspace react-on-rails-pro publish --new-version #{actual_npm_version} #{npm_publish_args}") + sh_in_dir(gem_root, + "yarn workspace react-on-rails-pro publish --new-version #{actual_npm_version} --no-git-tag-version #{npm_publish_args}")lib/react_on_rails/version_checker.rb (1)
268-273: Bug: start_with? does not accept RegexpString#start_with? only accepts strings; passing a Regexp will raise TypeError. This will crash for normal versions. Use match? or string prefixes.
Apply:
- raw.blank? || raw.start_with?(/[~^><*]/) || raw.include?(" - ") || raw.include?(" || ") + return true if raw.blank? + return true if raw.match?(/\A[~^><*]/) + raw.include?(" - ") || raw.include?(" || ")Add a spec asserting semver_wildcard? for values starting with each of ^ ~ > < *.
♻️ Duplicate comments (1)
docs/contributor-info/releasing.md (1)
178-182: Add language to fenced code block (MD040)Credentials file is YAML; tag it accordingly.
- ``` + ```yaml :github: Bearer <GITHUB_TOKEN></blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (4)</summary><blockquote> <details> <summary>spec/react_on_rails/version_checker_spec.rb (1)</summary><blockquote> `274-282`: **Inconsistent comment about fixture content** The two comments contradict (“not react-on-rails packages” vs “has react-on-rails”). Clarify to reduce reader confusion. </blockquote></details> <details> <summary>rakelib/release.rake (1)</summary><blockquote> `91-93`: **Pull behavior on release** git pull --rebase before bump is fine; skipping pull when skip_push=true is reasonable. Consider printing a reminder when skip_push is set that local is not synced before tagging. </blockquote></details> <details> <summary>docs/contributor-info/releasing.md (2)</summary><blockquote> `3-3`: **Clarify “unified versioning” in one sentence** Suggest adding: “Unified versioning means a single source-of-truth gem version is applied to all gems and npm packages, with npm prerelease syntax derived from the gem version.” --- `148-170`: **Scoped registry snippet for GitHub Packages** Add the scope mapping so yarn/npm route the private package to GitHub Packages without extra flags. ```diff **For private packages (GitHub Packages):** - Get a GitHub personal access token with `write:packages` scope - Add to `~/.npmrc`: - ```ini + ```ini + @shakacode-tools:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=<TOKEN> always-auth=true</blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 230d1901669dec9ea70f168cdf02affe73d4cd23 and 2395751e4d2642cd3404cf11aea1583fbfe05ee2. </details> <details> <summary>📒 Files selected for processing (5)</summary> * `docs/contributor-info/releasing.md` (3 hunks) * `lib/react_on_rails/version_checker.rb` (4 hunks) * `rakelib/release.rake` (9 hunks) * `spec/react_on_rails/utils_spec.rb` (1 hunks) * `spec/react_on_rails/version_checker_spec.rb` (3 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>📓 Path-based instructions (2)</summary> <details> <summary>**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}</summary> **📄 CodeRabbit inference engine (CLAUDE.md)** > Prettier is the sole authority for formatting all non-Ruby files; never manually format them Files: - `docs/contributor-info/releasing.md` </details> <details> <summary>{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}</summary> **📄 CodeRabbit inference engine (CLAUDE.md)** > `{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}`: All Ruby code must pass RuboCop with zero offenses before commit/push > RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files Files: - `spec/react_on_rails/version_checker_spec.rb` - `rakelib/release.rake` - `lib/react_on_rails/version_checker.rb` - `spec/react_on_rails/utils_spec.rb` </details> </details><details> <summary>🧠 Learnings (3)</summary> <details> <summary>📚 Learning: 2025-10-23T17:22:01.064Z</summary>Learnt from: AbanoubGhadban
PR: #1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. Thereact_on_rails_pro?method validates licenses and should raise errors early (including during path resolution in methods likeserver_bundle?) to enforce licensing requirements rather than failing later with obscure errors.**Applied to files:** - `spec/react_on_rails/version_checker_spec.rb` - `lib/react_on_rails/version_checker.rb` </details> <details> <summary>📚 Learning: 2025-09-29T12:23:13.615Z</summary>Learnt from: CR
PR: shakacode/react_on_rails#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-29T12:23:13.615Z
Learning: Applies to {Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}} : All Ruby code must pass RuboCop with zero offenses before commit/push**Applied to files:** - `spec/react_on_rails/utils_spec.rb` </details> <details> <summary>📚 Learning: 2025-02-18T13:08:01.477Z</summary>Learnt from: AbanoubGhadban
PR: #1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
- Pro version check in
run_stream_inside_fiber- RSC support check during pack generation via
ReactOnRailsPro.configuration.enable_rsc_support- RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.**Applied to files:** - `spec/react_on_rails/utils_spec.rb` </details> </details><details> <summary>🧬 Code graph analysis (3)</summary> <details> <summary>spec/react_on_rails/version_checker_spec.rb (2)</summary><blockquote> <details> <summary>spec/react_on_rails/support/version_test_helpers.rb (1)</summary> * `stub_gem_version` (3-5) </details> <details> <summary>lib/react_on_rails/version_checker.rb (8)</summary> * `validate_version_and_package_compatibility!` (28-33) * `build` (12-14) * `build` (218-220) * `raw` (230-252) * `react_on_rails_package?` (254-256) * `react_on_rails_pro_package?` (258-260) * `package_name` (262-266) * `semver_wildcard?` (268-273) </details> </blockquote></details> <details> <summary>lib/react_on_rails/version_checker.rb (1)</summary><blockquote> <details> <summary>lib/react_on_rails/utils.rb (3)</summary> * `package_manager_install_exact_command` (327-340) * `react_on_rails_pro?` (215-223) * `package_manager_remove_command` (346-359) </details> </blockquote></details> <details> <summary>spec/react_on_rails/utils_spec.rb (3)</summary><blockquote> <details> <summary>lib/react_on_rails/version_checker.rb (1)</summary> * `package_json_path` (222-224) </details> <details> <summary>lib/react_on_rails/utils.rb (3)</summary> * `detect_package_manager` (291-294) * `package_manager_install_exact_command` (327-340) * `package_manager_remove_command` (346-359) </details> <details> <summary>lib/generators/react_on_rails/generator_messages.rb (1)</summary> * `detect_package_manager` (183-193) </details> </blockquote></details> </details><details> <summary>🪛 ast-grep (0.39.6)</summary> <details> <summary>spec/react_on_rails/utils_spec.rb</summary> [warning] 704-704: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 704-704: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 720-720: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 720-720: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 728-728: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 728-728: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 729-729: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 729-729: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 737-737: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 737-737: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 738-738: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 738-738: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 739-739: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 739-739: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 747-747: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 747-747: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 748-748: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 748-748: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 749-749: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 749-749: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 750-750: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "package-lock.json")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 750-750: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "package-lock.json")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 758-758: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 758-758: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 759-759: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 759-759: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 760-760: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "bun.lockb")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 760-760: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "bun.lockb")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 761-761: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "package-lock.json")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 761-761: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "package-lock.json")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 775-775: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 775-775: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 788-788: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "yarn.lock")).and_return(false) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 788-788: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "yarn.lock")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 789-789: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: allow(File).to receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")).and_return(true) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) --- [warning] 789-789: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file. Context: receive(:exist?).with(File.join(Rails.root, "pnpm-lock.yaml")) Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES] https://cwe.mitre.org/data/definitions/522.html (hardcoded-secret-rsa-passphrase-ruby) </details> </details> <details> <summary>🪛 markdownlint-cli2 (0.18.1)</summary> <details> <summary>docs/contributor-info/releasing.md</summary> 162-162: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 180-180: Fenced code blocks should have a language specified (MD040, fenced-code-language) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)</summary> * GitHub Check: dummy-app-integration-tests (3.2, 20) * GitHub Check: dummy-app-integration-tests (3.4, 22) * GitHub Check: lint-js-and-ruby * GitHub Check: markdown-link-check * GitHub Check: build-dummy-app-webpack-test-bundles * GitHub Check: rspec-package-tests (3.4, minimum) * GitHub Check: rspec-package-tests (3.2, minimum) * GitHub Check: rspec-package-tests (3.4, latest) * GitHub Check: rspec-package-tests (3.2, latest) * GitHub Check: build-dummy-app-webpack-test-bundles </details> <details> <summary>🔇 Additional comments (10)</summary><blockquote> <details> <summary>spec/react_on_rails/utils_spec.rb (4)</summary><blockquote> `658-795`: **Excellent test coverage for package manager detection.** The tests comprehensively cover all detection scenarios: - Detection from `package.json` `packageManager` field for all supported managers - Fallback to lock file detection when the field is missing or invalid - Proper handling of unparsable/missing `package.json` - Correct default to yarn when no indicators exist The test structure is clear, and the mocking strategy correctly uses `and_call_original` with selective stubbing. --- `797-846`: **Well-structured tests for install command generation.** The tests verify the correct command format and flags for each package manager: - Proper exact-version flags (`--exact`, `--save-exact`) - Correct package@version format - Appropriate default to yarn for unknown managers --- `848-897`: **Complete test coverage for remove command generation.** The tests verify the correct remove/uninstall command for each package manager with appropriate defaults for unknown managers. --- `658-897`: **Note: Static analysis false positives.** The ast-grep warnings about "hardcoded RSA passphrase" for lines containing lock file paths (e.g., `"yarn.lock"`, `"pnpm-lock.yaml"`) are false positives. These are legitimate file paths used in test stubs, not security credentials. </blockquote></details> <details> <summary>spec/react_on_rails/version_checker_spec.rb (2)</summary><blockquote> `19-22`: **Good defaulting of Pro detection for tests** Stubbing ReactOnRails::Utils.react_on_rails_pro? to false by default keeps contexts isolated. LGTM. --- `24-39`: **Test matrix coverage is strong** Scenarios cover dual-install, missing packages, Pro/base mismatches, semver wildcards, version mismatch, local paths, matching Pro, and missing package.json. Assertions read clearly and align with initializer behavior. Nice work. Also applies to: 41-60, 62-85, 86-109, 111-129, 131-150, 152-169, 171-187, 189-209, 211-234 </blockquote></details> <details> <summary>lib/react_on_rails/version_checker.rb (2)</summary><blockquote> `180-201`: **Exact match check: good guardrails** Short-circuiting for nil and local paths avoids false positives; comparing normalized parts matches gem prerelease dotted vs npm hyphenated. LGTM. --- `37-58`: **Error UX is clear and actionable** Messages include install/remove commands tailored to the detected package manager and show the expected package.json location. This aligns with fail‑fast boot behavior. Optionally add one integration spec to assert the message includes the exact command for each package manager (npm, yarn, pnpm, bun). Also applies to: 71-91, 93-111, 113-131, 132-154 </blockquote></details> <details> <summary>rakelib/release.rake (2)</summary><blockquote> `220-231`: **publishConfig is correctly set to GitHub Packages** Verification confirms the concern is unfounded. The `react_on_rails_pro/package.json` file properly sets `publishConfig.registry` to `https://npm.pkg.github.com`, which ensures yarn publishes the scoped package to GitHub Packages when the `registry` parameter is not `verdaccio`. The code correctly enforces this routing without requiring additional arguments. --- `87-90`: **The review comment's portability concern is incorrect.** Based on my verification: 1. **-mindepth is supported on macOS/BSD**: Modern macOS find (BSD-based) explicitly supports `-mindepth` in its man pages. 2. **-delete already implies -depth**: On both GNU and BSD systems, the `-delete` action implicitly enables depth-first traversal, making explicit `-depth` unnecessary and the suggested workaround redundant. 3. **Actual portability**: `-mindepth` / `-maxdepth` are actually *more* portable than older BSD-specific options. The code is correct as written. The current implementation using `find . -mindepth 2 -name 'react_on_rails.gemspec' -delete` works correctly on macOS/BSD and requires no changes. > Likely an incorrect or invalid review comment. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
…gs and improving JSON parsing error handling
| Pull Request Review: Unified Release Scripts and Strict Version ValidationThis is an ambitious and well-executed PR that significantly improves version management across React on Rails. The changes are well-structured and thoroughly tested. Here's my detailed feedback: ✅ Strengths1. Excellent Code Quality
 2. Robust Validation LogicThe  
 3. Well-Designed Release ScriptThe unified release script (release.rake) shows good engineering: 
 4. Excellent Test Coverage
 5. Great Documentation
 🔍 Potential Issues & Suggestions1. Performance Consideration (Minor)Location:  The validation runs on  
 # Potential enhancement
initializer "react_on_rails.validate_version_and_package_compatibility" do
  config.after_initialize do
    unless ReactOnRails.configuration.skip_version_validation
      Rails.logger.info "[React on Rails] Validating package version and compatibility..."
      VersionChecker.build.validate_version_and_package_compatibility\!
      Rails.logger.info "[React on Rails] Package validation successful"
    end
  end
end2. Regex Edge Case (Minor)Location:  The wildcard detection regex  
 Suggestion: Consider more comprehensive regex: def wildcard_or_x_range?
  raw == "*" || 
  raw =~ /^[xX*]$/ || 
  raw =~ /^[xX*]\./ || 
  raw =~ /\.[xX*]\b/ || 
  raw =~ /\.[xX*]$/
end3. Node Renderer Version Normalization (Minor)Location:  The  Current regex:  
 Suggestion: Handle multiple prerelease segments: function normalizeVersion(version: string): string {
  if (\!version) return '';
  let normalized = version.trim().toLowerCase();
  // Replace dots with hyphens in prerelease section
  normalized = normalized.replace(/^(\d+\.\d+\.\d+)\.(.*)/,  (_, base, prerelease) => {
    return base + '-' + prerelease.replace(/\./g, '-');
  });
  return normalized;
}4. Security: JSON Parsing Error Handling (Good, but could be enhanced)Location:  The JSON parsing error handling is good, but consider: Suggestion: Add file permission check before parsing: def parsed_package_contents
  return @parsed_package_contents if defined?(@parsed_package_contents)
  unless File.readable?(package_json)
    raise ReactOnRails::Error, "package.json exists but is not readable. Check file permissions."
  end
  begin
    @parsed_package_contents = JSON.parse(package_json_contents)
  rescue JSON::ParserError => e
    # ... existing error handling
  end
end5. Breaking Change CommunicationThis PR introduces breaking changes for users: 
 Suggestion: 
 🛡️ Security Considerations✅ No security concerns identified 
 🧪 Testing RecommendationsAdditional Test Cases to Consider:
 📝 Documentation Review✅ Excellent documentation 
 Minor suggestions: 
 🎯 Performance Considerations
 ✅ Best Practices Followed
 🏁 ConclusionThis is a high-quality PR that significantly improves the developer experience and prevents common configuration errors. The code is well-tested, clearly documented, and follows Ruby/TypeScript best practices. Recommendation: Approve with minor suggestionsThe issues identified are minor and mostly edge cases. The PR is ready to merge after addressing the breaking change communication (consider adding to CHANGELOG and ensuring users are aware of the behavioral changes). Priority Fixes Before Merge:
 Great work on this PR! The unified versioning approach will make releases much more reliable and prevent user configuration errors. The fail-fast validation is a significant UX improvement. 🤖 Review generated by Claude Code | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
lib/react_on_rails/version_checker.rb (1)
180-201: LGTM! Version matching validation is correct.The validation properly compares version parts and provides clear error messaging.
The guard clause
node_package_version.raw.nil? || node_package_version.local_path_or_url?is repeated at lines 157 and 181. Consider extracting to a helper method likeskip_version_validation?for DRY:def skip_version_validation? node_package_version.raw.nil? || node_package_version.local_path_or_url? endThen use:
return if skip_version_validation?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
- lib/react_on_rails/version_checker.rb(4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- lib/react_on_rails/version_checker.rb
🧠 Learnings (1)
📚 Learning: 2025-10-23T17:22:01.064Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Applied to files:
- lib/react_on_rails/version_checker.rb
🧬 Code graph analysis (1)
lib/react_on_rails/version_checker.rb (1)
lib/react_on_rails/utils.rb (3)
package_manager_install_exact_command(327-340)
react_on_rails_pro?(215-223)
package_manager_remove_command(346-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: dummy-app-integration-tests (3.2, 20)
- GitHub Check: dummy-app-integration-tests (3.4, 22)
- GitHub Check: build
- GitHub Check: markdown-link-check
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: claude-review
- GitHub Check: lint-js-and-ruby
- GitHub Check: build-dummy-app-webpack-test-bundles
🔇 Additional comments (10)
lib/react_on_rails/version_checker.rb (10)
20-33: LGTM! Well-orchestrated validation entry point.The method provides a clear, fail-fast validation flow with comprehensive documentation. The four validation steps are logically ordered and will catch all the misconfiguration scenarios mentioned in the PR objectives.
37-58: LGTM! Clear validation with actionable error messages.The validation correctly checks for package.json existence and provides package manager-specific installation commands for both base and Pro packages.
60-154: LGTM! Comprehensive package/gem compatibility enforcement.The validation suite correctly enforces mutual consistency between gem and package installations with clear, actionable error messages. The use of
ReactOnRails::Utils.react_on_rails_pro?at line 63 properly validates licenses and raises early as intended.
156-178: LGTM! Enforces exact version requirement clearly.The validation correctly prohibits semver ranges and wildcards with a clear error message that shows both the detected version and the expected gem version.
211-213: LGTM! Simple helper promotes consistent error messaging.
230-252: LGTM! Improved package detection with clear precedence.The updated logic correctly prioritizes the Pro package and handles all edge cases. The warning at lines 247-250 is now redundant with
validate_packages_installed!but serves as a useful debugging signal.
254-266: LGTM! Clean public interface for package detection.The new methods provide a clear API for checking package installation and retrieving the canonical package name, with appropriate Pro package precedence.
268-291: LGTM! Excellent decomposition of semver wildcard detection.The refactoring into focused helper methods significantly improves readability and maintainability. Each helper method has a clear, single responsibility and the patterns correctly identify all major semver range/wildcard syntaxes.
313-318: LGTM! Safe and defensive package presence check.The method correctly handles missing files and safely navigates the package.json structure. Limiting the check to
dependencies(notdevDependencies) is appropriate for runtime validation.
324-345: LGTM! Robust JSON parsing with excellent error guidance.The method properly handles JSON parsing errors with a comprehensive error message that lists common JSON syntax mistakes, making debugging much easier for users.
…r commands This commit adds defense-in-depth protection against potential command injection in package manager command generation methods. Changes: - Add Shellwords escaping for all package names and versions in generated commands - Add input validation for package names following npm naming standards - Add input validation for version strings to allow only safe semver patterns - Validate inputs before command generation in both install and remove methods Security benefits: - Multiple layers of protection (validation + escaping) - Clear error messages for invalid inputs - Future-proof against usage pattern changes All existing tests pass with these security enhancements. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| Code Review: PR #1881 - Unified Release & Strict Version ValidationThis is an excellent PR that improves React on Rails version management significantly. Overall Assessment: APPROVE with minor suggestionsStrengths: 
 Part 1: Unified Release Script - ExcellentStrengths: 
 Suggestions: 
 Part 2: Strict Version Validation - ExcellentSecurity - EXCELLENT: 
 Strengths: 
 Potential Issues: 
 Part 3: Node Renderer Validation - ExcellentStrengths: 
 Security Review: EXCELLENTNo security concerns identified. The input validation is exemplary: 
 Test Coverage: EXCELLENTRuby Tests: 53 tests covering all validation scenarios Suggestion: Add integration test that runs release script in dry-run mode Potential Bugs
 Performance Considerations
 Recommendations Before MergeHigh Priority:
 Medium Priority:
 Low Priority (Future):
 Final VerdictRecommendation: APPROVE with minor fixes This is high-quality work that significantly improves React on Rails maintainability and user experience. The implementation demonstrates: 
 The core functionality is solid and ready for merge after addressing the newline validation issue. Great Work! 🎉This PR exemplifies good software engineering: 
 Thank you for this valuable contribution to React on Rails! Reviewed by: Claude Code | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
lib/react_on_rails/utils.rb (3)
301-312: Consider more precise regex for npm package names.The current regex permits patterns that are invalid for npm packages:
- Allows
@anywhere in the name (e.g.,abc@def)- Scoped packages must follow
@scope/packageformat exactlyWhile this permissive approach may work for basic safety checks, consider tightening the regex to match the npm spec more closely if stricter validation is desired.
Example of a more precise pattern:
- return if package_name.match?(%r{\A[@a-z0-9][a-z0-9._/-]*\z}i) + # Match unscoped (alphanumeric + hyphens/dots/underscores) or scoped (@scope/package) + return if package_name.match?(%r{\A(@[a-z0-9-]+/)?[a-z0-9][a-z0-9._-]*\z}i)
319-331: Version regex is overly permissive for semver validation.The regex allows versions starting with letters (e.g.,
abc.def.ghi), but the PR context indicates this is for exact version pinning. Semver versions should start with digits.While npm tags like
latestornextare valid version specifiers, they shouldn't be used with exact version pinning.Apply this diff to enforce digit-first semver pattern:
- return if version.match?(/\A[a-z0-9][a-z0-9._-]*\z/i) + # Enforce semver pattern: must start with digit, allows prerelease/build metadata + return if version.match?(/\A\d+(\.\d+)*(-[a-z0-9._-]+)?(\+[a-z0-9._-]+)?\z/i) raise ReactOnRails::Error, "Invalid version: #{version.inspect}. " \ - "Versions must contain only alphanumeric characters, dots, hyphens, and underscores." + "Versions must follow semver format (e.g., 1.2.3, 1.2.3-beta.1)."
333-346: Overly broad exception handling masks potential issues.The
rescue StandardError(line 344) catches all errors silently, including JSON parsing failures, file permission errors, and encoding issues. This makes debugging difficult when package.json exists but has problems.Consider catching specific exceptions to allow real errors to surface during development:
- rescue StandardError + rescue JSON::ParserError, Errno::ENOENT, Errno::EACCES nil endThis still gracefully handles missing or malformed packageManager fields while allowing other errors to propagate in development mode.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
- lib/react_on_rails/utils.rb(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- lib/react_on_rails/utils.rb
🧬 Code graph analysis (1)
lib/react_on_rails/utils.rb (2)
lib/generators/react_on_rails/generator_messages.rb (1)
detect_package_manager(183-193)lib/react_on_rails/version_checker.rb (2)
package_name(262-266)
package_json_path(222-224)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: dummy-app-integration-tests (3.4, 22)
- GitHub Check: dummy-app-integration-tests (3.2, 20)
- GitHub Check: build
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: markdown-link-check
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: claude-review
- GitHub Check: lint-js-and-ruby
🔇 Additional comments (5)
lib/react_on_rails/utils.rb (5)
8-8: LGTM! Good security practice.Adding Shellwords for safe command construction is the right approach for preventing command injection vulnerabilities.
348-356: LGTM! Lock file detection logic is sound.The detection order (yarn → pnpm → bun → npm) is reasonable, and checking at
Rails.rootis correct since lock files are always at the project root. The separation from package.json detection (which checksnode_modules_location) is appropriate.
387-404: LGTM! Remove command generation is correct.The method properly validates inputs, escapes package names, and uses the correct removal command for each package manager (including npm's
uninstall).
364-381: Code changes are correct; Shellwords.escape preserves package@version format.Verification confirms that
Shellwords.escapedoes not modify the@character since it's not a shell metacharacter. Both standard packages (react-on-rails@16.0.0) and scoped packages (@scope/package@1.0.0) are preserved correctly, so the commands generated for each package manager will work as intended.
287-295: Disregard this review comment – the flagged methods serve different purposes and intentionally have separate defaults.These are two independent implementations with different signatures and contexts:
lib/react_on_rails/utils.rb::detect_package_manageris a public class method that returns symbols and defaults to:yarnfor runtime package detection, with comprehensive logic (checks package.json first per Corepack standard, then lock files).
lib/generators/react_on_rails/generator_messages.rb::detect_package_manageris an instance method that returns strings and defaults to"npm"for generator/setup context (Shakapacker 8.x default), with simpler logic (checks lock files only).They have different return types (symbols vs strings), different scopes, and are used in entirely different contexts. The different defaults are intentional, not an inconsistency requiring fixes.
Likely an incorrect or invalid review comment.
Enhance the wildcard_or_x_range? method to catch more edge cases: - Detect standalone wildcards: *, x, X - Detect wildcard prefixes: *.1.2, x.1.2, X.1.2 - Detect wildcard in middle: 1.*.2, 1.x.2, 1.X.2 - Detect wildcard suffixes: 1.2.*, 1.2.x, 1.2.X Previous pattern missed some valid npm wildcard patterns. New pattern is more explicit and comprehensive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| Pull Request Review - PR #1881Completed comprehensive review. This is impressive, well-architected work that significantly improves React on Rails release and version management. Overall AssessmentStatus: APPROVED with minor suggestions Demonstrates excellent practices: unified versioning, comprehensive testing (53 Ruby + 17 TS tests), detailed docs, fail-fast validation, thoughtful error handling. Key Strengths1. Unified Release Process 
 2. Fail-Fast Version Validation (lib/react_on_rails/version_checker.rb) 
 3. Node Renderer Version Validation 
 4. Test Coverage 
 5. Security Practices 
 Issues FoundCritical: None High Priority Suggestions: 
 Improvement SuggestionsCode Quality: 
 Documentation: 
 Performance: 
 Security: 
 Testing: 
 Final VerdictLGTM ✅ Merge confidence: High Production-ready code. Suggestions are minor improvements that don't block merging. Special recognition for: 
 Excellent work! 🚀 Review by Claude Code per CLAUDE.md | 
| Code Review: Unify release scripts and add strict version validationI've completed a comprehensive review of PR #1881. This is an excellent PR that significantly improves the React on Rails release process and version management. Here's my detailed analysis: 🎯 Overall AssessmentVerdict: ✅ APPROVE with minor suggestions This PR demonstrates exceptional engineering quality with: 
 🌟 Strengths1. Unified Release Script (rakelib/release.rake)Excellent Design: 
 Security: 
 2. Version Validation (lib/react_on_rails/version_checker.rb)Robust Implementation: 
 Highlights: 
 3. Node Renderer Validation (checkProtocolVersionHandler.ts)Smart Design: 
 4. Package Manager Utilities (lib/react_on_rails/utils.rb)Security-Conscious: 
 Good Coverage: 
 📋 Code Quality AssessmentBest Practices ✅
 Test Coverage ✅Based on the PR description: 
 🔍 Potential Issues & Suggestions1. Minor: Double Negation in Code# lib/react_on_rails/version_checker.rb:132
def validate_pro_package_has_pro_gem\!(is_pro_gem, has_pro_package)
  return unless \!is_pro_gem && has_pro_package  # Consider: return if is_pro_gem || \!has_pro_packageSuggestion: De Morgan's law would make this more readable: return if is_pro_gem || \!has_pro_package2. Minor: Regex Optimization# lib/react_on_rails/version_checker.rb:290
def range_operator?
  raw.start_with?(/[~^><*]/)  # Regex not needed for character class
endSuggestion: Use string character class for better performance: def range_operator?
  raw.start_with?('^', '~', '>', '<', '*')
end3. Enhancement: Package Manager Detection Could Handle Edge CasesThe package manager detection silently catches all exceptions: # lib/react_on_rails/utils.rb:344
rescue StandardError
  nil
endSuggestion: Consider logging when JSON parsing fails to aid debugging: rescue StandardError => e
  Rails.logger.debug("Failed to detect package manager from package.json: #{e.message}")
  nil
end4. Enhancement: Version Normalization Could Document Edge Cases// checkProtocolVersionHandler.ts:31
normalized = normalized.replace(/^(\d+\.\d+\.\d+)\.([a-z]+)/, '$1-$2');This handles  Suggestion: Add test cases for these edge cases or document assumptions. 5. Performance: Version Regex Could Be Compiled Once# lib/react_on_rails/version_checker.rb:10
VERSION_PARTS_REGEX = /(\d+)\.(\d+)\.(\d+)(?:[-.]([0-9A-Za-z.-]+))?/This is already a constant - good! But in the NodePackageVersion class methods, regexes are inline: raw =~ /^[xX*]$/
raw =~ /^[xX*]\./Suggestion: Consider extracting these to constants if performance becomes a concern. 🔒 Security Analysis✅ Strengths:
 
 | 
| Comprehensive Code Review: PR #1881SummaryThis is an excellent, well-architected PR that significantly improves React on Rails' version management and release process. The three-part approach (unified release script, strict validation, and node renderer validation) is well thought out and thoroughly tested. ✅ Strengths1. Exceptional Code Quality
 2. Outstanding Test Coverage
 3. Security - Well Handled ✅
 4. Excellent User Experience
 🔍 Code Quality ObservationsVery Good ✅
 🐛 Potential Issues / SuggestionsMinor Issues
 Questions for Maintainer
 📊 Performance ConsiderationsGood: 
 Potential optimization: 
 🔒 Security Review - Excellent ✅The PR demonstrates excellent security practices: 
 📝 DocumentationStrengths: 
 Suggestions: 
 🎯 RecommendationsBefore Merge:
 Future Enhancements (not blocking):
 ✅ Final VerdictLGTM with minor suggestions - This is high-quality, production-ready code that significantly improves the project. The architecture is sound, testing is thorough, and security is well-handled. Recommended action: Merge after addressing the minor clarity issues mentioned above. Review completed by Claude Code | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
docs/contributor-info/releasing.md (3)
63-64: Fix list formatting for PRIVATE packages.Both items are rendered on one line. Split into proper list items for readability.
Apply this diff:
-**PRIVATE (GitHub Packages):** 4. **@shakacode-tools/react-on-rails-pro-node-renderer** - NPM package 5. **react_on_rails_pro** - RubyGem +**PRIVATE (GitHub Packages):** + +4. **@shakacode-tools/react-on-rails-pro-node-renderer** - NPM package +5. **react_on_rails_pro** - RubyGem
160-169: Add language tags to fenced code blocks.The .npmrc snippet (line 162) and the export command (line 168) code blocks need language identifiers for proper rendering and to satisfy markdownlint.
Apply this diff:
- Add to `~/.npmrc`: - ``` + ```ini //npm.pkg.github.com/:_authToken=<TOKEN> always-auth=true
- Set environment variable:
export GITHUB_TOKEN=<TOKEN>
--- `180-182`: **Add language tag to fenced code block.** The credentials file snippet is missing a language identifier, triggering MD040 linting failures. Apply this diff: ```diff - Add to `~/.gem/credentials`: - ``` + ```yaml :github: Bearer <GITHUB_TOKEN></blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (5)</summary><blockquote> <details> <summary>docs/contributor-info/releasing.md (1)</summary><blockquote> `3-3`: **Consider clarifying "unified versioning" terminology.** The phrase "using unified versioning" followed by "We keep the version numbers in sync" is somewhat redundant. Consider being more explicit about what this means. For example: ```diff -We're releasing this as a unified release with 5 packages total. We keep the version numbers in sync across all packages using unified versioning. +We're releasing this as a unified release with 5 packages total. All packages share the same version number and are released together (unified versioning).react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (4)
63-80: Cache by normalized gem version to dedupe logs and comparisons.Currently the cache keys on the raw
gemVersion, causing duplicate work/logs for equivalent variants (case/whitespace/prerelease dot vs hyphen). Key by normalized value.- // Check cache first - let versionsMatch = versionCache.get(gemVersion); - let justCached = false; - - // If not in cache, perform comparison and cache the result - if (versionsMatch === undefined) { - const normalizedGemVersion = normalizeVersion(gemVersion); - const normalizedPackageVersion = normalizeVersion(packageJson.version); - versionsMatch = normalizedGemVersion === normalizedPackageVersion; + const normalizedGemVersion = normalizeVersion(gemVersion); + // Check cache first using normalized key + let versionsMatch = versionCache.get(normalizedGemVersion); + let justCached = false; + + // If not in cache, perform comparison and cache the result + if (versionsMatch === undefined) { + const normalizedPackageVersion = normalizeVersion(packageJson.version); + versionsMatch = normalizedGemVersion === normalizedPackageVersion; // Clear cache if it exceeds max size to prevent unbounded growth if (versionCache.size >= VERSION_CACHE_MAX_SIZE) { versionCache.clear(); } - versionCache.set(gemVersion, versionsMatch); + versionCache.set(normalizedGemVersion, versionsMatch); justCached = true; }
11-15: Make cache-eviction comment match behavior.Comment says “exceeds 10” but code clears at
>= 10. Clarify to avoid confusion.-// Cache is cleared when it exceeds 10 entries to prevent unbounded growth +// Cache is cleared when it reaches VERSION_CACHE_MAX_SIZE entries to prevent unbounded growth
1-4: Fix JSDoc module name typo.- * @module worker/checkProtocVersionHandler + * @module worker/checkProtocolVersionHandler
91-93: Include env context in the production warning for easier debugging.- log.warn(mismatchMessage); + log.warn( + `${mismatchMessage} (railsEnv=${railsEnv ?? 'undefined'}, NODE_ENV=${process.env.NODE_ENV ?? 'undefined'})` + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
- docs/contributor-info/releasing.md(3 hunks)
- lib/react_on_rails/version_checker.rb(4 hunks)
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
- docs/contributor-info/releasing.md
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
- lib/react_on_rails/version_checker.rb
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JS/TS code (lint via rake lint or yarn lint)
Files:
- react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
🧠 Learnings (1)
📚 Learning: 2025-10-23T17:22:01.064Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Applied to files:
- lib/react_on_rails/version_checker.rb
🧬 Code graph analysis (2)
lib/react_on_rails/version_checker.rb (1)
lib/react_on_rails/utils.rb (3)
package_manager_install_exact_command(364-381)
react_on_rails_pro?(216-224)
package_manager_remove_command(387-404)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (1)
react_on_rails_pro/packages/node-renderer/src/worker/types.ts (1)
FastifyRequest(11-11)
🪛 markdownlint-cli2 (0.18.1)
docs/contributor-info/releasing.md
180-180: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: dummy-app-integration-tests (3.4, 22)
- GitHub Check: dummy-app-integration-tests (3.2, 20)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build
- GitHub Check: lint-js-and-ruby
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: markdown-link-check
- GitHub Check: claude-review
🔇 Additional comments (9)
lib/react_on_rails/version_checker.rb (8)
20-33: LGTM: Well-structured validation orchestration.The new entry point properly orchestrates all compatibility checks in a logical sequence. The documentation clearly explains what each validation enforces.
37-58: LGTM: Clear error messaging with actionable remediation.The validation correctly detects missing package.json and provides package-manager-aware installation commands for both base and Pro scenarios.
60-154: LGTM: Comprehensive package-gem compatibility validation.The four-tier validation correctly enforces:
- At least one package must be present
- Mutual exclusivity of base and Pro packages (Pro supersedes base)
- Pro gem requires Pro package
- Pro package requires Pro gem (with fallback option to base)
All error messages provide actionable, package-manager-aware remediation steps.
156-178: LGTM: Proper exact-version enforcement.The validation correctly skips legitimate cases (nil, local paths/URLs) and enforces exact versioning with clear error messaging that lists prohibited semver syntax.
180-201: LGTM: Version match validation is sound.Correctly compares parsed version components for exact match, with appropriate edge-case handling and actionable error messaging.
230-266: LGTM: Improved package detection with appropriate precedence.The refactored
rawmethod correctly:
- Uses shared JSON parsing
- Prioritizes Pro over base package (correct precedence)
- Logs a warning for missing packages (hard errors are raised in validation methods)
The new helper methods (
react_on_rails_package?,react_on_rails_pro_package?,package_name) provide clean, testable abstractions.
268-295: Comprehensive semver range detection.The granular helpers correctly identify all forms of non-exact versions:
- Special strings (latest, next, canary, etc.)
- Wildcard/x-ranges (*, x, X in various positions)
- Range operators (^, ~, >, <)
- Range syntax (" - ", " || ")
Minor observation: Line 272 treats blank as a wildcard, which is pragmatic for validation purposes but semantically a blank value is more "invalid/missing" than a "wildcard." This is acceptable as a defensive check.
328-349: LGTM: Robust JSON parsing with excellent error guidance.The memoized parsing includes comprehensive error handling that provides:
- Exact file location
- Original error message
- Common JSON syntax issues to check
This will significantly improve the debugging experience for malformed package.json files.
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (1)
26-36: normalizeVersion implementation looks solid.Good handling of prerelease normalization and casing; simple and readable.
| const NODE_ENV = process.env.NODE_ENV || 'production'; | ||
|  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Avoid defaulting NODE_ENV to 'production' and avoid import-time capture.
Defaulting to production can mask dev mismatches; capturing at import time makes tests brittle. Compute from env at request time and keep your OR semantics.
-const NODE_ENV = process.env.NODE_ENV || 'production';
+// Read NODE_ENV at request time to reflect the current environment.-      const isProduction = railsEnv === 'production' || NODE_ENV === 'production';
+      const isProduction = railsEnv === 'production' || process.env.NODE_ENV === 'production';Please run your node-renderer tests with scenarios where:
- railsEnv='development', NODE_ENV unset
- railsEnv='development', NODE_ENV='production'
- railsEnv unset, NODE_ENV='production'
 to confirm the intended permissive/strict behavior.
Also applies to: 84-85
🏁 Script executed:
#!/bin/bash
# Examine the target file to understand current implementation
find . -name "checkProtocolVersionHandler.ts" -type f | head -5Length of output: 85
🏁 Script executed:
#!/bin/bash
# View the file content, focusing on lines around 9-10 and 84-85
cat react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.tsLength of output: 4077
🏁 Script executed:
#!/bin/bash
# Search for all usages of NODE_ENV in the codebase
rg -n "NODE_ENV" --type ts --type js -C 2Length of output: 121634
🏁 Script executed:
#!/bin/bash
# Look for test files related to checkProtocolVersionHandler
find . -name "*checkProtocolVersionHandler*" -o -name "*test*" -o -name "*spec*" | grep -i "checkprotocol\|worker" | head -20Length of output: 197
🏁 Script executed:
#!/bin/bash
# Examine the test file
cat react_on_rails_pro/packages/node-renderer/tests/worker.test.ts | head -100Length of output: 3448
🏁 Script executed:
#!/bin/bash
# Check if NODE_ENV const is used anywhere else in the handler file
grep -n "NODE_ENV" react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.tsLength of output: 142
🏁 Script executed:
#!/bin/bash
# Look for any tests that modify NODE_ENV or test environment behavior
rg -n "NODE_ENV\s*=" react_on_rails_pro/packages/node-renderer/tests/ --type tsLength of output: 0
Remove the import-time NODE_ENV capture and read from environment at request time.
The concern is valid: capturing process.env.NODE_ENV at import time freezes its value, and defaulting to 'production' can mask development scenarios. This is especially problematic when NODE_ENV is unset—the code should use development behavior by default, not production.
At line 84, change from reading the captured NODE_ENV constant to reading process.env.NODE_ENV directly at request time to reflect the current environment state and avoid surprising defaults.
-const NODE_ENV = process.env.NODE_ENV || 'production';
+// Read NODE_ENV at request time to reflect the current environment.-      const isProduction = railsEnv === 'production' || NODE_ENV === 'production';
+      const isProduction = railsEnv === 'production' || process.env.NODE_ENV === 'production';🤖 Prompt for AI Agents
In
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
around lines 9-10 and at line 84, remove the import-time capture const NODE_ENV
= process.env.NODE_ENV || 'production'; and instead read process.env.NODE_ENV at
request time where the code currently uses the NODE_ENV constant (line 84);
change the logic to treat an unset NODE_ENV as development behavior (e.g.,
default to 'development' or branch on falsy to development) so the environment
is evaluated per-request rather than frozen at module import.
| const { protocolVersion: reqProtocolVersion, gemVersion, railsEnv } = req.body as RequestBody; | ||
|  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent crash when req.body is undefined (safe destructuring).
Destructuring req.body directly can throw if body is missing. Use a safe default to avoid runtime errors.
-  const { protocolVersion: reqProtocolVersion, gemVersion, railsEnv } = req.body as RequestBody;
+  const {
+    protocolVersion: reqProtocolVersion,
+    gemVersion,
+    railsEnv,
+  } = (req.body as Partial<RequestBody>) ?? {};🤖 Prompt for AI Agents
In
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
around lines 45 to 46, destructuring req.body directly can throw when body is
undefined; change to safely destructure from a default empty object (and adjust
types if needed) so reqProtocolVersion, gemVersion and railsEnv are read from
req.body || {} to avoid runtime crashes when req.body is missing.
…ing error message enhancements, strict version validation, and command injection protection.
| Pull Request Review: Unify release scripts and add strict version validationI've completed a comprehensive review of this PR. Overall, this is excellent work that significantly improves the React on Rails release process and runtime safety. The implementation is thorough, well-tested, and follows best practices. ✅ Strengths1. Unified Release Script (Part 1)
 2. Strict Version Validation (Part 2)
 3. Node Renderer Version Validation (Part 3)
 4. Test Coverage
 🔍 Code Quality ObservationsSecurity ✅
 Performance ✅
 Maintainability ✅
 📝 Minor Suggestions1. Release Script - Ruby Version Detection ( | 
Summary
This PR implements three major improvements to React on Rails version management:
These changes work together to ensure consistent versioning across all packages (both during releases and at runtime).
Part 1: Unified Release Script
Problem
Previously, React on Rails had two separate release scripts with different workflows:
react-on-railsgem +react-on-railsNPM +react-on-rails-proNPMreact_on_rails_progem +node-rendererNPMThis created maintenance overhead and potential for version mismatches.
Solution: Synchronized Versioning
All packages now share the same version number, managed by a single release script at the root.
Packages unified:
react-on-rails(gem + NPM)react-on-rails-pro(gem + NPM)node-renderer(NPM)Version files updated atomically (6 locations):
/lib/react_on_rails/version.rb/packages/react-on-rails/package.json/packages/react-on-rails-pro/package.json/react_on_rails_pro/lib/react_on_rails_pro/version.rb/react_on_rails_pro/package.json(node-renderer)/package.json(root workspace)Key Features
patch,minor,majoror specify exact version^or~)Usage Examples
Files Removed (Deprecated)
react_on_rails_pro/rakelib/release.rake- Replaced by unified scriptreact_on_rails_pro/script/release- No longer neededreact_on_rails_pro/package.json- Not needed at Pro rootDocumentation Updated
docs/contributor-info/releasing.md- Complete rewrite with new processreact_on_rails_pro/CONTRIBUTING.md- Updated to reference root scriptreact_on_rails_pro/docs/contributors-info/releasing.md- Updated release docsPart 2: Strict Version Validation
Problem
Users could misconfigure package.json (wrong versions, conflicting packages, semver wildcards) and only discover issues at runtime. Warnings were easily missed in logs.
Solution: Fail-Fast Validation
Application now validates configuration at boot and raises clear errors for misconfigurations.
Implementation
validate_version_and_package_compatibility!config.after_initialize^,~,>,<,*)Validation Scenarios
1. Missing package.json
2. Both packages installed
3. Pro gem with base package
4. Pro package without Pro gem
5. Non-exact version (semver wildcard)
6. Version mismatch
Code Quality Improvements
package_installed?(package_name)helperreact_on_rails_package?,react_on_rails_pro_package?log_if_gem_and_node_package_versions_differmethodTest Coverage
Part 3: Node Renderer Gem Version Validation
Problem
When using React on Rails Pro with a remote node renderer, version mismatches between the Ruby gem (
react_on_rails_pro) and the node renderer package (@shakacode-tools/react-on-rails-pro-node-renderer) could cause subtle runtime issues. These mismatches were difficult to diagnose.Solution: Runtime Version Validation
The node renderer now validates that the gem version matches the node renderer package version on every request, with environment-aware behavior.
Implementation
Ruby Side Changes (
lib/react_on_rails_pro/utils.rb):railsEnvtocommon_form_datamethodNode Renderer Changes (
packages/node-renderer/src/worker/checkProtocolVersionHandler.ts):normalizeVersion()function to handle version format differencesVersion Normalization
The
normalizeVersion()function handles these edge cases:4.0.0.rc.14.0.0-rc.14.0.0-RC.14.0.0-rc.14.0.04.0.04.0.0.alpha.14.0.0-alpha.14.0.0.beta.24.0.0-beta.2Behavior
Development Environment:
Production Environment:
Environment Detection
The node renderer determines if it's in production using either:
railsEnv === 'production'(sent from Ruby)NODE_ENV === 'production'(node environment variable)If either is production, the permissive behavior applies.
Test Coverage
Updated Tests (
packages/node-renderer/tests/worker.test.ts):railsEnvfield in requestsNew Tests Added (6 comprehensive tests):
4.0.0.rc.1==4.0.0-rc.1)4.0.0-RC.1==4.0.0-rc.1)Test Results:
Files Changed
Release Script Changes
rakelib/release.rake- Unified release logic for all packagesrakelib/task_helpers.rb- Enhanced with Ruby version detectiondocs/contributor-info/releasing.md- Complete documentation rewritereact_on_rails_pro/CONTRIBUTING.md- Updated contributor guidereact_on_rails_pro/docs/contributors-info/releasing.md- Updated release docsreact_on_rails_pro/react_on_rails_pro.gemspec- Dependency updatesVersion Validation Changes
lib/react_on_rails/engine.rb- Added validation initializerlib/react_on_rails/version_checker.rb- Core validation logic (205 lines changed)spec/react_on_rails/version_checker_spec.rb- Comprehensive test coverage (327 lines changed)spec/react_on_rails/fixtures/- New test fixtures (3 files)Node Renderer Validation Changes
lib/react_on_rails_pro/utils.rb- AddedrailsEnvto request datapackages/node-renderer/src/worker/checkProtocolVersionHandler.ts- Added gem version validation with normalizationpackages/node-renderer/tests/worker.test.ts- Updated existing tests + 6 new testsRemoved Files
react_on_rails_pro/rakelib/release.rake- Deprecatedreact_on_rails_pro/script/release- No longer neededreact_on_rails_pro/package.json- Not needed at Pro rootBenefits
Unified Release Script
Strict Version Validation
Node Renderer Validation
Testing
Release Script Testing
Validation Testing
Node Renderer Testing
Migration Notes
For Contributors
rake releasecommand instead of Pro-specific scriptsFor Users
^,~, etc.)Fixes #1876
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com
This change is
Summary by CodeRabbit
New Features
Chores
Documentation
Tests