Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
b70a34b
Merge pull request #1898 from GSA/feature/rust-widget-renderer
rileyseaburg Nov 20, 2025
539f661
Tighten ignore for env/vars files
rileyseaburg Nov 21, 2025
bb3cd67
Look for widget artifact in workspace target dir
rileyseaburg Nov 21, 2025
8af0c02
Fix widget build script app root detection
rileyseaburg Nov 21, 2025
2db8e84
Make widget build script locate ext directory flexibly
rileyseaburg Nov 21, 2025
51bbc6a
Link rutie against shared ruby in runtime build
rileyseaburg Nov 21, 2025
36b2721
Avoid rutie static link; skip linking when building at runtime
rileyseaburg Nov 21, 2025
a80e494
Prefer cached Rust toolchain in runtime build
rileyseaburg Nov 21, 2025
2eaaf05
Ensure widget .so is included in CF bits
rileyseaburg Nov 21, 2025
6143f92
Copy shipped widget .so into target/release at runtime
rileyseaburg Nov 21, 2025
fa7dbbe
Let Rutie define WidgetRenderer (drop Ruby module wrapper)
rileyseaburg Nov 22, 2025
d598548
Load widget renderer from lib/widget_renderer
rileyseaburg Nov 22, 2025
8d0bbd1
Remove stale WidgetRenderer module before Rutie init
rileyseaburg Nov 22, 2025
936da01
Guard WidgetRenderer constant as class before Rutie init
rileyseaburg Nov 22, 2025
a23cc09
Allow app-staging host in staging manifest
rileyseaburg Nov 22, 2025
1fa69f2
Use app-staging as asset host to satisfy SRI
rileyseaburg Nov 22, 2025
c1ecb52
Scope session cookie domain via optional env
rileyseaburg Nov 22, 2025
d98161b
Point LOGIN_GOV_REDIRECT_URI to app-staging host
rileyseaburg Nov 22, 2025
9c96767
Pass question text field to Rust renderer
rileyseaburg Nov 22, 2025
faf7e69
Clean up cx collections export tests and fix service csv list
rileyseaburg Nov 22, 2025
b420feb
Merge branch 'feature/rust-widget-renderer' into develop
rileyseaburg Nov 22, 2025
4580b73
Bump Ruby to 3.4.7
rileyseaburg Nov 24, 2025
6cc6804
Build Rust widget renderer in CircleCI
rileyseaburg Nov 24, 2025
4b566d9
Use cargo build for widget renderer in CI
rileyseaburg Nov 24, 2025
8ff23e8
Coerce nil booleans before calling Rust renderer
rileyseaburg Nov 24, 2025
2dfa28e
Skip Rust widget renderer in test env to stabilize specs
rileyseaburg Nov 24, 2025
0c32cce
Default element_selector for widget renderer
rileyseaburg Nov 24, 2025
609891d
Stabilize form permissions spec expectations
rileyseaburg Nov 24, 2025
c6fe6d2
Revert Ruby target to 3.2.8 for CF buildpack
rileyseaburg Nov 24, 2025
1b0c575
Use prebuilt widget renderer .so before compiling at runtime
rileyseaburg Nov 24, 2025
b92b49b
Fix widget renderer build artifact detection
rileyseaburg Nov 24, 2025
0081849
Make widget renderer tolerate null booleans
rileyseaburg Nov 24, 2025
d48eeb4
Add logging and extra fallback for widget renderer .so in pre-start
rileyseaburg Nov 24, 2025
cf2a312
Allow widget renderer pre-start to build if no prebuilt lib
rileyseaburg Nov 24, 2025
0395cf6
Set HOME to /home/vcap before building widget renderer
rileyseaburg Nov 24, 2025
fc0ebbe
Harden widget renderer runtime build paths
rileyseaburg Nov 24, 2025
42d9cc4
Trigger CircleCI deploy
rileyseaburg Nov 24, 2025
21c7ccf
Guard CF deploy steps to a single parallel node
rileyseaburg Nov 24, 2025
16004a5
Precompile done.svg so the landing page renders
rileyseaburg Nov 24, 2025
1bea5e4
Link done.svg in manifest and clean precompile entry
rileyseaburg Nov 24, 2025
ee4a044
Allow asset fallback in staging
rileyseaburg Nov 24, 2025
4203ce3
Enable Rack::Attack middleware
rileyseaburg Nov 24, 2025
12b0b2f
Stabilize digital product create feature spec
rileyseaburg Nov 24, 2025
2e448c4
Loosen digital product path assertion
rileyseaburg Nov 24, 2025
82b503d
Avoid runtime Rust build in widget renderer
rileyseaburg Nov 24, 2025
2c78f55
Increase memory allocation to 2G for Rust widget renderer
rileyseaburg Nov 25, 2025
273f1d0
Fix SRI CORS issue by adding crossorigin attribute to asset tags
rileyseaburg Nov 25, 2025
54b8531
Add CORS headers for static assets to support SRI cross-origin requests
rileyseaburg Nov 25, 2025
2af401e
Add prebuilt Linux libwidget_renderer.so for Cloud Foundry deployment
rileyseaburg Nov 25, 2025
051deb6
Add debug logging for WidgetRenderer initialization
rileyseaburg Nov 25, 2025
73380ed
Add debugging output to widget_renderer.rb
rileyseaburg Dec 1, 2025
0480a2b
Fix: Copy library to expected location when found in workspace target…
rileyseaburg Dec 1, 2025
d3e0271
Fix: Set LD_LIBRARY_PATH for libruby.so at runtime on Cloud Foundry
rileyseaburg Dec 1, 2025
6a9cac1
Fix flaky test: explicitly set service to twitter for digital_service…
rileyseaburg Dec 1, 2025
3596c94
Add retry logic to CF deploy scripts to handle staging race conditions
rileyseaburg Dec 1, 2025
e7b114a
Add deployment wait logic to prevent CF supersession errors
rileyseaburg Dec 1, 2025
3475fe0
Add CF env-based deploy lock to serialize concurrent pipelines
rileyseaburg Dec 1, 2025
14288a9
Build Rust extension at runtime on CF to fix libruby.so linking
rileyseaburg Dec 1, 2025
e304dff
Check library linkage before using - rebuild if libruby not found
rileyseaburg Dec 1, 2025
0768a3b
Merge pull request #1888 from GSA/develop
rileyseaburg Dec 1, 2025
2f0c4ae
Add Cargo caching and library linkage verification to CircleCI
rileyseaburg Dec 1, 2025
decad73
Fix cx_collections export_csv 500 error
rileyseaburg Dec 10, 2025
446fc3c
Update schema.rb with new indexes for CircleCI
rileyseaburg Dec 10, 2025
2a919af
Update schema version to include new migration
rileyseaburg Dec 10, 2025
39a848c
Add tests for User#cx_collections method
rileyseaburg Dec 11, 2025
91a8a15
Production release: Fix CX Collections export CSV error (#1911)
rileyseaburg Dec 11, 2025
fea936d
fix: use git URL for rust buildpack in production manifest
rileyseaburg Dec 11, 2025
df21164
fix: correct redis service name in production manifest
rileyseaburg Dec 11, 2025
f376cab
Fix widget renderer load when native lib missing (#1913)
rileyseaburg Dec 15, 2025
1a85d02
Release: WidgetRenderer load fix (#1914)
rileyseaburg Dec 15, 2025
2b1fb3a
Fix User#cx_collections specs for Service owner (#1915)
rileyseaburg Dec 15, 2025
4a17475
Fix User#cx_collections specs for Service owner (#1915) (#1917)
rileyseaburg Dec 15, 2025
bbcb0ac
Fix production manifest for rust buildpack (#1918)
rileyseaburg Dec 18, 2025
b304af6
Release: set prod disk quota to 2G (#1919)
rileyseaburg Dec 18, 2025
0befb69
fix: remove empty secret keys from manifest to prevent wiping env var…
rileyseaburg Dec 18, 2025
9dd5ae4
fix: Use fba-usa-modal class for USWDS Modal compatibility
rileyseaburg Dec 18, 2025
c75835b
fix: Add CSS support to Rust widget renderer to fix modal positioning
rileyseaburg Dec 18, 2025
e37e530
fix: Use parent_id instead of parent in Organization factory
rileyseaburg Dec 18, 2025
d073960
Increase Cloud Foundry start timeout to 180s and fix Sidekiq health c…
rileyseaburg Dec 19, 2025
96a834b
Fix Sidekiq crash and optimize Rust build script
rileyseaburg Dec 19, 2025
17c5edb
build(cf): simplify widget_renderer build script and ignore rules
rileyseaburg Dec 19, 2025
4a038a7
Increase deployment timeout and add widget_renderer fallback to resol…
rileyseaburg Dec 19, 2025
20ba1df
fix(widget_renderer): restore LoadError and adjust app timeout
rileyseaburg Dec 19, 2025
00aae42
ci: increase deployment wait time and enable static files in dev
rileyseaburg Dec 19, 2025
bec0f54
ci(deploy): increase timeouts and enable static file serving
rileyseaburg Dec 19, 2025
c31ee4d
Decouple db:migrate from deploy: migrations must be run separately to…
rileyseaburg Dec 19, 2025
a5513bd
Add automated pre-deploy migrations via cf run-task to avoid 180s tim…
rileyseaburg Dec 19, 2025
63126ac
Set health check type to process for sidekiq worker before rolling de…
rileyseaburg Dec 19, 2025
7b1902e
Fix sidekiq worker timeout: explicitly set to 180s before rolling deploy
rileyseaburg Dec 19, 2025
8c589a3
Fix flaky logo upload test: add wait time to prevent Selenium stale e…
rileyseaburg Dec 19, 2025
6694a60
Fix cf set-health-check: use --invocation-timeout instead of --timeout
rileyseaburg Dec 19, 2025
33aa4ca
Fix Rack::Attack test: create actual form fixture to avoid 404 responses
rileyseaburg Dec 19, 2025
48b4e42
Scale sidekiq worker to 1 instance during rolling deploy to avoid org…
rileyseaburg Dec 19, 2025
6cbc40a
Stop sidekiq worker before push to free memory for staging (avoids or…
rileyseaburg Dec 19, 2025
e654f1a
Fix cf run-task syntax: add --command flag for migrations
rileyseaburg Dec 19, 2025
b17086f
Skip WidgetRenderer load during migrations - library not built in tas…
rileyseaburg Dec 19, 2025
4bd89c1
Fix Rack::Attack test: add valid submission params to avoid 400 errors
rileyseaburg Dec 19, 2025
0979b8e
Temporarily disable pre-deploy migrations to unblock deployment
rileyseaburg Dec 19, 2025
2f19ac3
Fix widget_renderer initializer - use simpler skip detection logic
rileyseaburg Dec 19, 2025
572ce1c
Fix deployment: restore db:migrate in manifest and enable migrations …
rileyseaburg Dec 19, 2025
0ad8705
Revert migrations to start command - Rust library not available in cf…
rileyseaburg Dec 19, 2025
f1dd1e6
Build Rust library at runtime in .profile.d script
rileyseaburg Dec 19, 2025
a3b3e3b
Revert to working widget_renderer script that copies prebuilt library
rileyseaburg Dec 19, 2025
3ae31df
Keep prebuilt Rust library during deployment to ensure correct linkin…
rileyseaburg Dec 19, 2025
92b1f75
Fix deploy-sidekiq.sh: remove explicit buildpack flags to avoid re-in…
rileyseaburg Dec 19, 2025
722f8e5
Fix touchpoints.yml: comment out buildpacks to prevent Rust reinstall…
rileyseaburg Dec 19, 2025
d632d21
Fix flaky timing test in submission_digest mailer spec
rileyseaburg Dec 19, 2025
875cb7b
Fix custom-button-modal USWDS initialization
rileyseaburg Dec 19, 2025
4b11274
Bump Cargo version to force Rust rebuild
rileyseaburg Dec 19, 2025
3ee1dda
Bump widget_renderer version to force Cargo rebuild
rileyseaburg Dec 19, 2025
24b0e26
Force cargo clean before build to ensure recompilation
rileyseaburg Dec 19, 2025
93f4271
Bump widget_renderer gem version to 0.1.2 to force rebuild
rileyseaburg Dec 19, 2025
05fb5a0
Force Rust rebuild with BUILD_ID and version bump
rileyseaburg Dec 19, 2025
32df1a1
Bump widget_renderer to 0.1.2 to force CF to rebuild native extension
rileyseaburg Dec 19, 2025
763a305
Update Gemfile.lock for widget_renderer 0.1.2
rileyseaburg Dec 19, 2025
45d9661
Add Rust library verification before CF push
rileyseaburg Dec 19, 2025
513bf2b
Prioritize workspace-level Rust library and bump to 0.1.3
rileyseaburg Dec 19, 2025
3125b91
Invalidate CircleCI cargo cache to force fresh Rust build
rileyseaburg Dec 19, 2025
35b2d51
Fix Rust widget renderer modal button initialization (#1924)
rileyseaburg Dec 22, 2025
b07fa59
Address PR #1925 feedback
rileyseaburg Dec 22, 2025
f6b5555
Fix empty string check for customButtonSelector
rileyseaburg Dec 22, 2025
92d4e38
Merge pull request #1926 from GSA/fix/pr-1925-feedback
rileyseaburg Dec 22, 2025
edc19e4
Merge production into develop to resolve PR #1925 conflicts
rileyseaburg Dec 22, 2025
08faf20
Fix flaky inline title edit test by waiting for AJAX to complete
rileyseaburg Dec 22, 2025
d5a596b
Add post-mortem for widget modal button incident (Dec 2025)
rileyseaburg Dec 22, 2025
c653d1b
Revert "Add post-mortem for widget modal button incident (Dec 2025)"
rileyseaburg Dec 22, 2025
6845520
Merge pull request #1925 from GSA/develop
rileyseaburg Dec 22, 2025
557f3a5
Fix deploy script rolling deployment timeout issue
rileyseaburg Dec 22, 2025
574de74
Merge pull request #1927 from GSA/develop
rileyseaburg Dec 22, 2025
c3cf39c
Bust Cargo cache to force Rust widget rebuild (v2 -> v3)
rileyseaburg Dec 22, 2025
ed37d83
Merge pull request #1928 from GSA/develop
rileyseaburg Dec 22, 2025
a69e34f
Update Cargo.lock to force cache invalidation and Rust rebuild
rileyseaburg Dec 22, 2025
d599a61
Merge pull request #1929 from GSA/develop
rileyseaburg Dec 22, 2025
dbd4605
Fix Cargo cache key to include source file checksum (v3 -> v4)
rileyseaburg Dec 22, 2025
84b1031
Merge pull request #1930 from GSA/develop
rileyseaburg Dec 22, 2025
3f6bf55
Update buildpack to force clean Rust builds (commit b073e44)
rileyseaburg Dec 22, 2025
c3e3fef
Remove pre-compiled Rust binaries to force fresh build on CF
rileyseaburg Dec 22, 2025
8c3bf7d
Add DISABLE_RUST_RENDERER env var to force ERB fallback
rileyseaburg Dec 22, 2025
adc4305
Fix cf-cli download URL to use direct GitHub release URL
rileyseaburg Dec 22, 2025
9ecb049
Fix cf-cli installation using APT repository instead of direct download
rileyseaburg Dec 22, 2025
f527d3b
Update .circleci/config.yml
rileyseaburg Dec 22, 2025
03fd10d
Update .circleci/config.yml
rileyseaburg Dec 22, 2025
324730f
Merge pull request #1932 from GSA/fix/cf-cli-apt-install
rileyseaburg Dec 22, 2025
6626b3f
Add missing touchpoints-s3-uploads service binding to manifest
rileyseaburg Dec 23, 2025
8b654bb
Merge pull request #1933 from GSA/develop
rileyseaburg Dec 23, 2025
ff76f6b
Fix CF CLI GPG key installation for modern apt
rileyseaburg Dec 23, 2025
7a7f668
Merge pull request #1934 from GSA/develop
rileyseaburg Dec 23, 2025
6baf5ca
Add SKIP_WIDGET_RENDERER to manifests to prevent env var removal on d…
rileyseaburg Dec 23, 2025
7779a14
Merge pull request #1935 from GSA/develop
rileyseaburg Dec 23, 2025
375dde5
Add SKIP_WIDGET_RENDERER check at gem load time to prevent crash
rileyseaburg Dec 23, 2025
194e0fa
Merge pull request #1936 from GSA/develop
rileyseaburg Dec 23, 2025
cc7e07a
Update post-mortem with Dec 23 production outage details
rileyseaburg Dec 23, 2025
0772ff2
Add 2026 to fiscal year dropdown for CX data collections
rileyseaburg Jan 9, 2026
c085a0c
Fix timezone test to use current year date for format_submission_time
rileyseaburg Jan 9, 2026
7a4a65a
Merge pull request #1942 from GSA/add-fiscal-year-2026
rileyseaburg Jan 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .cfignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
/public/packs-test
/node_modules

# Ignore Rust build artifacts
# Ignore Rust build artifacts, but keep the prebuilt widget library
target/
ext/widget_renderer/target/

Copilot AI Nov 22, 2025

Copy link

Choose a reason for hiding this comment

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

The negation pattern on line 44 won't work as intended because line 43 already ignores the parent directory ext/widget_renderer/target/. In gitignore-style patterns, once a parent directory is ignored, you cannot un-ignore it with a negation pattern before un-ignoring its contents.

Consider removing line 43 (ext/widget_renderer/target/) and keeping only line 42 (target/) which already covers this path. The specific negations on lines 45-46 should then work correctly.

Suggested change
ext/widget_renderer/target/

Copilot uses AI. Check for mistakes.
!ext/widget_renderer/target/
!ext/widget_renderer/target/release/
!ext/widget_renderer/target/release/libwidget_renderer.so
!ext/widget_renderer/libwidget_renderer.so
17 changes: 12 additions & 5 deletions .github/workflows/build-widget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@ jobs:
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: x86_64-unknown-linux-gnu
override: true

- name: Build widget (Linux .so)
working-directory: ext/widget_renderer
run: cargo build --release --target x86_64-unknown-linux-gnu
run: cargo build --release

- name: Prepare artifact for CF
run: |
mkdir -p ext/widget_renderer/target/release
cp ext/widget_renderer/target/x86_64-unknown-linux-gnu/release/libwidget_renderer.so ext/widget_renderer/
cp ext/widget_renderer/target/x86_64-unknown-linux-gnu/release/libwidget_renderer.so ext/widget_renderer/target/release/
set -euo pipefail
mkdir -p ext/widget_renderer/target/release target/release
artifact=$(find target ext/widget_renderer/target -maxdepth 4 -name 'libwidget_renderer*.so' 2>/dev/null | head -n 1 || true)
if [ -z "${artifact}" ]; then
echo "No built libwidget_renderer.so found. Current target tree:"
find target ext/widget_renderer/target -maxdepth 4 -type f | sed 's/^/ /'
exit 1
fi
echo "Using artifact: ${artifact}"
cp "${artifact}" ext/widget_renderer/libwidget_renderer.so
cp "${artifact}" ext/widget_renderer/target/release/libwidget_renderer.so

- name: Upload artifact
uses: actions/upload-artifact@v4
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
# Don't check in these things
.env
.env.development
.env.*
.manifest.yml
.csv
vars.yml
vars*.yml

# For Macs
.DS_Store
Expand Down
35 changes: 33 additions & 2 deletions .profile.d/build_widget_renderer.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail

APP_ROOT="${HOME}/app"
EXT_DIR="${APP_ROOT}/ext/widget_renderer"
if [ -d "${HOME}/ext/widget_renderer" ]; then
EXT_DIR="${HOME}/ext/widget_renderer"
elif [ -d "${HOME}/app/ext/widget_renderer" ]; then
EXT_DIR="${HOME}/app/ext/widget_renderer"
else
echo "===> widget_renderer: extension directory not found under HOME: ${HOME}"
exit 1
fi
LIB_SO="${EXT_DIR}/libwidget_renderer.so"
LIB_DYLIB="${EXT_DIR}/libwidget_renderer.dylib"

echo "===> widget_renderer: checking for native library"

# Ensure target/release has the library if it's already present at the root.
if [ -f "$LIB_SO" ]; then
mkdir -p "${EXT_DIR}/target/release"
cp "$LIB_SO" "${EXT_DIR}/target/release/libwidget_renderer.so"
fi

# Build the Rust extension at runtime if the shared library is missing.
if [ ! -f "$LIB_SO" ] && [ ! -f "$LIB_DYLIB" ]; then
echo "===> widget_renderer: building native extension"

# Ensure Cargo toolchain from the Rust buildpack is used (avoid reinstall).
if [ -z "${CARGO_HOME:-}" ] && [ -d "/home/vcap/deps/0/rust/cargo" ]; then
export CARGO_HOME="/home/vcap/deps/0/rust/cargo"
fi
if [ -z "${RUSTUP_HOME:-}" ] && [ -d "/home/vcap/deps/0/rust/rustup" ]; then
export RUSTUP_HOME="/home/vcap/deps/0/rust/rustup"
fi
echo "===> widget_renderer: CARGO_HOME=${CARGO_HOME:-unset}"
echo "===> widget_renderer: RUSTUP_HOME=${RUSTUP_HOME:-unset}"

# Tell rutie to link against the shared Ruby library provided by the Ruby buildpack.
RUBY_LIB_PATH=$(ruby -e 'require "rbconfig"; print RbConfig::CONFIG["libdir"]')
RUBY_SO_NAME=$(ruby -e 'require "rbconfig"; print RbConfig::CONFIG["RUBY_SO_NAME"]')
export RUTIE_RUBY_LIB_PATH="$RUBY_LIB_PATH"
export RUTIE_RUBY_LIB_NAME="$RUBY_SO_NAME"
unset RUBY_STATIC
export NO_LINK_RUTIE=1

cd "$EXT_DIR"
ruby extconf.rb
make
Expand Down
2 changes: 1 addition & 1 deletion app/models/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def touchpoints_js_string
'form-header-logo-square'
end
end,
questions: ordered_questions.map { |q| { answer_field: q.answer_field, question_type: q.question_type, question_text: q.question_text, is_required: q.is_required } },
questions: ordered_questions.map { |q| { answer_field: q.answer_field, question_type: q.question_type, question_text: q.text, is_required: q.is_required } },
}
json = form_hash.to_json
puts "DEBUG: JSON class: #{json.class}"
Expand Down
16 changes: 8 additions & 8 deletions app/models/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ def self.to_csv
organization_name organization_abbreviation service_provider_id service_provider_name service_provider_slug
] - %w[
channels
budget_code
uii_code
non_digital_explanation
homepage_url
digital_service
estimated_annual_volume_of_customers
fully_digital_service
barriers_to_fully_digital_service
budget_code
uii_code
non_digital_explanation
homepage_url
digital_service
estimated_annual_volume_of_customers
fully_digital_service
barriers_to_fully_digital_service
multi_agency_service
multi_agency_explanation
other_service_type
Expand Down
3 changes: 2 additions & 1 deletion config/environments/staging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@

# Prevent host header injection
# Reference: https://github.com/ankane/secure_rails
config.action_controller.asset_host = ENV.fetch('TOUCHPOINTS_WEB_DOMAIN')
asset_host = ENV.fetch('ASSET_HOST', nil)
config.action_controller.asset_host = asset_host.presence || ENV.fetch('TOUCHPOINTS_WEB_DOMAIN')

config.action_mailer.delivery_method = :ses_v2
config.action_mailer.ses_v2_settings = {
Expand Down
7 changes: 6 additions & 1 deletion config/initializers/session_store.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# frozen_string_literal: true

Rails.application.config.session_store :cookie_store, key: '_touchpoints_session', domain: ENV.fetch('TOUCHPOINTS_WEB_DOMAIN'), same_site: :lax, expire_after: 30.minutes
cookie_domain = ENV['SESSION_COOKIE_DOMAIN'].presence

Copilot AI Nov 22, 2025

Copy link

Choose a reason for hiding this comment

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

The SESSION_COOKIE_DOMAIN environment variable is not defined in touchpoints-staging.yml, which means cookie_domain will be nil. This changes the cookie domain behavior from the previous explicit value (ENV.fetch('TOUCHPOINTS_WEB_DOMAIN')). A nil domain makes the cookie available only to the current host without subdomains.

Consider either:

  1. Adding SESSION_COOKIE_DOMAIN to the environment configuration in touchpoints-staging.yml, or
  2. Providing a fallback: cookie_domain = ENV['SESSION_COOKIE_DOMAIN'].presence || ENV.fetch('TOUCHPOINTS_WEB_DOMAIN')
Suggested change
cookie_domain = ENV['SESSION_COOKIE_DOMAIN'].presence
cookie_domain = ENV['SESSION_COOKIE_DOMAIN'].presence || ENV.fetch('TOUCHPOINTS_WEB_DOMAIN')

Copilot uses AI. Check for mistakes.
Rails.application.config.session_store :cookie_store,
key: '_touchpoints_session',
domain: cookie_domain,
same_site: :lax,
expire_after: 30.minutes
4 changes: 2 additions & 2 deletions config/initializers/widget_renderer.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Load the Rust widget renderer extension
begin
# Try loading from the extension directory
require_relative '../../ext/widget_renderer/widget_renderer'
require_relative '../../ext/widget_renderer/lib/widget_renderer'
rescue LoadError => e
Rails.logger.warn "Widget renderer extension not available: #{e.message}"
# Attempt to build the Rust extension on the fly (installs Rust via extconf if needed)
Expand All @@ -11,7 +11,7 @@
Dir.chdir(ext_dir) do
system('ruby extconf.rb') && system('make')
end
require_relative '../../ext/widget_renderer/widget_renderer'
require_relative '../../ext/widget_renderer/lib/widget_renderer'
Rails.logger.info 'Successfully compiled widget_renderer extension at runtime.'
rescue StandardError => build_error
Rails.logger.warn "Widget renderer build failed: #{build_error.class}: #{build_error.message}"
Expand Down
145 changes: 75 additions & 70 deletions ext/widget_renderer/lib/widget_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,90 @@

require 'rutie'

module WidgetRenderer
root = File.expand_path('..', __dir__)
root = File.expand_path('..', __dir__)

# Debugging: Print root and directory contents
puts "WidgetRenderer: root=#{root}"
puts "WidgetRenderer: __dir__=#{__dir__}"
# Debugging: Print root and directory contents
puts "WidgetRenderer: root=#{root}"
puts "WidgetRenderer: __dir__=#{__dir__}"

# Define potential paths where the shared object might be located
paths = [
File.join(root, 'target', 'release'),
File.expand_path('../../target/release', root), # Workspace target directory
File.join(root, 'widget_renderer', 'target', 'release'),
File.join(root, 'target', 'debug'),
File.expand_path('../../target/debug', root), # Workspace debug directory
File.join(root, 'widget_renderer', 'target', 'debug'),
root,
]
# If a stale module exists, remove it so Rutie can define or reopen the class.
if defined?(WidgetRenderer) && WidgetRenderer.is_a?(Module) && !WidgetRenderer.is_a?(Class)
Object.send(:remove_const, :WidgetRenderer)
end
# Ensure the constant exists as a Class so rb_define_class will reopen it instead of erroring on Module.
WidgetRenderer = Class.new unless defined?(WidgetRenderer) && WidgetRenderer.is_a?(Class)

# Find the first path that contains the library file
found_path = paths.find do |p|
exists = File.exist?(File.join(p, 'libwidget_renderer.so')) ||
File.exist?(File.join(p, 'libwidget_renderer.bundle')) ||
File.exist?(File.join(p, 'libwidget_renderer.dylib'))
puts "WidgetRenderer: Checking #{p} -> #{exists}"
exists
end
# Define potential paths where the shared object might be located
paths = [
File.join(root, 'target', 'release'),
File.expand_path('../../target/release', root), # Workspace target directory
File.join(root, 'widget_renderer', 'target', 'release'),
File.join(root, 'target', 'debug'),
File.expand_path('../../target/debug', root), # Workspace debug directory
File.join(root, 'widget_renderer', 'target', 'debug'),
root,
]

# Find the first path that contains the library file
found_path = paths.find do |p|
exists = File.exist?(File.join(p, 'libwidget_renderer.so')) ||
File.exist?(File.join(p, 'libwidget_renderer.bundle')) ||
File.exist?(File.join(p, 'libwidget_renderer.dylib'))
puts "WidgetRenderer: Checking #{p} -> #{exists}"
exists
end

if found_path
puts "WidgetRenderer: Found library in #{found_path}"

# Debug: Check dependencies
lib_file = File.join(found_path, 'libwidget_renderer.so')
if File.exist?(lib_file)
puts "WidgetRenderer: File details for #{lib_file}"
puts `ls -l #{lib_file}`
puts `file #{lib_file}`
puts "WidgetRenderer: Running ldd on #{lib_file}"
puts `ldd #{lib_file} 2>&1`
end
if found_path
puts "WidgetRenderer: Found library in #{found_path}"

# Debug: Check dependencies
lib_file = File.join(found_path, 'libwidget_renderer.so')
if File.exist?(lib_file)
puts "WidgetRenderer: File details for #{lib_file}"
puts `ls -l #{lib_file}`
puts `file #{lib_file}`
puts "WidgetRenderer: Running ldd on #{lib_file}"
puts `ldd #{lib_file} 2>&1`
end
else
puts 'WidgetRenderer: Library not found in any checked path. Listing root contents:'
# List files in root to help debug
Dir.glob(File.join(root, '*')).each { |f| puts f }

puts 'WidgetRenderer: Listing target contents:'
target_dir = File.join(root, 'target')
if Dir.exist?(target_dir)
Dir.glob(File.join(target_dir, '*')).each { |f| puts f }
else
puts 'WidgetRenderer: Library not found in any checked path. Listing root contents:'
# List files in root to help debug
Dir.glob(File.join(root, '*')).each { |f| puts f }

puts 'WidgetRenderer: Listing target contents:'
target_dir = File.join(root, 'target')
if Dir.exist?(target_dir)
Dir.glob(File.join(target_dir, '*')).each { |f| puts f }
else
puts "WidgetRenderer: target directory does not exist at #{target_dir}"
end
puts "WidgetRenderer: target directory does not exist at #{target_dir}"
end

puts 'WidgetRenderer: Listing target/release contents:'
release_dir = File.join(root, 'target', 'release')
if Dir.exist?(release_dir)
Dir.glob(File.join(release_dir, '*')).each { |f| puts f }
else
puts "WidgetRenderer: target/release directory does not exist at #{release_dir}"
end
puts 'WidgetRenderer: Listing target/release contents:'
release_dir = File.join(root, 'target', 'release')
if Dir.exist?(release_dir)
Dir.glob(File.join(release_dir, '*')).each { |f| puts f }
else
puts "WidgetRenderer: target/release directory does not exist at #{release_dir}"
end
end

# Default to root if not found (Rutie might have its own lookup)
path = found_path || root
# Default to root if not found (Rutie might have its own lookup)
path = found_path || root

# Rutie expects the project root, not the directory containing the library.
# It appends /target/release/lib<name>.so to the path.
# So if we found it in .../target/release, we need to strip that part.
if path.end_with?('target/release')
path = path.sub(%r{/target/release$}, '')
elsif path.end_with?('target/debug')
path = path.sub(%r{/target/debug$}, '')
end
# Rutie expects the project root, not the directory containing the library.
# It appends /target/release/lib<name>.so to the path.
# So if we found it in .../target/release, we need to strip that part.
if path.end_with?('target/release')
path = path.sub(%r{/target/release$}, '')
elsif path.end_with?('target/debug')
path = path.sub(%r{/target/debug$}, '')
end

# Rutie assumes the passed path is a subdirectory (like lib/) and goes up one level
# before appending target/release.
# So we append a 'lib' directory so that when it goes up, it lands on the root.
path = File.join(path, 'lib')
# Rutie assumes the passed path is a subdirectory (like lib/) and goes up one level
# before appending target/release.
# So we append a 'lib' directory so that when it goes up, it lands on the root.
path = File.join(path, 'lib')

puts "WidgetRenderer: Initializing Rutie with path: #{path}"
puts "WidgetRenderer: Initializing Rutie with path: #{path}"

Rutie.new(:widget_renderer).init 'Init_widget_renderer', path
end
Rutie.new(:widget_renderer).init 'Init_widget_renderer', path
50 changes: 0 additions & 50 deletions spec/controllers/admin/cx_collections_controller_export_spec.rb

This file was deleted.

Loading
Loading