Skip to content

Conversation

@lodewiges
Copy link
Contributor

@lodewiges lodewiges commented Jan 17, 2026

PDF generation did work locally but it did not work on staging

Summary by CodeRabbit

  • Chores

    • Reduced container image footprint by installing font support and cleaning package caches; improved container stability.
  • Configuration

    • Made server-side rendering settings environment-aware so launcher path and launch arguments are applied only outside development, improving production rendering reliability.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings January 17, 2026 19:27
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Updates the Dockerfile to add fonts-liberation and perform apt cleanup; adjusts Grover initializer to build config.options via a local hash and conditionally set executable_path and launch_args in non-development environments.

Changes

Cohort / File(s) Summary
Docker Image Setup
Dockerfile
Adds fonts-liberation to apt packages and appends apt-get clean plus removal of /var/lib/apt/lists/* in the same RUN to reduce image size.
Grover Configuration
config/initializers/grover.rb
Replaces direct inline config.options = { ... } with a local options hash; assigns options[:executable_path] and options[:launch_args] only when not in Rails.env.development?, then sets config.options = options.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A tiny image, tidy and spry,
Fonts snug inside, caches waved goodbye.
Grover finds Chromium, flags in a row,
The rabbit hops on, ready to go!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is significantly incomplete compared to the template requirements, missing checklist items, detailed summary of changes, and explanation of how the hotfix addresses the staging environment issue. Complete the description template by: 1) filling the checklist section with database migration status; 2) expanding the summary to explain what was changed and why it fixes the staging issue; 3) noting any dependencies or environment-specific configuration changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Hotfix for fixing PDF generation' is directly related to the changes made in the Dockerfile and grover.rb configuration, which address PDF generation issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses PDF generation failures in staging by configuring Grover (a Ruby PDF generation library) to use Chromium with appropriate containerized environment settings. The changes ensure PDF generation works in Docker containers where sandboxing and resource constraints differ from local development.

Changes:

  • Added explicit Chromium executable path and Docker-compatible launch arguments to Grover configuration
  • Enhanced Dockerfile with fonts package and cleanup commands for better image optimization

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
config/initializers/grover.rb Configured Chromium executable path and launch arguments to work in containerized environments
Dockerfile Added fonts-liberation package for proper PDF rendering and cleanup commands to reduce image size
Comments suppressed due to low confidence (1)

Dockerfile:27

  • The Node installation RUN command on lines 25-27 should also include cleanup commands (apt-get clean and rm -rf /var/lib/apt/lists/*) to reduce the Docker image size, similar to what was added for the first apt-get command. This is a Docker best practice to minimize layer sizes.
RUN curl -sL https://deb.nodesource.com/setup_22.x | bash - && \
  apt-get install -y nodejs && \
  npm install -q -g yarn

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

display_url: "https://#{Rails.application.config.x.sofia_host}"

display_url: "https://#{Rails.application.config.x.sofia_host}",
executable_path: '/usr/bin/chromium',
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The hardcoded executable path /usr/bin/chromium will break local development environments where developers might have Chromium installed in different locations (e.g., macOS users would have it in a different path). Consider making this path configurable based on the environment, or allowing Grover to auto-detect the executable in development/test environments while only setting it explicitly for production/staging.

Copilot uses AI. Check for mistakes.

display_url: "https://#{Rails.application.config.x.sofia_host}",
executable_path: '/usr/bin/chromium',
launch_args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The --no-sandbox and --disable-setuid-sandbox flags reduce the security isolation of the Chromium process. While these are often necessary in containerized environments, they should ideally be configured only for production/staging environments and not applied globally. Consider making these launch arguments environment-specific to maintain better security in development and test environments.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@config/initializers/grover.rb`:
- Around line 16-18: The Grover init currently sets executable_path and
launch_args with sandbox-disabling flags unconditionally; change this so the
sandbox-disable flags
('--no-sandbox','--disable-setuid-sandbox','--disable-dev-shm-usage') are only
added when an environment toggle (e.g. ENV['GROVER_DISABLE_SANDBOX'] or
ENV.fetch('GROVER_ALLOW_NO_SANDBOX','false')) is truthy. Update the initializer
that builds the Grover config (the hash with display_url, executable_path,
launch_args) to compute launch_args conditionally: use a safe default (empty or
minimal flags) and append the sandbox-disable flags only when the env toggle is
enabled, and document/validate the env var where appropriate.

Comment on lines 16 to 18
display_url: "https://#{Rails.application.config.x.sofia_host}",
executable_path: '/usr/bin/chromium',
launch_args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find the grover initializer and understand context
fd -name "grover.rb" -o -name "Gemfile*" | head -20

Repository: csvalpha/sofia

Length of output: 288


🌐 Web query:

Grover 1.2.4 documentation configuration options executable_path launch_args

💡 Result:

Grover accepts Puppeteer/Chromium launch configuration via options — two relevant ones:

  • executable_path: path to the Chrome/Chromium binary used by Puppeteer. Set this to the absolute path Puppeteer/Chromium should run (useful when system Chrome/AppArmor or a custom Puppeteer-managed binary must be pointed at explicitly). [1][2]

  • launch_args: array of Chromium command-line switches (strings) passed to the browser when launched (e.g. ['--no-sandbox','--disable-features=HttpsUpgrades']). You may also supply launch_args via meta tags in HTML. See Chromium switch docs for available flags. [1][2]

Example (initializer or per-instance):

  • global config (initializer)
    Grover.configure do |config|
    config.options = {
    executable_path: '/usr/bin/chromium-browser',
    launch_args: ['--no-sandbox', '--disable-features=HttpsUpgrades']
    }
    end
  • per-instance
    grover = Grover.new(html_or_url, executable_path: '/usr/bin/chromium-browser', launch_args: ['--no-sandbox'])

References:
[1] Studiosity/grover README (GitHub).
[2] Grover 1.2.4 API docs (RubyDoc).


🏁 Script executed:

# Search for how Grover is being used in the codebase
rg -i "grover" --type rb -A 3 -B 3 | head -100

Repository: csvalpha/sofia

Length of output: 84


🏁 Script executed:

# Look for Docker or deployment files that might reference chromium
fd -name "Dockerfile*" -o -name "docker-compose*" -o -name ".dockerignore" | xargs cat 2>/dev/null || echo "No Docker files found"

Repository: csvalpha/sofia

Length of output: 288


🏁 Script executed:

# Check if there are any references to untrusted content or HTML rendering
rg -i "html|render|untrusted|pdf" config/initializers/ -A 2 -B 2

Repository: csvalpha/sofia

Length of output: 13457


🏁 Script executed:

cat config/initializers/grover.rb

Repository: csvalpha/sofia

Length of output: 739


🏁 Script executed:

# Look for Docker files more carefully
find . -type f \( -name "Dockerfile*" -o -name "*.dockerfile" -o -name "docker-compose*.yml" -o -name "docker-compose*.yaml" \)

Repository: csvalpha/sofia

Length of output: 91


🏁 Script executed:

# Search for how grover is being called to understand what content is rendered
rg "Grover.new|grover\(" --type rb -B 3 -A 5 | head -60

Repository: csvalpha/sofia

Length of output: 84


🏁 Script executed:

# Check if there's a .env or similar that might configure chromium paths
find . -type f \( -name ".env*" -o -name "*.env" \) 2>/dev/null | head -10

Repository: csvalpha/sofia

Length of output: 72


🏁 Script executed:

cat Dockerfile

Repository: csvalpha/sofia

Length of output: 1645


🏁 Script executed:

cat docker-compose.yml

Repository: csvalpha/sofia

Length of output: 1015


🏁 Script executed:

# Search for Grover usage without -t rb type
rg "Grover.new" -B 3 -A 5

Repository: csvalpha/sofia

Length of output: 2132


🏁 Script executed:

# Also search for .render_pdf or similar methods that call grover
rg "render.*pdf|grover.*render" -i -B 2 -A 5

Repository: csvalpha/sofia

Length of output: 1856


Consider gating sandbox-disable flags behind an environment toggle.

Grover 1.2.4 does recognize executable_path and launch_args, and /usr/bin/chromium is correctly available in the Docker image (installed via apt-get). The configuration is valid and functional. However, the current setup disables Chromium's sandbox globally for all environments. While your code today only renders internal application templates (via invoices/show), it's good practice to make sandbox-disable opt-in via an environment variable to preserve the security boundary for use cases that don't require it.

♻️ Example: make sandbox-disable opt-in via env
-    launch_args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
+    launch_args: begin
+      args = ['--disable-dev-shm-usage']
+      args += ['--no-sandbox', '--disable-setuid-sandbox'] if ENV['CHROMIUM_NO_SANDBOX'] == '1'
+      args
+    end
🤖 Prompt for AI Agents
In `@config/initializers/grover.rb` around lines 16 - 18, The Grover init
currently sets executable_path and launch_args with sandbox-disabling flags
unconditionally; change this so the sandbox-disable flags
('--no-sandbox','--disable-setuid-sandbox','--disable-dev-shm-usage') are only
added when an environment toggle (e.g. ENV['GROVER_DISABLE_SANDBOX'] or
ENV.fetch('GROVER_ALLOW_NO_SANDBOX','false')) is truthy. Update the initializer
that builds the Grover config (the hash with display_url, executable_path,
launch_args) to compute launch_args conditionally: use a safe default (empty or
minimal flags) and append the sandbox-disable flags only when the env toggle is
enabled, and document/validate the env var where appropriate.

@codecov
Copy link

codecov bot commented Jan 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.08%. Comparing base (fb90056) to head (1f0a18f).
⚠️ Report is 1 commits behind head on staging.

Additional details and impacted files
@@           Coverage Diff            @@
##           staging    #1208   +/-   ##
========================================
  Coverage    77.08%   77.08%           
========================================
  Files           54       54           
  Lines         1370     1370           
========================================
  Hits          1056     1056           
  Misses         314      314           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lodewiges lodewiges merged commit d3da56d into staging Jan 17, 2026
6 checks passed
@lodewiges lodewiges deleted the hotfix/pdf-generation branch January 17, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants