diff --git a/.github/workflows/run-end-to-end.yml b/.github/workflows/run-end-to-end.yml
index 8b879285f7..91bc1d5c31 100644
--- a/.github/workflows/run-end-to-end.yml
+++ b/.github/workflows/run-end-to-end.yml
@@ -217,6 +217,8 @@ jobs:
weblog: rails61
- library: ruby
weblog: rails70
+ - library: ruby
+ weblog: rails71
version:
- prod
- dev
diff --git a/utils/build/docker/ruby/README.md b/utils/build/docker/ruby/README.md
new file mode 100644
index 0000000000..bfb2443bba
--- /dev/null
+++ b/utils/build/docker/ruby/README.md
@@ -0,0 +1,26 @@
+# System test apps for Ruby
+
+## Updating lockfiles
+
+
+```
+# example with rails71
+
+# get base image to use same ruby version
+cat rails71.Dockerfile | perl -ne '/^FROM (.*)/ and print "$1\n"'
+
+# go into app
+cd rails71
+
+# conservative lock update (like bundle install)
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock
+
+# full lock update (like bundle update)
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock --update
+
+# adding a target platform with same deps as local platform
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock --add-platform x86_64-linux-gnu
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock --add-platform aarch64-linux-gnu
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock --add-platform x86_64-darwin
+docker run --rm -it -v "${PWD}":"${PWD}" -w "${PWD}" ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd bundle lock --add-platform arm64-darwin
+```
diff --git a/utils/build/docker/ruby/rails71.Dockerfile b/utils/build/docker/ruby/rails71.Dockerfile
new file mode 100644
index 0000000000..f4e66f2e8a
--- /dev/null
+++ b/utils/build/docker/ruby/rails71.Dockerfile
@@ -0,0 +1,19 @@
+FROM ghcr.io/datadog/dd-trace-rb/ruby:3.2.0-dd
+
+RUN apt-get update && apt-get install -y nodejs npm
+
+RUN mkdir -p /app
+WORKDIR /app
+
+COPY utils/build/docker/ruby/rails71/ .
+COPY utils/build/docker/ruby/install_ddtrace.sh binaries* /binaries/
+RUN /binaries/install_ddtrace.sh
+
+ENV DD_TRACE_HEADER_TAGS=user-agent
+ENV RAILS_ENV=production
+ENV RAILS_MASTER_KEY=9d319c57ec128e905d9e2ce5742bf2de
+RUN bundle exec rails db:create db:migrate db:seed
+
+RUN echo "#!/bin/bash\nbundle exec puma -b tcp://0.0.0.0 -p 7777 -w 1" > app.sh
+RUN chmod +x app.sh
+CMD [ "./app.sh" ]
diff --git a/utils/build/docker/ruby/rails71/.dockerignore b/utils/build/docker/ruby/rails71/.dockerignore
new file mode 100644
index 0000000000..df27d2d07d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/.dockerignore
@@ -0,0 +1,4 @@
+.envrc
+shell.nix
+vendor/bundle
+node_modules
diff --git a/utils/build/docker/ruby/rails71/.gitattributes b/utils/build/docker/ruby/rails71/.gitattributes
new file mode 100644
index 0000000000..31eeee0b6a
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/.gitattributes
@@ -0,0 +1,7 @@
+# See https://git-scm.com/docs/gitattributes for more about git attribute files.
+
+# Mark the database schema as having been generated.
+db/schema.rb linguist-generated
+
+# Mark any vendored files as having been vendored.
+vendor/* linguist-vendored
diff --git a/utils/build/docker/ruby/rails71/.gitignore b/utils/build/docker/ruby/rails71/.gitignore
new file mode 100644
index 0000000000..67ca8a3bfe
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/.gitignore
@@ -0,0 +1,39 @@
+# See https://help.github.com/articles/ignoring-files for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile '~/.gitignore_global'
+
+# Ignore bundler config.
+/.bundle
+
+# Ignore the default SQLite database.
+/db/*.sqlite3
+/db/*.sqlite3-*
+
+# Ignore all logfiles and tempfiles.
+/log/*
+/tmp/*
+!/log/.keep
+!/tmp/.keep
+
+# Ignore pidfiles, but keep the directory.
+/tmp/pids/*
+!/tmp/pids/
+!/tmp/pids/.keep
+
+# Ignore uploaded files in development.
+/storage/*
+!/storage/.keep
+/tmp/storage/*
+!/tmp/storage/
+!/tmp/storage/.keep
+
+/public/assets
+
+# Ignore master key for decrypting credentials and more.
+/config/master.key
+
+.envrc
+shell.nix
+/vendor/bundle
diff --git a/utils/build/docker/ruby/rails71/.ruby-version b/utils/build/docker/ruby/rails71/.ruby-version
new file mode 100644
index 0000000000..4efbd8f759
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/.ruby-version
@@ -0,0 +1 @@
+ruby-3.0.2
diff --git a/utils/build/docker/ruby/rails71/Gemfile b/utils/build/docker/ruby/rails71/Gemfile
new file mode 100644
index 0000000000..bf774ad6a6
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/Gemfile
@@ -0,0 +1,80 @@
+source "https://rubygems.org"
+git_source(:github) { |repo| "https://github.com/#{repo}.git" }
+
+ruby "~> 3.2.0"
+
+# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
+gem "rails", "~> 7.1.1"
+
+# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
+gem "sprockets-rails"
+
+# Use sqlite3 as the database for Active Record
+gem "sqlite3", "~> 1.4"
+
+# Use the Puma web server [https://github.com/puma/puma]
+gem "puma", "~> 6.0"
+
+# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
+gem "importmap-rails"
+
+# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
+gem "turbo-rails"
+
+# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
+gem "stimulus-rails"
+
+# Build JSON APIs with ease [https://github.com/rails/jbuilder]
+gem "jbuilder"
+
+# Talk with Kafka for propagation tests
+gem "ruby-kafka"
+
+# Use Redis adapter to run Action Cable in production
+# gem "redis", "~> 4.0"
+
+# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
+# gem "kredis"
+
+# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
+# gem "bcrypt", "~> 3.1.7"
+
+# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
+gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
+
+# Reduces boot times through caching; required in config/boot.rb
+gem "bootsnap", require: false
+
+# Use Sass to process CSS
+# gem "sassc-rails"
+
+# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
+# gem "image_processing", "~> 1.2"
+
+group :development, :test do
+ # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
+ gem "debug", platforms: %i[ mri mingw x64_mingw ]
+end
+
+group :development do
+ # Use console on exceptions pages [https://github.com/rails/web-console]
+ gem "web-console"
+
+ # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
+ # gem "rack-mini-profiler"
+
+ # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
+ # gem "spring"
+end
+
+group :test do
+ # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
+ gem "capybara"
+ gem "selenium-webdriver"
+ gem "webdrivers"
+end
+
+gem 'devise'
+
+gem 'pry'
+gem 'ddtrace', '~> 1.0.0.a', require: 'ddtrace/auto_instrument'
diff --git a/utils/build/docker/ruby/rails71/Gemfile.lock b/utils/build/docker/ruby/rails71/Gemfile.lock
new file mode 100644
index 0000000000..9651ed709e
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/Gemfile.lock
@@ -0,0 +1,314 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actioncable (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ nio4r (~> 2.0)
+ websocket-driver (>= 0.6.1)
+ zeitwerk (~> 2.6)
+ actionmailbox (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ activejob (= 7.1.3.2)
+ activerecord (= 7.1.3.2)
+ activestorage (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ mail (>= 2.7.1)
+ net-imap
+ net-pop
+ net-smtp
+ actionmailer (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ actionview (= 7.1.3.2)
+ activejob (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ mail (~> 2.5, >= 2.5.4)
+ net-imap
+ net-pop
+ net-smtp
+ rails-dom-testing (~> 2.2)
+ actionpack (7.1.3.2)
+ actionview (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ nokogiri (>= 1.8.5)
+ racc
+ rack (>= 2.2.4)
+ rack-session (>= 1.0.1)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ actiontext (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ activerecord (= 7.1.3.2)
+ activestorage (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ globalid (>= 0.6.0)
+ nokogiri (>= 1.8.5)
+ actionview (7.1.3.2)
+ activesupport (= 7.1.3.2)
+ builder (~> 3.1)
+ erubi (~> 1.11)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ activejob (7.1.3.2)
+ activesupport (= 7.1.3.2)
+ globalid (>= 0.3.6)
+ activemodel (7.1.3.2)
+ activesupport (= 7.1.3.2)
+ activerecord (7.1.3.2)
+ activemodel (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ timeout (>= 0.4.0)
+ activestorage (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ activejob (= 7.1.3.2)
+ activerecord (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ marcel (~> 1.0)
+ activesupport (7.1.3.2)
+ base64
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ mutex_m
+ tzinfo (~> 2.0)
+ addressable (2.8.6)
+ public_suffix (>= 2.0.2, < 6.0)
+ base64 (0.2.0)
+ bcrypt (3.1.20)
+ bigdecimal (3.1.7)
+ bindex (0.8.1)
+ bootsnap (1.18.3)
+ msgpack (~> 1.2)
+ builder (3.2.4)
+ capybara (3.40.0)
+ addressable
+ matrix
+ mini_mime (>= 0.1.3)
+ nokogiri (~> 1.11)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (>= 1.5, < 3.0)
+ xpath (~> 3.2)
+ coderay (1.1.3)
+ concurrent-ruby (1.2.3)
+ connection_pool (2.4.1)
+ crass (1.0.6)
+ date (3.3.4)
+ ddtrace (1.0.0)
+ debase-ruby_core_source (<= 0.10.15)
+ libddwaf (~> 1.3.0.0.0.a)
+ msgpack
+ debase-ruby_core_source (0.10.15)
+ debug (1.9.1)
+ irb (~> 1.10)
+ reline (>= 0.3.8)
+ devise (4.9.3)
+ bcrypt (~> 3.0)
+ orm_adapter (~> 0.1)
+ railties (>= 4.1.0)
+ responders
+ warden (~> 1.2.3)
+ digest-crc (0.6.5)
+ rake (>= 12.0.0, < 14.0.0)
+ drb (2.2.1)
+ erubi (1.12.0)
+ ffi (1.16.3)
+ globalid (1.2.1)
+ activesupport (>= 6.1)
+ i18n (1.14.4)
+ concurrent-ruby (~> 1.0)
+ importmap-rails (2.0.1)
+ actionpack (>= 6.0.0)
+ activesupport (>= 6.0.0)
+ railties (>= 6.0.0)
+ io-console (0.7.2)
+ irb (1.12.0)
+ rdoc
+ reline (>= 0.4.2)
+ jbuilder (2.11.5)
+ actionview (>= 5.0.0)
+ activesupport (>= 5.0.0)
+ libddwaf (1.3.0.0.0-aarch64-linux)
+ ffi (~> 1.0)
+ libddwaf (1.3.0.0.0-arm64-darwin)
+ ffi (~> 1.0)
+ libddwaf (1.3.0.0.0-x86_64-darwin)
+ ffi (~> 1.0)
+ libddwaf (1.3.0.0.0-x86_64-linux)
+ ffi (~> 1.0)
+ loofah (2.22.0)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.12.0)
+ mail (2.8.1)
+ mini_mime (>= 0.1.1)
+ net-imap
+ net-pop
+ net-smtp
+ marcel (1.0.4)
+ matrix (0.4.2)
+ method_source (1.0.0)
+ mini_mime (1.1.5)
+ minitest (5.22.3)
+ msgpack (1.7.2)
+ mutex_m (0.2.0)
+ net-imap (0.4.10)
+ date
+ net-protocol
+ net-pop (0.1.2)
+ net-protocol
+ net-protocol (0.2.2)
+ timeout
+ net-smtp (0.4.0.1)
+ net-protocol
+ nio4r (2.7.0)
+ nokogiri (1.16.3-aarch64-linux)
+ racc (~> 1.4)
+ nokogiri (1.16.3-arm64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.16.3-x86_64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.16.3-x86_64-linux)
+ racc (~> 1.4)
+ orm_adapter (0.5.0)
+ pry (0.14.2)
+ coderay (~> 1.1)
+ method_source (~> 1.0)
+ psych (5.1.2)
+ stringio
+ public_suffix (5.0.4)
+ puma (6.4.2)
+ nio4r (~> 2.0)
+ racc (1.7.3)
+ rack (3.0.9.1)
+ rack-session (2.0.0)
+ rack (>= 3.0.0)
+ rack-test (2.1.0)
+ rack (>= 1.3)
+ rackup (2.1.0)
+ rack (>= 3)
+ webrick (~> 1.8)
+ rails (7.1.3.2)
+ actioncable (= 7.1.3.2)
+ actionmailbox (= 7.1.3.2)
+ actionmailer (= 7.1.3.2)
+ actionpack (= 7.1.3.2)
+ actiontext (= 7.1.3.2)
+ actionview (= 7.1.3.2)
+ activejob (= 7.1.3.2)
+ activemodel (= 7.1.3.2)
+ activerecord (= 7.1.3.2)
+ activestorage (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ bundler (>= 1.15.0)
+ railties (= 7.1.3.2)
+ rails-dom-testing (2.2.0)
+ activesupport (>= 5.0.0)
+ minitest
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.6.0)
+ loofah (~> 2.21)
+ nokogiri (~> 1.14)
+ railties (7.1.3.2)
+ actionpack (= 7.1.3.2)
+ activesupport (= 7.1.3.2)
+ irb
+ rackup (>= 1.0.0)
+ rake (>= 12.2)
+ thor (~> 1.0, >= 1.2.2)
+ zeitwerk (~> 2.6)
+ rake (13.1.0)
+ rdoc (6.6.2)
+ psych (>= 4.0.0)
+ regexp_parser (2.9.0)
+ reline (0.4.3)
+ io-console (~> 0.5)
+ responders (3.1.1)
+ actionpack (>= 5.2)
+ railties (>= 5.2)
+ rexml (3.2.6)
+ ruby-kafka (1.5.0)
+ digest-crc
+ rubyzip (2.3.2)
+ selenium-webdriver (4.18.1)
+ base64 (~> 0.2)
+ rexml (~> 3.2, >= 3.2.5)
+ rubyzip (>= 1.2.2, < 3.0)
+ websocket (~> 1.0)
+ sprockets (4.2.1)
+ concurrent-ruby (~> 1.0)
+ rack (>= 2.2.4, < 4)
+ sprockets-rails (3.4.2)
+ actionpack (>= 5.2)
+ activesupport (>= 5.2)
+ sprockets (>= 3.0.0)
+ sqlite3 (1.7.3-aarch64-linux)
+ sqlite3 (1.7.3-arm64-darwin)
+ sqlite3 (1.7.3-x86_64-darwin)
+ sqlite3 (1.7.3-x86_64-linux)
+ stimulus-rails (1.3.3)
+ railties (>= 6.0.0)
+ stringio (3.1.0)
+ thor (1.3.1)
+ timeout (0.4.1)
+ turbo-rails (2.0.5)
+ actionpack (>= 6.0.0)
+ activejob (>= 6.0.0)
+ railties (>= 6.0.0)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ warden (1.2.9)
+ rack (>= 2.0.9)
+ web-console (4.2.1)
+ actionview (>= 6.0.0)
+ activemodel (>= 6.0.0)
+ bindex (>= 0.4.0)
+ railties (>= 6.0.0)
+ webdrivers (5.2.0)
+ nokogiri (~> 1.6)
+ rubyzip (>= 1.3.0)
+ selenium-webdriver (~> 4.0)
+ webrick (1.8.1)
+ websocket (1.2.10)
+ websocket-driver (0.7.6)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.5)
+ xpath (3.2.0)
+ nokogiri (~> 1.8)
+ zeitwerk (2.6.13)
+
+PLATFORMS
+ aarch64-linux-gnu
+ arm64-darwin
+ x86_64-darwin
+ x86_64-linux-gnu
+
+DEPENDENCIES
+ bootsnap
+ capybara
+ ddtrace (~> 1.0.0.a)
+ debug
+ devise
+ importmap-rails
+ jbuilder
+ pry
+ puma (~> 6.0)
+ rails (~> 7.1.1)
+ ruby-kafka
+ selenium-webdriver
+ sprockets-rails
+ sqlite3 (~> 1.4)
+ stimulus-rails
+ turbo-rails
+ tzinfo-data
+ web-console
+ webdrivers
+
+RUBY VERSION
+ ruby 3.2.0p0
+
+BUNDLED WITH
+ 2.3.26
diff --git a/utils/build/docker/ruby/rails71/README.md b/utils/build/docker/ruby/rails71/README.md
new file mode 100644
index 0000000000..7db80e4ca1
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/README.md
@@ -0,0 +1,24 @@
+# README
+
+This README would normally document whatever steps are necessary to get the
+application up and running.
+
+Things you may want to cover:
+
+* Ruby version
+
+* System dependencies
+
+* Configuration
+
+* Database creation
+
+* Database initialization
+
+* How to run the test suite
+
+* Services (job queues, cache servers, search engines, etc.)
+
+* Deployment instructions
+
+* ...
diff --git a/utils/build/docker/ruby/rails71/Rakefile b/utils/build/docker/ruby/rails71/Rakefile
new file mode 100644
index 0000000000..9a5ea7383a
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/Rakefile
@@ -0,0 +1,6 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require_relative "config/application"
+
+Rails.application.load_tasks
diff --git a/utils/build/docker/ruby/rails71/app/assets/config/manifest.js b/utils/build/docker/ruby/rails71/app/assets/config/manifest.js
new file mode 100644
index 0000000000..ddd546a0be
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/assets/config/manifest.js
@@ -0,0 +1,4 @@
+//= link_tree ../images
+//= link_directory ../stylesheets .css
+//= link_tree ../../javascript .js
+//= link_tree ../../../vendor/javascript .js
diff --git a/utils/build/docker/ruby/rails71/app/assets/images/.keep b/utils/build/docker/ruby/rails71/app/assets/images/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/app/assets/stylesheets/application.css b/utils/build/docker/ruby/rails71/app/assets/stylesheets/application.css
new file mode 100644
index 0000000000..288b9ab718
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/assets/stylesheets/application.css
@@ -0,0 +1,15 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
+ * vendor/assets/stylesheets directory can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS
+ * files in this directory. Styles in this file should be added after the last require_* statement.
+ * It is generally better to create a new file per style scope.
+ *
+ *= require_tree .
+ *= require_self
+ */
diff --git a/utils/build/docker/ruby/rails71/app/channels/application_cable/channel.rb b/utils/build/docker/ruby/rails71/app/channels/application_cable/channel.rb
new file mode 100644
index 0000000000..d672697283
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/channels/application_cable/channel.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Channel < ActionCable::Channel::Base
+ end
+end
diff --git a/utils/build/docker/ruby/rails71/app/channels/application_cable/connection.rb b/utils/build/docker/ruby/rails71/app/channels/application_cable/connection.rb
new file mode 100644
index 0000000000..0ff5442f47
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/channels/application_cable/connection.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Connection < ActionCable::Connection::Base
+ end
+end
diff --git a/utils/build/docker/ruby/rails71/app/controllers/application_controller.rb b/utils/build/docker/ruby/rails71/app/controllers/application_controller.rb
new file mode 100644
index 0000000000..09705d12ab
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/controllers/application_controller.rb
@@ -0,0 +1,2 @@
+class ApplicationController < ActionController::Base
+end
diff --git a/utils/build/docker/ruby/rails71/app/controllers/concerns/.keep b/utils/build/docker/ruby/rails71/app/controllers/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/app/controllers/system_test_controller.rb b/utils/build/docker/ruby/rails71/app/controllers/system_test_controller.rb
new file mode 100644
index 0000000000..1da71d87b3
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/controllers/system_test_controller.rb
@@ -0,0 +1,216 @@
+require 'datadog/kit/appsec/events'
+require 'kafka'
+
+class SystemTestController < ApplicationController
+ skip_before_action :verify_authenticity_token
+
+ def root
+ render plain: 'Hello, world!'
+ end
+
+ def waf
+ render plain: 'Hello, world!'
+ end
+
+ def handle_path_params
+ render plain: 'Hello, world!'
+ end
+
+ def generate_spans
+ begin
+ repeats = Integer(request.params['repeats'] || 0)
+ garbage = Integer(request.params['garbage'] || 0)
+ rescue ArgumentError
+ render plain: 'bad request', status: 400
+ else
+ repeats.times do |i|
+ Datadog::Tracing.trace('repeat-#{i}') do |span|
+ garbage.times do |j|
+ span.set_tag("garbage-#{j}", "#{j}")
+ end
+ end
+ end
+ end
+
+ render plain: 'Generated #{repeats} spans with #{garbage} garbage tags'
+ end
+
+ def test_headers
+ response.set_header('Content-Type', 'text/plain')
+ response.set_header('Content-Length', '15')
+ response.set_header('Content-Language', 'en-US')
+
+ render plain: 'Hello, headers!'
+ end
+
+ def identify
+ trace = Datadog::Tracing.active_trace
+ trace.set_tag('usr.id', 'usr.id')
+ trace.set_tag('usr.name', 'usr.name')
+ trace.set_tag('usr.email', 'usr.email')
+ trace.set_tag('usr.session_id', 'usr.session_id')
+ trace.set_tag('usr.role', 'usr.role')
+ trace.set_tag('usr.scope', 'usr.scope')
+
+ render plain: 'Hello, world!'
+ end
+
+ def status
+ render plain: "Ok", status: params[:code]
+ end
+
+ def read_file
+ render plain: File.read(params[:file])
+ end
+
+ def make_distant_call
+ url = params[:url]
+ uri = URI(url)
+ request = nil
+ response = nil
+
+ Net::HTTP.start(uri.host, uri.port) do |http|
+ request = Net::HTTP::Get.new(uri)
+
+ response = http.request(request)
+ end
+
+ result = {
+ "url": url,
+ "status_code": response.code,
+ "request_headers": request.each_header.to_h,
+ "response_headers": response.each_header.to_h,
+ }
+
+ render json: result
+ end
+
+ def user_login_success_event
+ Datadog::Kit::AppSec::Events.track_login_success(
+ Datadog::Tracing.active_trace, user: {id: 'system_tests_user'}, metadata0: "value0", metadata1: "value1"
+ )
+
+ render plain: 'Hello, world!'
+ end
+
+ def user_login_failure_event
+ Datadog::Kit::AppSec::Events.track_login_failure(
+ Datadog::Tracing.active_trace, user_id: 'system_tests_user', user_exists: true, metadata0: "value0", metadata1: "value1"
+ )
+
+ render plain: 'Hello, world!'
+ end
+
+ def custom_event
+ Datadog::Kit::AppSec::Events.track('system_tests_event', Datadog::Tracing.active_trace, metadata0: "value0", metadata1: "value1")
+
+ render plain: 'Hello, world!'
+ end
+
+ def tag_value
+ event_value = params[:tag_value]
+ status_code = params[:status_code]
+
+ if request.method == "POST" && event_value.include?('payload_in_response_body')
+ render json: { payload: request.POST }
+ return
+ end
+
+ headers = request.query_string.split('&').map {|e | e.split('=')} || []
+
+ trace = Datadog::Tracing.active_trace
+ trace.set_tag("appsec.events.system_tests_appsec_event.value", event_value)
+
+ headers.each do |key, value|
+ response.set_header(key, value)
+ end
+
+ render plain: 'Value tagged', status: status_code
+ end
+
+ def users
+ user_id = request.params["user"]
+
+ Datadog::Kit::Identity.set_user(id: user_id)
+
+ render plain: 'Hello, user!'
+ end
+
+ def login
+ request.env["devise.allow_params_authentication"] = true
+
+ sdk_event = request.params[:sdk_event]
+ sdk_user = request.params[:sdk_user]
+ sdk_email = request.params[:sdk_mail]
+ sdk_exists = request.params[:sdk_user_exists]
+
+ if sdk_exists
+ sdk_exists = sdk_exists == "true"
+ end
+
+ result = request.env['warden'].authenticate({ scope: Devise.mappings[:user].name })
+
+ if sdk_event === 'failure' && sdk_user
+ metadata = {}
+ metadata[:email] = sdk_email if sdk_email
+ Datadog::Kit::AppSec::Events.track_login_failure(user_id: sdk_user, user_exists: sdk_exists, **metadata)
+ elsif sdk_event === 'success' && sdk_user
+ user = {}
+ user[:id] = sdk_user
+ user[:email] = sdk_email if sdk_email
+ Datadog::Kit::AppSec::Events.track_login_success(user: user)
+ end
+
+ unless result
+ render plain: '', status: 401
+ return
+ end
+
+
+ render plain: 'Hello, world!'
+ end
+
+
+ def kafka_produce
+ kafka_client = Kafka.new(["kafka:9092"], client_id: "system-tests-client-producer")
+ topic = request.params["topic"]
+ stop = false
+ while stop == false
+ begin
+ Datadog::Tracing.trace('kafka_produce') do |span|
+ kafka_client.deliver_message("Hello, world!", topic: topic)
+ # This has to be done manually for now, because ruby does not add the topic
+ # to the span at all
+ span.set_tag("span.kind", "producer")
+ span.set_tag("kafka.topic", topic)
+ stop = true
+ end
+ rescue Kafka::LeaderNotAvailable
+ end
+ end
+
+ render plain: "Done"
+ end
+
+
+ def kafka_consume
+ kafka_client = Kafka.new(["kafka:9092"], client_id: "system-tests-client-consumer")
+ topic = request.params["topic"]
+ consumer = kafka_client.consumer(group_id: "system-tests-group")
+ consumer.subscribe(topic)
+ begin
+ consumer.each_message do |message|
+ if not message.nil?
+ break
+ end
+ end
+ rescue Exception => e
+ puts "An error has occurred while consuming messages from Kafka: #{e}"
+ ensure
+ consumer.stop
+ end
+
+ render plain: "Done"
+ end
+
+end
diff --git a/utils/build/docker/ruby/rails71/app/helpers/application_helper.rb b/utils/build/docker/ruby/rails71/app/helpers/application_helper.rb
new file mode 100644
index 0000000000..de6be7945c
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
diff --git a/utils/build/docker/ruby/rails71/app/javascript/application.js b/utils/build/docker/ruby/rails71/app/javascript/application.js
new file mode 100644
index 0000000000..0d7b49404c
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/javascript/application.js
@@ -0,0 +1,3 @@
+// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
+import "@hotwired/turbo-rails"
+import "controllers"
diff --git a/utils/build/docker/ruby/rails71/app/javascript/controllers/application.js b/utils/build/docker/ruby/rails71/app/javascript/controllers/application.js
new file mode 100644
index 0000000000..1213e85c7a
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/javascript/controllers/application.js
@@ -0,0 +1,9 @@
+import { Application } from "@hotwired/stimulus"
+
+const application = Application.start()
+
+// Configure Stimulus development experience
+application.debug = false
+window.Stimulus = application
+
+export { application }
diff --git a/utils/build/docker/ruby/rails71/app/javascript/controllers/hello_controller.js b/utils/build/docker/ruby/rails71/app/javascript/controllers/hello_controller.js
new file mode 100644
index 0000000000..5975c0789d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/javascript/controllers/hello_controller.js
@@ -0,0 +1,7 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+ connect() {
+ this.element.textContent = "Hello World!"
+ }
+}
diff --git a/utils/build/docker/ruby/rails71/app/javascript/controllers/index.js b/utils/build/docker/ruby/rails71/app/javascript/controllers/index.js
new file mode 100644
index 0000000000..54ad4cad4d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/javascript/controllers/index.js
@@ -0,0 +1,11 @@
+// Import and register all your controllers from the importmap under controllers/*
+
+import { application } from "controllers/application"
+
+// Eager load all controllers defined in the import map under controllers/**/*_controller
+import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
+eagerLoadControllersFrom("controllers", application)
+
+// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
+// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
+// lazyLoadControllersFrom("controllers", application)
diff --git a/utils/build/docker/ruby/rails71/app/jobs/application_job.rb b/utils/build/docker/ruby/rails71/app/jobs/application_job.rb
new file mode 100644
index 0000000000..d394c3d106
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/jobs/application_job.rb
@@ -0,0 +1,7 @@
+class ApplicationJob < ActiveJob::Base
+ # Automatically retry jobs that encountered a deadlock
+ # retry_on ActiveRecord::Deadlocked
+
+ # Most jobs are safe to ignore if the underlying records are no longer available
+ # discard_on ActiveJob::DeserializationError
+end
diff --git a/utils/build/docker/ruby/rails71/app/mailers/application_mailer.rb b/utils/build/docker/ruby/rails71/app/mailers/application_mailer.rb
new file mode 100644
index 0000000000..3c34c8148f
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/mailers/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: "from@example.com"
+ layout "mailer"
+end
diff --git a/utils/build/docker/ruby/rails71/app/models/application_record.rb b/utils/build/docker/ruby/rails71/app/models/application_record.rb
new file mode 100644
index 0000000000..b63caeb8a5
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/models/application_record.rb
@@ -0,0 +1,3 @@
+class ApplicationRecord < ActiveRecord::Base
+ primary_abstract_class
+end
diff --git a/utils/build/docker/ruby/rails71/app/models/concerns/.keep b/utils/build/docker/ruby/rails71/app/models/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/app/models/user.rb b/utils/build/docker/ruby/rails71/app/models/user.rb
new file mode 100644
index 0000000000..47567994e9
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/models/user.rb
@@ -0,0 +1,6 @@
+class User < ApplicationRecord
+ # Include default devise modules. Others available are:
+ # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
+ devise :database_authenticatable, :registerable,
+ :recoverable, :rememberable, :validatable
+end
diff --git a/utils/build/docker/ruby/rails71/app/views/layouts/application.html.erb b/utils/build/docker/ruby/rails71/app/views/layouts/application.html.erb
new file mode 100644
index 0000000000..0d2f3c9bdb
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/views/layouts/application.html.erb
@@ -0,0 +1,16 @@
+
+
+
+ Rails70
+
+ <%= csrf_meta_tags %>
+ <%= csp_meta_tag %>
+
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
+ <%= javascript_importmap_tags %>
+
+
+
+ <%= yield %>
+
+
diff --git a/utils/build/docker/ruby/rails71/app/views/layouts/mailer.html.erb b/utils/build/docker/ruby/rails71/app/views/layouts/mailer.html.erb
new file mode 100644
index 0000000000..cbd34d2e9d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/views/layouts/mailer.html.erb
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+ <%= yield %>
+
+
diff --git a/utils/build/docker/ruby/rails71/app/views/layouts/mailer.text.erb b/utils/build/docker/ruby/rails71/app/views/layouts/mailer.text.erb
new file mode 100644
index 0000000000..37f0bddbd7
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/app/views/layouts/mailer.text.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/utils/build/docker/ruby/rails71/bin/rails b/utils/build/docker/ruby/rails71/bin/rails
new file mode 100755
index 0000000000..efc0377492
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/bin/rails
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+APP_PATH = File.expand_path("../config/application", __dir__)
+require_relative "../config/boot"
+require "rails/commands"
diff --git a/utils/build/docker/ruby/rails71/config.ru b/utils/build/docker/ruby/rails71/config.ru
new file mode 100644
index 0000000000..4a3c09a688
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config.ru
@@ -0,0 +1,6 @@
+# This file is used by Rack-based servers to start the application.
+
+require_relative "config/environment"
+
+run Rails.application
+Rails.application.load_server
diff --git a/utils/build/docker/ruby/rails71/config/application.rb b/utils/build/docker/ruby/rails71/config/application.rb
new file mode 100644
index 0000000000..1f0390ac07
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/application.rb
@@ -0,0 +1,22 @@
+require_relative "boot"
+
+require "rails/all"
+
+# Require the gems listed in Gemfile, including any gems
+# you've limited to :test, :development, or :production.
+Bundler.require(*Rails.groups)
+
+module Rails70
+ class Application < Rails::Application
+ # Initialize configuration defaults for originally generated Rails version.
+ config.load_defaults 7.0
+
+ # Configuration for the application, engines, and railties goes here.
+ #
+ # These settings can be overridden in specific environments using the files
+ # in config/environments, which are processed later.
+ #
+ # config.time_zone = "Central Time (US & Canada)"
+ # config.eager_load_paths << Rails.root.join("extras")
+ end
+end
diff --git a/utils/build/docker/ruby/rails71/config/boot.rb b/utils/build/docker/ruby/rails71/config/boot.rb
new file mode 100644
index 0000000000..988a5ddc46
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/boot.rb
@@ -0,0 +1,4 @@
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+require "bundler/setup" # Set up gems listed in the Gemfile.
+require "bootsnap/setup" # Speed up boot time by caching expensive operations.
diff --git a/utils/build/docker/ruby/rails71/config/cable.yml b/utils/build/docker/ruby/rails71/config/cable.yml
new file mode 100644
index 0000000000..8ea8617f58
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/cable.yml
@@ -0,0 +1,10 @@
+development:
+ adapter: async
+
+test:
+ adapter: test
+
+production:
+ adapter: redis
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
+ channel_prefix: rails70_production
diff --git a/utils/build/docker/ruby/rails71/config/credentials.yml.enc b/utils/build/docker/ruby/rails71/config/credentials.yml.enc
new file mode 100644
index 0000000000..aeb5eb19e6
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/credentials.yml.enc
@@ -0,0 +1 @@
+G5RovwV49vRCRsWk/HDncp0URlHKknKKjpxxP5znIc/TKR+dvGVoevXlv7QrfaJG1X8gq4nnL1uahrEwFNtqc5qVrTeM/GrFoY5UUthoIjDNTG8CboZEpCfvlo5n7qC1Tm3SnkxCR4q0c1Hpq7GFkRnpPRhK/Y69Xd/2TyHirAHGKPfWb27aS77VXtFO7Haho9NnL3mB5PPn1VEIQnwBAhRggeQF6hs460e6tS5nZiKsa3QOO1G86Q1sU7k3AF/J+cG/NIT555LI3Wso7qU80KySor4j/IY+DVe7jys8XB9frX5ppt2vfnRc/F5indCRUrT7N8wXdLx7C1eOxyWNLKt2L9fmt1JYauOlI/GZ9YJWtqqAkPDsssYuUc8F6ZeIZQQTxHWeFd4MJZVplFKDrG20lUROIAz41nAM--qxpsBmnjgm5xqiYc--Dow+e/9K97oMj5VdQge/tQ==
\ No newline at end of file
diff --git a/utils/build/docker/ruby/rails71/config/database.yml b/utils/build/docker/ruby/rails71/config/database.yml
new file mode 100644
index 0000000000..fcba57f19f
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/database.yml
@@ -0,0 +1,25 @@
+# SQLite. Versions 3.8.0 and up are supported.
+# gem install sqlite3
+#
+# Ensure the SQLite 3 gem is defined in your Gemfile
+# gem "sqlite3"
+#
+default: &default
+ adapter: sqlite3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ timeout: 5000
+
+development:
+ <<: *default
+ database: db/development.sqlite3
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ <<: *default
+ database: db/test.sqlite3
+
+production:
+ <<: *default
+ database: db/production.sqlite3
diff --git a/utils/build/docker/ruby/rails71/config/environment.rb b/utils/build/docker/ruby/rails71/config/environment.rb
new file mode 100644
index 0000000000..cac5315775
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require_relative "application"
+
+# Initialize the Rails application.
+Rails.application.initialize!
diff --git a/utils/build/docker/ruby/rails71/config/environments/development.rb b/utils/build/docker/ruby/rails71/config/environments/development.rb
new file mode 100644
index 0000000000..5e311ae21d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/environments/development.rb
@@ -0,0 +1,72 @@
+require "active_support/core_ext/integer/time"
+
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded any time
+ # it changes. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports.
+ config.consider_all_requests_local = true
+
+ # Enable server timing
+ config.server_timing = true
+
+ # Enable/disable caching. By default caching is disabled.
+ # Run rails dev:cache to toggle caching.
+ if Rails.root.join("tmp/caching-dev.txt").exist?
+ config.action_controller.perform_caching = true
+ config.action_controller.enable_fragment_cache_logging = true
+
+ config.cache_store = :memory_store
+ config.public_file_server.headers = {
+ "Cache-Control" => "public, max-age=#{2.days.to_i}"
+ }
+ else
+ config.action_controller.perform_caching = false
+
+ config.cache_store = :null_store
+ end
+
+ # Store uploaded files on the local file system (see config/storage.yml for options).
+ config.active_storage.service = :local
+
+ # Don't care if the mailer can't send.
+ config.action_mailer.raise_delivery_errors = false
+
+ config.action_mailer.perform_caching = false
+
+ # Print deprecation notices to the Rails logger.
+ config.active_support.deprecation = :log
+
+ # Raise exceptions for disallowed deprecations.
+ config.active_support.disallowed_deprecation = :raise
+
+ # Tell Active Support which deprecation messages to disallow.
+ config.active_support.disallowed_deprecation_warnings = []
+
+ # Raise an error on page load if there are pending migrations.
+ config.active_record.migration_error = :page_load
+
+ # Highlight code that triggered database queries in logs.
+ config.active_record.verbose_query_logs = true
+
+ # Suppress logger output for asset requests.
+ config.assets.quiet = true
+
+ # Raises error for missing translations.
+ # config.i18n.raise_on_missing_translations = true
+
+ # Annotate rendered view with file names.
+ # config.action_view.annotate_rendered_view_with_filenames = true
+
+ # Uncomment if you wish to allow Action Cable access from any origin.
+ # config.action_cable.disable_request_forgery_protection = true
+
+ config.hosts.clear
+end
diff --git a/utils/build/docker/ruby/rails71/config/environments/production.rb b/utils/build/docker/ruby/rails71/config/environments/production.rb
new file mode 100644
index 0000000000..e58961b313
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/environments/production.rb
@@ -0,0 +1,93 @@
+require "active_support/core_ext/integer/time"
+
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # Code is not reloaded between requests.
+ config.cache_classes = true
+
+ # Eager load code on boot. This eager loads most of Rails and
+ # your application in memory, allowing both threaded web servers
+ # and those relying on copy on write to perform better.
+ # Rake tasks automatically ignore this option for performance.
+ config.eager_load = true
+
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
+ # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
+ # config.require_master_key = true
+
+ # Disable serving static files from the `/public` folder by default since
+ # Apache or NGINX already handles this.
+ config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
+
+ # Compress CSS using a preprocessor.
+ # config.assets.css_compressor = :sass
+
+ # Do not fallback to assets pipeline if a precompiled asset is missed.
+ config.assets.compile = false
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
+ # config.asset_host = "http://assets.example.com"
+
+ # Specifies the header that your server uses for sending files.
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
+ # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
+
+ # Store uploaded files on the local file system (see config/storage.yml for options).
+ config.active_storage.service = :local
+
+ # Mount Action Cable outside main process or domain.
+ # config.action_cable.mount_path = nil
+ # config.action_cable.url = "wss://example.com/cable"
+ # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # Include generic and useful information about system operation, but avoid logging too much
+ # information to avoid inadvertent exposure of personally identifiable information (PII).
+ config.log_level = :info
+
+ # Prepend all log lines with the following tags.
+ config.log_tags = [ :request_id ]
+
+ # Use a different cache store in production.
+ # config.cache_store = :mem_cache_store
+
+ # Use a real queuing backend for Active Job (and separate queues per environment).
+ # config.active_job.queue_adapter = :resque
+ # config.active_job.queue_name_prefix = "rails70_production"
+
+ config.action_mailer.perform_caching = false
+
+ # Ignore bad email addresses and do not raise email delivery errors.
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation cannot be found).
+ config.i18n.fallbacks = true
+
+ # Don't log any deprecations.
+ config.active_support.report_deprecations = false
+
+ # Use default logging formatter so that PID and timestamp are not suppressed.
+ config.log_formatter = ::Logger::Formatter.new
+
+ # Use a different logger for distributed setups.
+ # require "syslog/logger"
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
+
+ if ENV["RAILS_LOG_TO_STDOUT"].present?
+ logger = ActiveSupport::Logger.new(STDOUT)
+ logger.formatter = config.log_formatter
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
+ end
+
+ # Do not dump schema after migrations.
+ config.active_record.dump_schema_after_migration = false
+end
diff --git a/utils/build/docker/ruby/rails71/config/environments/test.rb b/utils/build/docker/ruby/rails71/config/environments/test.rb
new file mode 100644
index 0000000000..6ea4d1e706
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/environments/test.rb
@@ -0,0 +1,60 @@
+require "active_support/core_ext/integer/time"
+
+# The test environment is used exclusively to run your application's
+# test suite. You never need to work with it otherwise. Remember that
+# your test database is "scratch space" for the test suite and is wiped
+# and recreated between test runs. Don't rely on the data there!
+
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # Turn false under Spring and add config.action_view.cache_template_loading = true.
+ config.cache_classes = true
+
+ # Eager loading loads your whole application. When running a single test locally,
+ # this probably isn't necessary. It's a good idea to do in a continuous integration
+ # system, or in some way before deploying your code.
+ config.eager_load = ENV["CI"].present?
+
+ # Configure public file server for tests with Cache-Control for performance.
+ config.public_file_server.enabled = true
+ config.public_file_server.headers = {
+ "Cache-Control" => "public, max-age=#{1.hour.to_i}"
+ }
+
+ # Show full error reports and disable caching.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+ config.cache_store = :null_store
+
+ # Raise exceptions instead of rendering exception templates.
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
+
+ # Store uploaded files on the local file system in a temporary directory.
+ config.active_storage.service = :test
+
+ config.action_mailer.perform_caching = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Print deprecation notices to the stderr.
+ config.active_support.deprecation = :stderr
+
+ # Raise exceptions for disallowed deprecations.
+ config.active_support.disallowed_deprecation = :raise
+
+ # Tell Active Support which deprecation messages to disallow.
+ config.active_support.disallowed_deprecation_warnings = []
+
+ # Raises error for missing translations.
+ # config.i18n.raise_on_missing_translations = true
+
+ # Annotate rendered view with file names.
+ # config.action_view.annotate_rendered_view_with_filenames = true
+end
diff --git a/utils/build/docker/ruby/rails71/config/importmap.rb b/utils/build/docker/ruby/rails71/config/importmap.rb
new file mode 100644
index 0000000000..8dce42d406
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/importmap.rb
@@ -0,0 +1,7 @@
+# Pin npm packages by running ./bin/importmap
+
+pin "application", preload: true
+pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
+pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
+pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
+pin_all_from "app/javascript/controllers", under: "controllers"
diff --git a/utils/build/docker/ruby/rails71/config/initializers/assets.rb b/utils/build/docker/ruby/rails71/config/initializers/assets.rb
new file mode 100644
index 0000000000..2eeef966fe
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/assets.rb
@@ -0,0 +1,12 @@
+# Be sure to restart your server when you modify this file.
+
+# Version of your assets, change this if you want to expire all your assets.
+Rails.application.config.assets.version = "1.0"
+
+# Add additional assets to the asset load path.
+# Rails.application.config.assets.paths << Emoji.images_path
+
+# Precompile additional assets.
+# application.js, application.css, and all non-JS/CSS in the app/assets
+# folder are already added.
+# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/utils/build/docker/ruby/rails71/config/initializers/content_security_policy.rb b/utils/build/docker/ruby/rails71/config/initializers/content_security_policy.rb
new file mode 100644
index 0000000000..3621f97f8e
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/content_security_policy.rb
@@ -0,0 +1,26 @@
+# Be sure to restart your server when you modify this file.
+
+# Define an application-wide content security policy
+# For further information see the following documentation
+# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
+
+# Rails.application.configure do
+# config.content_security_policy do |policy|
+# policy.default_src :self, :https
+# policy.font_src :self, :https, :data
+# policy.img_src :self, :https, :data
+# policy.object_src :none
+# policy.script_src :self, :https
+# policy.style_src :self, :https
+# # Specify URI for violation reports
+# # policy.report_uri "/csp-violation-report-endpoint"
+# end
+#
+# # Generate session nonces for permitted importmap and inline scripts
+# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
+# config.content_security_policy_nonce_directives = %w(script-src)
+#
+# # Report CSP violations to a specified URI. See:
+# # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
+# # config.content_security_policy_report_only = true
+# end
diff --git a/utils/build/docker/ruby/rails71/config/initializers/datadog.rb b/utils/build/docker/ruby/rails71/config/initializers/datadog.rb
new file mode 100644
index 0000000000..e7079ecc33
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/datadog.rb
@@ -0,0 +1,11 @@
+Datadog.configure do |c|
+ c.diagnostics.debug = true
+end
+
+# Send non-web init event
+
+if defined?(Datadog::Tracing)
+ Datadog::Tracing.trace('init.service') { }
+else
+ Datadog.tracer.trace('init.service') { }
+end
diff --git a/utils/build/docker/ruby/rails71/config/initializers/devise.rb b/utils/build/docker/ruby/rails71/config/initializers/devise.rb
new file mode 100644
index 0000000000..098e4a0aa6
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/devise.rb
@@ -0,0 +1,313 @@
+# frozen_string_literal: true
+
+# Assuming you have not yet modified this file, each configuration option below
+# is set to its default value. Note that some are commented out while others
+# are not: uncommented lines are intended to protect your configuration from
+# breaking changes in upgrades (i.e., in the event that future versions of
+# Devise change the default values for those options).
+#
+# Use this hook to configure devise mailer, warden hooks and so forth.
+# Many of these configuration options can be set straight in your model.
+Devise.setup do |config|
+ # The secret key used by Devise. Devise uses this key to generate
+ # random tokens. Changing this key will render invalid all existing
+ # confirmation, reset password and unlock tokens in the database.
+ # Devise will use the `secret_key_base` as its `secret_key`
+ # by default. You can change it below and use your own secret key.
+ # config.secret_key = '2aa7763a03b8aeefb5507ab110519240bbd9c017f8c15c8e5d652871ebdc194735d7acda52f0a3eef7a46fb2f16bc4a0eeacd1542a3f63ad6d56e38a15484fa8'
+
+ # ==> Controller configuration
+ # Configure the parent class to the devise controllers.
+ # config.parent_controller = 'DeviseController'
+
+ # ==> Mailer Configuration
+ # Configure the e-mail address which will be shown in Devise::Mailer,
+ # note that it will be overwritten if you use your own mailer class
+ # with default "from" parameter.
+ config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
+
+ # Configure the class responsible to send e-mails.
+ # config.mailer = 'Devise::Mailer'
+
+ # Configure the parent class responsible to send e-mails.
+ # config.parent_mailer = 'ActionMailer::Base'
+
+ # ==> ORM configuration
+ # Load and configure the ORM. Supports :active_record (default) and
+ # :mongoid (bson_ext recommended) by default. Other ORMs may be
+ # available as additional gems.
+ require 'devise/orm/active_record'
+
+ # ==> Configuration for any authentication mechanism
+ # Configure which keys are used when authenticating a user. The default is
+ # just :email. You can configure it to use [:username, :subdomain], so for
+ # authenticating a user, both parameters are required. Remember that those
+ # parameters are used only when authenticating and not when retrieving from
+ # session. If you need permissions, you should implement that in a before filter.
+ # You can also supply a hash where the value is a boolean determining whether
+ # or not authentication should be aborted when the value is not present.
+ config.authentication_keys = [ :username ]
+
+ # Configure parameters from the request object used for authentication. Each entry
+ # given should be a request method and it will automatically be passed to the
+ # find_for_authentication method and considered in your model lookup. For instance,
+ # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
+ # The same considerations mentioned for authentication_keys also apply to request_keys.
+ # config.request_keys = []
+
+ # Configure which authentication keys should be case-insensitive.
+ # These keys will be downcased upon creating or modifying a user and when used
+ # to authenticate or find a user. Default is :email.
+ config.case_insensitive_keys = [:email]
+
+ # Configure which authentication keys should have whitespace stripped.
+ # These keys will have whitespace before and after removed upon creating or
+ # modifying a user and when used to authenticate or find a user. Default is :email.
+ config.strip_whitespace_keys = [:email]
+
+ # Tell if authentication through request.params is enabled. True by default.
+ # It can be set to an array that will enable params authentication only for the
+ # given strategies, for example, `config.params_authenticatable = [:database]` will
+ # enable it only for database (email + password) authentication.
+ # config.params_authenticatable = true
+
+ # Tell if authentication through HTTP Auth is enabled. False by default.
+ # It can be set to an array that will enable http authentication only for the
+ # given strategies, for example, `config.http_authenticatable = [:database]` will
+ # enable it only for database authentication.
+ # For API-only applications to support authentication "out-of-the-box", you will likely want to
+ # enable this with :database unless you are using a custom strategy.
+ # The supported strategies are:
+ # :database = Support basic authentication with authentication key + password
+ config.http_authenticatable = true
+
+ # If 401 status code should be returned for AJAX requests. True by default.
+ # config.http_authenticatable_on_xhr = true
+
+ # The realm used in Http Basic Authentication. 'Application' by default.
+ # config.http_authentication_realm = 'Application'
+
+ # It will change confirmation, password recovery and other workflows
+ # to behave the same regardless if the e-mail provided was right or wrong.
+ # Does not affect registerable.
+ # config.paranoid = true
+
+ # By default Devise will store the user in session. You can skip storage for
+ # particular strategies by setting this option.
+ # Notice that if you are skipping storage for all authentication paths, you
+ # may want to disable generating routes to Devise's sessions controller by
+ # passing skip: :sessions to `devise_for` in your config/routes.rb
+ config.skip_session_storage = [:http_auth]
+
+ # By default, Devise cleans up the CSRF token on authentication to
+ # avoid CSRF token fixation attacks. This means that, when using AJAX
+ # requests for sign in and sign up, you need to get a new CSRF token
+ # from the server. You can disable this option at your own risk.
+ # config.clean_up_csrf_token_on_authentication = true
+
+ # When false, Devise will not attempt to reload routes on eager load.
+ # This can reduce the time taken to boot the app but if your application
+ # requires the Devise mappings to be loaded during boot time the application
+ # won't boot properly.
+ # config.reload_routes = true
+
+ # ==> Configuration for :database_authenticatable
+ # For bcrypt, this is the cost for hashing the password and defaults to 12. If
+ # using other algorithms, it sets how many times you want the password to be hashed.
+ # The number of stretches used for generating the hashed password are stored
+ # with the hashed password. This allows you to change the stretches without
+ # invalidating existing passwords.
+ #
+ # Limiting the stretches to just one in testing will increase the performance of
+ # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
+ # a value less than 10 in other environments. Note that, for bcrypt (the default
+ # algorithm), the cost increases exponentially with the number of stretches (e.g.
+ # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
+ config.stretches = Rails.env.test? ? 1 : 12
+
+ # Set up a pepper to generate the hashed password.
+ # config.pepper = '8b94639bc3aa104aa9b17554d6209cdc5bbbd767a3296f3f6600220cda59ddae62ddc13c37250d3602924f4e4d9c0e24788e318eba5c60dff77e478139388460'
+
+ # Send a notification to the original email when the user's email is changed.
+ # config.send_email_changed_notification = false
+
+ # Send a notification email when the user's password is changed.
+ # config.send_password_change_notification = false
+
+ # ==> Configuration for :confirmable
+ # A period that the user is allowed to access the website even without
+ # confirming their account. For instance, if set to 2.days, the user will be
+ # able to access the website for two days without confirming their account,
+ # access will be blocked just in the third day.
+ # You can also set it to nil, which will allow the user to access the website
+ # without confirming their account.
+ # Default is 0.days, meaning the user cannot access the website without
+ # confirming their account.
+ # config.allow_unconfirmed_access_for = 2.days
+
+ # A period that the user is allowed to confirm their account before their
+ # token becomes invalid. For example, if set to 3.days, the user can confirm
+ # their account within 3 days after the mail was sent, but on the fourth day
+ # their account can't be confirmed with the token any more.
+ # Default is nil, meaning there is no restriction on how long a user can take
+ # before confirming their account.
+ # config.confirm_within = 3.days
+
+ # If true, requires any email changes to be confirmed (exactly the same way as
+ # initial account confirmation) to be applied. Requires additional unconfirmed_email
+ # db field (see migrations). Until confirmed, new email is stored in
+ # unconfirmed_email column, and copied to email column on successful confirmation.
+ config.reconfirmable = true
+
+ # Defines which key will be used when confirming an account
+ # config.confirmation_keys = [:email]
+
+ # ==> Configuration for :rememberable
+ # The time the user will be remembered without asking for credentials again.
+ # config.remember_for = 2.weeks
+
+ # Invalidates all the remember me tokens when the user signs out.
+ config.expire_all_remember_me_on_sign_out = true
+
+ # If true, extends the user's remember period when remembered via cookie.
+ # config.extend_remember_period = false
+
+ # Options to be passed to the created cookie. For instance, you can set
+ # secure: true in order to force SSL only cookies.
+ # config.rememberable_options = {}
+
+ # ==> Configuration for :validatable
+ # Range for password length.
+ config.password_length = 4..128
+
+ # Email regex used to validate email formats. It simply asserts that
+ # one (and only one) @ exists in the given string. This is mainly
+ # to give user feedback and not to assert the e-mail validity.
+ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
+
+ # ==> Configuration for :timeoutable
+ # The time you want to timeout the user session without activity. After this
+ # time the user will be asked for credentials again. Default is 30 minutes.
+ # config.timeout_in = 30.minutes
+
+ # ==> Configuration for :lockable
+ # Defines which strategy will be used to lock an account.
+ # :failed_attempts = Locks an account after a number of failed attempts to sign in.
+ # :none = No lock strategy. You should handle locking by yourself.
+ # config.lock_strategy = :failed_attempts
+
+ # Defines which key will be used when locking and unlocking an account
+ # config.unlock_keys = [:email]
+
+ # Defines which strategy will be used to unlock an account.
+ # :email = Sends an unlock link to the user email
+ # :time = Re-enables login after a certain amount of time (see :unlock_in below)
+ # :both = Enables both strategies
+ # :none = No unlock strategy. You should handle unlocking by yourself.
+ # config.unlock_strategy = :both
+
+ # Number of authentication tries before locking an account if lock_strategy
+ # is failed attempts.
+ # config.maximum_attempts = 20
+
+ # Time interval to unlock the account if :time is enabled as unlock_strategy.
+ # config.unlock_in = 1.hour
+
+ # Warn on the last attempt before the account is locked.
+ # config.last_attempt_warning = true
+
+ # ==> Configuration for :recoverable
+ #
+ # Defines which key will be used when recovering the password for an account
+ # config.reset_password_keys = [:email]
+
+ # Time interval you can reset your password with a reset password key.
+ # Don't put a too small interval or your users won't have the time to
+ # change their passwords.
+ config.reset_password_within = 6.hours
+
+ # When set to false, does not sign a user in automatically after their password is
+ # reset. Defaults to true, so a user is signed in automatically after a reset.
+ # config.sign_in_after_reset_password = true
+
+ # ==> Configuration for :encryptable
+ # Allow you to use another hashing or encryption algorithm besides bcrypt (default).
+ # You can use :sha1, :sha512 or algorithms from others authentication tools as
+ # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20
+ # for default behavior) and :restful_authentication_sha1 (then you should set
+ # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper).
+ #
+ # Require the `devise-encryptable` gem when using anything other than bcrypt
+ # config.encryptor = :sha512
+
+ # ==> Scopes configuration
+ # Turn scoped views on. Before rendering "sessions/new", it will first check for
+ # "users/sessions/new". It's turned off by default because it's slower if you
+ # are using only default views.
+ # config.scoped_views = false
+
+ # Configure the default scope given to Warden. By default it's the first
+ # devise role declared in your routes (usually :user).
+ # config.default_scope = :user
+
+ # Set this configuration to false if you want /users/sign_out to sign out
+ # only the current scope. By default, Devise signs out all scopes.
+ # config.sign_out_all_scopes = true
+
+ # ==> Navigation configuration
+ # Lists the formats that should be treated as navigational. Formats like
+ # :html should redirect to the sign in page when the user does not have
+ # access, but formats like :xml or :json, should return 401.
+ #
+ # If you have any extra navigational formats, like :iphone or :mobile, you
+ # should add them to the navigational formats lists.
+ #
+ # The "*/*" below is required to match Internet Explorer requests.
+ # config.navigational_formats = ['*/*', :html, :turbo_stream]
+
+ # The default HTTP method used to sign out a resource. Default is :delete.
+ config.sign_out_via = :delete
+
+ # ==> OmniAuth
+ # Add a new OmniAuth provider. Check the wiki for more information on setting
+ # up on your models and hooks.
+ # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
+
+ # ==> Warden configuration
+ # If you want to use other strategies, that are not supported by Devise, or
+ # change the failure app, you can configure them inside the config.warden block.
+ #
+ # config.warden do |manager|
+ # manager.intercept_401 = false
+ # manager.default_strategies(scope: :user).unshift :some_external_strategy
+ # end
+
+ # ==> Mountable engine configurations
+ # When using Devise inside an engine, let's call it `MyEngine`, and this engine
+ # is mountable, there are some extra configurations to be taken into account.
+ # The following options are available, assuming the engine is mounted as:
+ #
+ # mount MyEngine, at: '/my_engine'
+ #
+ # The router that invoked `devise_for`, in the example above, would be:
+ # config.router_name = :my_engine
+ #
+ # When using OmniAuth, Devise cannot automatically set OmniAuth path,
+ # so you need to do it manually. For the users scope, it would be:
+ # config.omniauth_path_prefix = '/my_engine/users/auth'
+
+ # ==> Hotwire/Turbo configuration
+ # When using Devise with Hotwire/Turbo, the http status for error responses
+ # and some redirects must match the following. The default in Devise for existing
+ # apps is `200 OK` and `302 Found respectively`, but new apps are generated with
+ # these new defaults that match Hotwire/Turbo behavior.
+ # Note: These might become the new default in future versions of Devise.
+ config.responder.error_status = :unprocessable_entity
+ config.responder.redirect_status = :see_other
+
+ # ==> Configuration for :registerable
+
+ # When set to false, does not sign a user in automatically after their password is
+ # changed. Defaults to true, so a user is signed in automatically after changing a password.
+ # config.sign_in_after_change_password = true
+end
diff --git a/utils/build/docker/ruby/rails71/config/initializers/filter_parameter_logging.rb b/utils/build/docker/ruby/rails71/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000000..4b34a03668
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/filter_parameter_logging.rb
@@ -0,0 +1,6 @@
+# Be sure to restart your server when you modify this file.
+
+# Configure sensitive parameters which will be filtered from the log file.
+Rails.application.config.filter_parameters += [
+ :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
+]
diff --git a/utils/build/docker/ruby/rails71/config/initializers/inflections.rb b/utils/build/docker/ruby/rails71/config/initializers/inflections.rb
new file mode 100644
index 0000000000..3860f659ea
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/inflections.rb
@@ -0,0 +1,16 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format. Inflections
+# are locale specific, and you may define rules for as many different
+# locales as you wish. All of these examples are active by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.plural /^(ox)$/i, "\\1en"
+# inflect.singular /^(ox)en/i, "\\1"
+# inflect.irregular "person", "people"
+# inflect.uncountable %w( fish sheep )
+# end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.acronym "RESTful"
+# end
diff --git a/utils/build/docker/ruby/rails71/config/initializers/permissions_policy.rb b/utils/build/docker/ruby/rails71/config/initializers/permissions_policy.rb
new file mode 100644
index 0000000000..00f64d71b0
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/initializers/permissions_policy.rb
@@ -0,0 +1,11 @@
+# Define an application-wide HTTP permissions policy. For further
+# information see https://developers.google.com/web/updates/2018/06/feature-policy
+#
+# Rails.application.config.permissions_policy do |f|
+# f.camera :none
+# f.gyroscope :none
+# f.microphone :none
+# f.usb :none
+# f.fullscreen :self
+# f.payment :self, "https://secure.example.com"
+# end
diff --git a/utils/build/docker/ruby/rails71/config/locales/en.yml b/utils/build/docker/ruby/rails71/config/locales/en.yml
new file mode 100644
index 0000000000..8ca56fc74f
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/locales/en.yml
@@ -0,0 +1,33 @@
+# Files in the config/locales directory are used for internationalization
+# and are automatically loaded by Rails. If you want to use locales other
+# than English, add the necessary files in this directory.
+#
+# To use the locales, use `I18n.t`:
+#
+# I18n.t "hello"
+#
+# In views, this is aliased to just `t`:
+#
+# <%= t("hello") %>
+#
+# To use a different locale, set it with `I18n.locale`:
+#
+# I18n.locale = :es
+#
+# This would use the information in config/locales/es.yml.
+#
+# The following keys must be escaped otherwise they will not be retrieved by
+# the default I18n backend:
+#
+# true, false, on, off, yes, no
+#
+# Instead, surround them with single quotes.
+#
+# en:
+# "true": "foo"
+#
+# To learn more, please read the Rails Internationalization guide
+# available at https://guides.rubyonrails.org/i18n.html.
+
+en:
+ hello: "Hello world"
diff --git a/utils/build/docker/ruby/rails71/config/puma.rb b/utils/build/docker/ruby/rails71/config/puma.rb
new file mode 100644
index 0000000000..daaf036999
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/puma.rb
@@ -0,0 +1,43 @@
+# Puma can serve each request in a thread from an internal thread pool.
+# The `threads` method setting takes two numbers: a minimum and maximum.
+# Any libraries that use thread pools should be configured to match
+# the maximum value specified for Puma. Default is set to 5 threads for minimum
+# and maximum; this matches the default thread size of Active Record.
+#
+max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
+min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
+threads min_threads_count, max_threads_count
+
+# Specifies the `worker_timeout` threshold that Puma will use to wait before
+# terminating a worker in development environments.
+#
+worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
+
+# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
+#
+port ENV.fetch("PORT") { 3000 }
+
+# Specifies the `environment` that Puma will run in.
+#
+environment ENV.fetch("RAILS_ENV") { "development" }
+
+# Specifies the `pidfile` that Puma will use.
+pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
+
+# Specifies the number of `workers` to boot in clustered mode.
+# Workers are forked web server processes. If using threads and workers together
+# the concurrency of the application would be max `threads` * `workers`.
+# Workers do not work on JRuby or Windows (both of which do not support
+# processes).
+#
+# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
+
+# Use the `preload_app!` method when specifying a `workers` number.
+# This directive tells Puma to first boot the application and load code
+# before forking the application. This takes advantage of Copy On Write
+# process behavior so workers use less memory.
+#
+# preload_app!
+
+# Allow puma to be restarted by `bin/rails restart` command.
+plugin :tmp_restart
diff --git a/utils/build/docker/ruby/rails71/config/routes.rb b/utils/build/docker/ruby/rails71/config/routes.rb
new file mode 100644
index 0000000000..717c4b77da
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/routes.rb
@@ -0,0 +1,46 @@
+Rails.application.routes.draw do
+ # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
+
+ # Defines the root path route ("/")
+ # root "articles#index"
+
+ get '/' => 'system_test#root'
+ post '/' => 'system_test#root'
+
+ get '/waf' => 'system_test#waf'
+ post '/waf' => 'system_test#waf'
+ get '/waf/*other' => 'system_test#waf'
+ post '/waf/*other' => 'system_test#waf'
+
+ get '/kafka/produce' => 'system_test#kafka_produce'
+ get '/kafka/consume' => 'system_test#kafka_consume'
+
+ get '/params/:value' => 'system_test#handle_path_params'
+ get '/spans' => 'system_test#generate_spans'
+ get '/status' => 'system_test#status'
+ get '/read_file' => 'system_test#read_file'
+ get '/make_distant_call' => 'system_test#make_distant_call'
+
+ get '/headers' => 'system_test#test_headers'
+ get '/identify' => 'system_test#identify'
+
+ get 'user_login_success_event' => 'system_test#user_login_success_event'
+ get 'user_login_failure_event' => 'system_test#user_login_failure_event'
+ get 'custom_event' => 'system_test#custom_event'
+
+ %i(get post).each do |request_method|
+ send(request_method, '/tag_value/:tag_value/:status_code' => 'system_test#tag_value')
+ end
+
+ match '/tag_value/:tag_value/:status_code' => 'system_test#tag_value', via: :options
+
+ get '/users' => 'system_test#users'
+
+ devise_for :users
+ %i(get post).each do |request_method|
+ # We have to provide format: false to make sure the Test_DiscoveryScan test do not break
+ # https://github.com/DataDog/system-tests/blob/515310b5fb1fd0792fc283c9ee134ab3803d6e7c/tests/appsec/waf/test_rules.py#L374
+ # The test hits '/login.pwd' and expects a 404. By default rails parse format by default and consider the route to exists. We want want onlt '/login' to exists
+ send(request_method, '/login' => 'system_test#login', format: false)
+ end
+end
diff --git a/utils/build/docker/ruby/rails71/config/storage.yml b/utils/build/docker/ruby/rails71/config/storage.yml
new file mode 100644
index 0000000000..4942ab6694
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/config/storage.yml
@@ -0,0 +1,34 @@
+test:
+ service: Disk
+ root: <%= Rails.root.join("tmp/storage") %>
+
+local:
+ service: Disk
+ root: <%= Rails.root.join("storage") %>
+
+# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
+# amazon:
+# service: S3
+# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+# region: us-east-1
+# bucket: your_own_bucket-<%= Rails.env %>
+
+# Remember not to checkin your GCS keyfile to a repository
+# google:
+# service: GCS
+# project: your_project
+# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
+# bucket: your_own_bucket-<%= Rails.env %>
+
+# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
+# microsoft:
+# service: AzureStorage
+# storage_account_name: your_account_name
+# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
+# container: your_container_name-<%= Rails.env %>
+
+# mirror:
+# service: Mirror
+# primary: local
+# mirrors: [ amazon, google, microsoft ]
diff --git a/utils/build/docker/ruby/rails71/db/migrate/20230621141816_devise_create_users.rb b/utils/build/docker/ruby/rails71/db/migrate/20230621141816_devise_create_users.rb
new file mode 100644
index 0000000000..0f43e58c82
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/db/migrate/20230621141816_devise_create_users.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class DeviseCreateUsers < ActiveRecord::Migration[7.0]
+ def change
+ create_table :users, id: :string do |t|
+ ## Database authenticatable
+ t.string :username, null: false, default: ""
+ t.string :email, null: false, default: ""
+ t.string :encrypted_password, null: false, default: ""
+
+ ## Recoverable
+ t.string :reset_password_token
+ t.datetime :reset_password_sent_at
+
+ ## Rememberable
+ t.datetime :remember_created_at
+
+ ## Trackable
+ # t.integer :sign_in_count, default: 0, null: false
+ # t.datetime :current_sign_in_at
+ # t.datetime :last_sign_in_at
+ # t.string :current_sign_in_ip
+ # t.string :last_sign_in_ip
+
+ ## Confirmable
+ # t.string :confirmation_token
+ # t.datetime :confirmed_at
+ # t.datetime :confirmation_sent_at
+ # t.string :unconfirmed_email # Only if using reconfirmable
+
+ ## Lockable
+ # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
+ # t.string :unlock_token # Only if unlock strategy is :email or :both
+ # t.datetime :locked_at
+
+
+ t.timestamps null: false
+ end
+
+ add_index :users, :email, unique: true
+ add_index :users, :reset_password_token, unique: true
+ # add_index :users, :confirmation_token, unique: true
+ # add_index :users, :unlock_token, unique: true
+ end
+end
diff --git a/utils/build/docker/ruby/rails71/db/seeds.rb b/utils/build/docker/ruby/rails71/db/seeds.rb
new file mode 100644
index 0000000000..a09838ff3b
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/db/seeds.rb
@@ -0,0 +1,11 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
+#
+# Examples:
+#
+# movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }])
+# Character.create(name: "Luke", movie: movies.first)
+
+User.delete_all
+User.create!(:id => 'social-security-id', :username => 'test', :email => 'testuser@ddog.com', :password => '1234', :password_confirmation => '1234')
+User.create!(:id => '591dc126-8431-4d0f-9509-b23318d3dce4', :username => 'testuuid', :email => 'testuseruuid@ddog.com', :password => '1234', :password_confirmation => '1234')
diff --git a/utils/build/docker/ruby/rails71/lib/assets/.keep b/utils/build/docker/ruby/rails71/lib/assets/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/lib/tasks/.keep b/utils/build/docker/ruby/rails71/lib/tasks/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/public/404.html b/utils/build/docker/ruby/rails71/public/404.html
new file mode 100644
index 0000000000..2be3af26fc
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/public/404.html
@@ -0,0 +1,67 @@
+
+
+
+ The page you were looking for doesn't exist (404)
+
+
+
+
+
+
+
+
+
The page you were looking for doesn't exist.
+
You may have mistyped the address or the page may have moved.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/utils/build/docker/ruby/rails71/public/422.html b/utils/build/docker/ruby/rails71/public/422.html
new file mode 100644
index 0000000000..c08eac0d1d
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/public/422.html
@@ -0,0 +1,67 @@
+
+
+
+ The change you wanted was rejected (422)
+
+
+
+
+
+
+
+
+
The change you wanted was rejected.
+
Maybe you tried to change something you didn't have access to.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/utils/build/docker/ruby/rails71/public/500.html b/utils/build/docker/ruby/rails71/public/500.html
new file mode 100644
index 0000000000..78a030af22
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/public/500.html
@@ -0,0 +1,66 @@
+
+
+
+ We're sorry, but something went wrong (500)
+
+
+
+
+
+
+
+
+
We're sorry, but something went wrong.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/utils/build/docker/ruby/rails71/public/apple-touch-icon-precomposed.png b/utils/build/docker/ruby/rails71/public/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/public/apple-touch-icon.png b/utils/build/docker/ruby/rails71/public/apple-touch-icon.png
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/public/favicon.ico b/utils/build/docker/ruby/rails71/public/favicon.ico
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/public/robots.txt b/utils/build/docker/ruby/rails71/public/robots.txt
new file mode 100644
index 0000000000..c19f78ab68
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/public/robots.txt
@@ -0,0 +1 @@
+# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
diff --git a/utils/build/docker/ruby/rails71/storage/.keep b/utils/build/docker/ruby/rails71/storage/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/application_system_test_case.rb b/utils/build/docker/ruby/rails71/test/application_system_test_case.rb
new file mode 100644
index 0000000000..d19212abd5
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/test/application_system_test_case.rb
@@ -0,0 +1,5 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+end
diff --git a/utils/build/docker/ruby/rails71/test/channels/application_cable/connection_test.rb b/utils/build/docker/ruby/rails71/test/channels/application_cable/connection_test.rb
new file mode 100644
index 0000000000..800405f15e
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/test/channels/application_cable/connection_test.rb
@@ -0,0 +1,11 @@
+require "test_helper"
+
+class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
+ # test "connects with cookies" do
+ # cookies.signed[:user_id] = 42
+ #
+ # connect
+ #
+ # assert_equal connection.user_id, "42"
+ # end
+end
diff --git a/utils/build/docker/ruby/rails71/test/controllers/.keep b/utils/build/docker/ruby/rails71/test/controllers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/fixtures/files/.keep b/utils/build/docker/ruby/rails71/test/fixtures/files/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/helpers/.keep b/utils/build/docker/ruby/rails71/test/helpers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/integration/.keep b/utils/build/docker/ruby/rails71/test/integration/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/mailers/.keep b/utils/build/docker/ruby/rails71/test/mailers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/models/.keep b/utils/build/docker/ruby/rails71/test/models/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/system/.keep b/utils/build/docker/ruby/rails71/test/system/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/test/test_helper.rb b/utils/build/docker/ruby/rails71/test/test_helper.rb
new file mode 100644
index 0000000000..d713e377c9
--- /dev/null
+++ b/utils/build/docker/ruby/rails71/test/test_helper.rb
@@ -0,0 +1,13 @@
+ENV["RAILS_ENV"] ||= "test"
+require_relative "../config/environment"
+require "rails/test_help"
+
+class ActiveSupport::TestCase
+ # Run tests in parallel with specified workers
+ parallelize(workers: :number_of_processors)
+
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
+ fixtures :all
+
+ # Add more helper methods to be used by all tests here...
+end
diff --git a/utils/build/docker/ruby/rails71/tmp/.keep b/utils/build/docker/ruby/rails71/tmp/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/tmp/pids/.keep b/utils/build/docker/ruby/rails71/tmp/pids/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/tmp/storage/.keep b/utils/build/docker/ruby/rails71/tmp/storage/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/vendor/.keep b/utils/build/docker/ruby/rails71/vendor/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/utils/build/docker/ruby/rails71/vendor/javascript/.keep b/utils/build/docker/ruby/rails71/vendor/javascript/.keep
new file mode 100644
index 0000000000..e69de29bb2