diff --git a/README.md b/README.md index 1acca8234b..dfbc303204 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Using Bundler: ```ruby group :development do - gem 'brakeman' + gem 'brakeman', require: false end ``` diff --git a/docs/warning_types/command_injection/index.markdown b/docs/warning_types/command_injection/index.markdown index a342621216..20ed03eae4 100644 --- a/docs/warning_types/command_injection/index.markdown +++ b/docs/warning_types/command_injection/index.markdown @@ -10,4 +10,8 @@ There are many ways to run commands in Ruby: Brakeman will warn on any method like these that uses user input or unsafely interpolates variables. +You can use [`shellescape`](https://apidock.com/ruby/Shellwords/shellescape) to render a variable safe: + + `ls #{params[:file].shellescape}` + See [the Ruby Security Guide](http://guides.rubyonrails.org/security.html#command-line-injection) for details. diff --git a/gem_common.rb b/gem_common.rb index bd3159a76f..38e3da2d10 100644 --- a/gem_common.rb +++ b/gem_common.rb @@ -1,6 +1,7 @@ module Brakeman module GemDependencies def self.dev_dependencies spec + spec.add_development_dependency "csv" spec.add_development_dependency "minitest" spec.add_development_dependency "minitest-ci" spec.add_development_dependency "simplecov" diff --git a/lib/brakeman/checks/check_session_settings.rb b/lib/brakeman/checks/check_session_settings.rb index f117eadb88..cbd1424b0f 100644 --- a/lib/brakeman/checks/check_session_settings.rb +++ b/lib/brakeman/checks/check_session_settings.rb @@ -118,7 +118,7 @@ def check_secrets_yaml yaml = secrets_file.read require 'yaml' begin - secrets = YAML.safe_load yaml + secrets = YAML.safe_load yaml, aliases: true rescue Psych::SyntaxError, RuntimeError => e Brakeman.notify "[Notice] #{self.class}: Unable to parse `#{secrets_file}`" Brakeman.debug "Failed to parse #{secrets_file}: #{e.inspect}" diff --git a/lib/brakeman/options.rb b/lib/brakeman/options.rb index 73428d572b..857db864fc 100644 --- a/lib/brakeman/options.rb +++ b/lib/brakeman/options.rb @@ -101,6 +101,15 @@ def create_option_parser options options[:rails7] = true end + opts.on "-8", "--rails8", "Force Rails 8 mode" do + options[:rails3] = true + options[:rails4] = true + options[:rails5] = true + options[:rails6] = true + options[:rails7] = true + options[:rails8] = true + end + opts.separator "" opts.separator "Scanning options:" diff --git a/lib/brakeman/parsers/slim_embedded.rb b/lib/brakeman/parsers/slim_embedded.rb index a0970ce287..ceb730e89b 100644 --- a/lib/brakeman/parsers/slim_embedded.rb +++ b/lib/brakeman/parsers/slim_embedded.rb @@ -2,6 +2,7 @@ module Slim class Embedded class TiltEngine + alias_method :on_slim_embedded, :on_slim_embedded # silence redefined method warning def on_slim_embedded(engine, body, attrs) # Override this method to avoid Slim trying to load sass/scss and failing case engine @@ -22,6 +23,7 @@ def on_slim_embedded(engine, body, attrs) class SassEngine protected + alias_method :tilt_render, :tilt_render # silence redefined method warning def tilt_render(tilt_engine, tilt_options, text) [:dynamic, "BrakemanFilter.render(#{text.inspect}, #{self.class})"] diff --git a/lib/brakeman/processors/alias_processor.rb b/lib/brakeman/processors/alias_processor.rb index 4910670d1f..893328325c 100644 --- a/lib/brakeman/processors/alias_processor.rb +++ b/lib/brakeman/processors/alias_processor.rb @@ -665,7 +665,7 @@ def process_masgn exp exp[2] = exp[2][1] end - unless array? exp[1] and array? exp[2] and exp[1].length == exp[2].length + unless array? exp[1] and array? exp[2] return process_default(exp) end @@ -678,21 +678,42 @@ def process_masgn exp # Call each assignment as if it is normal vars.each_with_index do |var, i| val = vals[i] - if val + next unless val # TODO: Break if there are no vals left? - # This happens with nested destructuring like - # x, (a, b) = blah - if node_type? var, :masgn - # Need to add value to masgn exp - m = var.dup - m[2] = s(:to_ary, val) + # This happens with nested destructuring like + # x, (a, b) = blah + if node_type? var, :masgn + # Need to add value to masgn exp + m = var.dup + m[2] = s(:to_ary, val) - process_masgn m + process_masgn m + elsif node_type? var, :splat + # Assign the rest of the values to the variable: + # + # a, *b = 1, 2, 3 + # + # b == [2, 3] + + + assign = var[1].dup # var is s(:splat, s(:lasgn, :b)) + + if i == vars.length - 1 # Last variable being assigned, slurp up the rest + assign.rhs = s(:array, *vals[i..]) # val is the "rest" of the values else - assign = var.dup - assign.rhs = val - process assign + # Calculate how many values to assign based on how many variables + # there are. + # + # If there are more values than variables, the splat gets an empty array. + + assign.rhs = s(:array, *vals[i, (vals.length - vars.length + 1)]).line(vals.line) end + + process assign + else + assign = var.dup + assign.rhs = val + process assign end end diff --git a/lib/brakeman/tracker/config.rb b/lib/brakeman/tracker/config.rb index fb892be9ad..e4bc37d937 100644 --- a/lib/brakeman/tracker/config.rb +++ b/lib/brakeman/tracker/config.rb @@ -111,6 +111,14 @@ def set_rails_version version = nil tracker.options[:rails6] = true tracker.options[:rails7] = true Brakeman.notify "[Notice] Detected Rails 7 application" + elsif @rails_version.start_with? "8" + tracker.options[:rails3] = true + tracker.options[:rails4] = true + tracker.options[:rails5] = true + tracker.options[:rails6] = true + tracker.options[:rails7] = true + tracker.options[:rails8] = true + Brakeman.notify "[Notice] Detected Rails 8 application" end end end @@ -193,7 +201,7 @@ def load_rails_defaults version = tracker.config.rails[:load_defaults].value.to_s - unless version.match? /^\d+\.\d+$/ + unless version.match?(/^\d+\.\d+$/) Brakeman.debug "[Notice] Unknown version: #{tracker.config.rails[:load_defaults]}" return end diff --git a/lib/ruby_parser/bm_sexp.rb b/lib/ruby_parser/bm_sexp.rb index 43808698f7..abdee62fcd 100644 --- a/lib/ruby_parser/bm_sexp.rb +++ b/lib/ruby_parser/bm_sexp.rb @@ -6,6 +6,7 @@ class Sexp ASSIGNMENT_BOOL = [:gasgn, :iasgn, :lasgn, :cvdecl, :cvasgn, :cdecl, :or, :and, :colon2, :op_asgn_or] CALLS = [:call, :attrasgn, :safe_call, :safe_attrasgn] + alias_method :method_missing, :method_missing # silence redefined method warning def method_missing name, *args #Brakeman does not use this functionality, #so overriding it to raise a NoMethodError. @@ -46,10 +47,12 @@ def deep_clone line = nil s end + alias_method :paren, :paren # silence redefined method warning def paren @paren ||= false end + alias_method :value, :value # silence redefined method warning def value raise WrongSexpError, "Sexp#value called on multi-item Sexp: `#{self.inspect}`" if size > 2 self[1] @@ -98,6 +101,7 @@ def << arg old_push arg end + alias_method :hash, :hash # silence redefined method warning def hash #There still seems to be some instances in which the hash of the #Sexp changes, but I have not found what method call is doing it. @@ -616,7 +620,7 @@ def inspect seen = Set.new #Invalidate hash cache if the Sexp changes [:[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at, - :delete_if, :drop, :drop_while, :fill, :flatten!, :replace, :insert, + :delete_if, :drop, :drop_while, :fill, :flatten!, :insert, :keep_if, :map!, :pop, :push, :reject!, :replace, :reverse!, :rotate!, :select!, :shift, :shuffle!, :slice!, :sort!, :sort_by!, :transpose, :uniq!, :unshift].each do |method| diff --git a/test/apps/rails5.2/config/secrets.yml b/test/apps/rails5.2/config/secrets.yml index e69de29bb2..15b20e1cd1 100644 --- a/test/apps/rails5.2/config/secrets.yml +++ b/test/apps/rails5.2/config/secrets.yml @@ -0,0 +1,34 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rake secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +test_anchor: &test_anchor + abc: 123 + +development: + test_anchor: *test_anchor + secret_key_base: 12d3735e1cdb18ef2eca25f9a370028ac096ff273c5a889ed7a49047d5e30c9dc7fe095792a71b60c3f37dd80efaeda44db75e73c9f60813550c875eee7a241f + +test: + test_anchor: *test_anchor + secret_key_base: 446b08c3cdeccdaf9e8b247a2624d45218c5d429e8acde61ddd87aa7b9dd50973e49e6d94378cb4bcf08b7818a90abb044b5c8886f94de6970ade4a496df22f3 + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + test_anchor: *test_anchor + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> + +<% if Rails.root.join('config/ansible/secrets.yml').exist? %> +<%= Rails.root.join('config/ansible/secrets.yml').read %> +<% end %> + + diff --git a/test/apps/rails8/Gemfile b/test/apps/rails8/Gemfile new file mode 100644 index 0000000000..2738df56c8 --- /dev/null +++ b/test/apps/rails8/Gemfile @@ -0,0 +1,54 @@ +source "https://rubygems.org" + +# Use main development branch of Rails +gem "rails", "~> 8.0.0.alpha", github: "rails/rails", branch: "main" +# The modern asset pipeline for Rails [https://github.com/rails/propshaft] +gem "propshaft" +# Use sqlite3 as the database for Active Record +gem "sqlite3", ">= 1.4" +# Use the Puma web server [https://github.com/puma/puma] +gem "puma", ">= 5.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" +# Use Redis adapter to run Action Cable in production +gem "redis", ">= 4.0.1" + +# 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[ windows jruby ] + +# Reduces boot times through caching; required in config/boot.rb +gem "bootsnap", require: false + +# Deploy this application anywhere as a Docker container [https://kamal-deploy.org] +# gem "kamal", require: false + +# 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 windows ], require: "debug/prelude" + + # Static analysis for security vulnerabilities [https://brakemanscanner.org/] + # gem "brakeman", require: false + + # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/] + # gem "rubocop-rails-omakase", require: false +end + +group :development do + # Use console on exceptions pages [https://github.com/rails/web-console] + gem "web-console" +end diff --git a/test/apps/rails8/app/assets/stylesheets/application.css b/test/apps/rails8/app/assets/stylesheets/application.css new file mode 100644 index 0000000000..dcd72732ea --- /dev/null +++ b/test/apps/rails8/app/assets/stylesheets/application.css @@ -0,0 +1 @@ +/* Application styles */ diff --git a/test/apps/rails8/app/channels/application_cable/channel.rb b/test/apps/rails8/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/test/apps/rails8/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/test/apps/rails8/app/channels/application_cable/connection.rb b/test/apps/rails8/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/test/apps/rails8/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/test/apps/rails8/app/controllers/application_controller.rb b/test/apps/rails8/app/controllers/application_controller.rb new file mode 100644 index 0000000000..0d95db22b4 --- /dev/null +++ b/test/apps/rails8/app/controllers/application_controller.rb @@ -0,0 +1,4 @@ +class ApplicationController < ActionController::Base + # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. + allow_browser versions: :modern +end diff --git a/test/apps/rails8/app/helpers/application_helper.rb b/test/apps/rails8/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/test/apps/rails8/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/test/apps/rails8/app/javascript/application.js b/test/apps/rails8/app/javascript/application.js new file mode 100644 index 0000000000..0d7b49404c --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/app/javascript/controllers/application.js b/test/apps/rails8/app/javascript/controllers/application.js new file mode 100644 index 0000000000..1213e85c7a --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/app/javascript/controllers/hello_controller.js b/test/apps/rails8/app/javascript/controllers/hello_controller.js new file mode 100644 index 0000000000..5975c0789d --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/app/javascript/controllers/index.js b/test/apps/rails8/app/javascript/controllers/index.js new file mode 100644 index 0000000000..54ad4cad4d --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/app/jobs/application_job.rb b/test/apps/rails8/app/jobs/application_job.rb new file mode 100644 index 0000000000..d394c3d106 --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/app/mailers/application_mailer.rb b/test/apps/rails8/app/mailers/application_mailer.rb new file mode 100644 index 0000000000..3c34c8148f --- /dev/null +++ b/test/apps/rails8/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/test/apps/rails8/app/models/application_record.rb b/test/apps/rails8/app/models/application_record.rb new file mode 100644 index 0000000000..b63caeb8a5 --- /dev/null +++ b/test/apps/rails8/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/test/apps/rails8/app/views/layouts/application.html.erb b/test/apps/rails8/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..0983ca0749 --- /dev/null +++ b/test/apps/rails8/app/views/layouts/application.html.erb @@ -0,0 +1,24 @@ + + + + <%= content_for(:title) || "My App" %> + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= yield :head %> + + + + + + + <%= stylesheet_link_tag :all, "data-turbo-track": "reload" %> + <%= javascript_importmap_tags %> + + + + <%= yield %> + + diff --git a/test/apps/rails8/app/views/layouts/mailer.html.erb b/test/apps/rails8/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000000..3aac9002ed --- /dev/null +++ b/test/apps/rails8/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/test/apps/rails8/app/views/layouts/mailer.text.erb b/test/apps/rails8/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/test/apps/rails8/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/test/apps/rails8/app/views/pwa/manifest.json.erb b/test/apps/rails8/app/views/pwa/manifest.json.erb new file mode 100644 index 0000000000..242e0b294e --- /dev/null +++ b/test/apps/rails8/app/views/pwa/manifest.json.erb @@ -0,0 +1,22 @@ +{ + "name": "MyApp", + "icons": [ + { + "src": "/icon.png", + "type": "image/png", + "sizes": "512x512" + }, + { + "src": "/icon.png", + "type": "image/png", + "sizes": "512x512", + "purpose": "maskable" + } + ], + "start_url": "/", + "display": "standalone", + "scope": "/", + "description": "MyApp.", + "theme_color": "red", + "background_color": "red" +} diff --git a/test/apps/rails8/app/views/pwa/service-worker.js b/test/apps/rails8/app/views/pwa/service-worker.js new file mode 100644 index 0000000000..68d5c2ee66 --- /dev/null +++ b/test/apps/rails8/app/views/pwa/service-worker.js @@ -0,0 +1,26 @@ +// Add a service worker for processing Web Push notifications: +// +// self.addEventListener("push", async (event) => { +// const { title, options } = await event.data.json() +// event.waitUntil(self.registration.showNotification(title, options)) +// }) +// +// self.addEventListener("notificationclick", function(event) { +// event.notification.close() +// event.waitUntil( +// clients.matchAll({ type: "window" }).then((clientList) => { +// for (let i = 0; i < clientList.length; i++) { +// let client = clientList[i] +// let clientPath = (new URL(client.url)).pathname +// +// if (clientPath == event.notification.data.path && "focus" in client) { +// return client.focus() +// } +// } +// +// if (clients.openWindow) { +// return clients.openWindow(event.notification.data.path) +// } +// }) +// ) +// }) diff --git a/test/apps/rails8/bin/brakeman b/test/apps/rails8/bin/brakeman new file mode 100755 index 0000000000..ace1c9ba08 --- /dev/null +++ b/test/apps/rails8/bin/brakeman @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +ARGV.unshift("--ensure-latest") + +load Gem.bin_path("brakeman", "brakeman") diff --git a/test/apps/rails8/bin/importmap b/test/apps/rails8/bin/importmap new file mode 100755 index 0000000000..36502ab16c --- /dev/null +++ b/test/apps/rails8/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/test/apps/rails8/bin/kamal b/test/apps/rails8/bin/kamal new file mode 100755 index 0000000000..cbe59b95ed --- /dev/null +++ b/test/apps/rails8/bin/kamal @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'kamal' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("kamal", "kamal") diff --git a/test/apps/rails8/bin/rails b/test/apps/rails8/bin/rails new file mode 100755 index 0000000000..efc0377492 --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/bin/rake b/test/apps/rails8/bin/rake new file mode 100755 index 0000000000..4fbf10b960 --- /dev/null +++ b/test/apps/rails8/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/test/apps/rails8/bin/rubocop b/test/apps/rails8/bin/rubocop new file mode 100755 index 0000000000..40330c0ff1 --- /dev/null +++ b/test/apps/rails8/bin/rubocop @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +# explicit rubocop config increases performance slightly while avoiding config confusion. +ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) + +load Gem.bin_path("rubocop", "rubocop") diff --git a/test/apps/rails8/bin/setup b/test/apps/rails8/bin/setup new file mode 100755 index 0000000000..6ab7906897 --- /dev/null +++ b/test/apps/rails8/bin/setup @@ -0,0 +1,37 @@ +#!/usr/bin/env ruby +require "fileutils" + +APP_ROOT = File.expand_path("..", __dir__) +APP_NAME = "my_app" + +def system!(*args) + system(*args, exception: true) +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" + + # puts "\n== Configuring puma-dev ==" + # system "ln -nfs #{APP_ROOT} ~/.puma-dev/#{APP_NAME}" + # system "curl -Is https://#{APP_NAME}.test/up | head -n 1" +end diff --git a/test/apps/rails8/config.ru b/test/apps/rails8/config.ru new file mode 100644 index 0000000000..4a3c09a688 --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/config/application.rb b/test/apps/rails8/config/application.rb new file mode 100644 index 0000000000..294b283c0d --- /dev/null +++ b/test/apps/rails8/config/application.rb @@ -0,0 +1,42 @@ +require_relative "boot" + +require "rails" +# Pick the frameworks you want: +require "active_model/railtie" +require "active_job/railtie" +require "active_record/railtie" +require "active_storage/engine" +require "action_controller/railtie" +require "action_mailer/railtie" +require "action_mailbox/engine" +require "action_text/engine" +require "action_view/railtie" +require "action_cable/engine" +# require "rails/test_unit/railtie" + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module MyApp + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 8.0 + + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) + + # 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") + + # Don't generate system test files. + config.generators.system_tests = nil + end +end diff --git a/test/apps/rails8/config/boot.rb b/test/apps/rails8/config/boot.rb new file mode 100644 index 0000000000..988a5ddc46 --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/config/cable.yml b/test/apps/rails8/config/cable.yml new file mode 100644 index 0000000000..1163c48ef3 --- /dev/null +++ b/test/apps/rails8/config/cable.yml @@ -0,0 +1,11 @@ +development: + adapter: redis + url: redis://localhost:6379/1 + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: my_app_production diff --git a/test/apps/rails8/config/credentials.yml.enc b/test/apps/rails8/config/credentials.yml.enc new file mode 100644 index 0000000000..49c316fa50 --- /dev/null +++ b/test/apps/rails8/config/credentials.yml.enc @@ -0,0 +1 @@ +H0D18ePAXpz1hsN50y92mMXWQ81JfVpO4AcGAmekoYyhfKnV/axh7XnWCbo2QfCsMqtA3RFlexqE458SmUhC0ELC4XUKbf4YLlDZU3hPdC4AszUkqdZO5XxI9UT2HD77577sYni+mbbxpOESqMr7IvTDEpYvre79afPFBbodif8WEm6fQJVvQT4QbYsuRa1Rxg+cvtBh0MZZEhR2qGahs8b0xyHqKtRBts8NtDaDkM8E9nDQ6rm6/D6/cc9kLmLSvOrlLZcEZc999CyZKOwZKVETuGGGLWeGSL3XBMZdSI7lopzwHBSXn4bcYfuUI1gysxaIBu8X0Z/3Fb/dAIj3gpyE9kVJkC+82EoPpfrrNTu4W2FYxGX7PG+l58BBcpGCpzUOrW3KlOA6pPtwb9swkwlFunxl--I/0189+5PL944kTB--etq+j498EBV5ynkttoEY3w== \ No newline at end of file diff --git a/test/apps/rails8/config/database.yml b/test/apps/rails8/config/database.yml new file mode 100644 index 0000000000..4f787308dc --- /dev/null +++ b/test/apps/rails8/config/database.yml @@ -0,0 +1,28 @@ +# 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: storage/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: storage/test.sqlite3 + + +# Store production database in the storage/ directory, which by default +# is mounted as a persistent Docker volume in config/deploy.yml. +production: + <<: *default + database: storage/production.sqlite3 diff --git a/test/apps/rails8/config/deploy.yml b/test/apps/rails8/config/deploy.yml new file mode 100644 index 0000000000..d626493a69 --- /dev/null +++ b/test/apps/rails8/config/deploy.yml @@ -0,0 +1,87 @@ +# Name of your application. Used to uniquely configure containers. +service: my_app + +# Name of the container image. +image: your-user/my_app + +# Deploy to these servers. +servers: + web: + - 192.168.0.1 + # job: + # hosts: + # - 192.168.0.1 + # cmd: bin/solid_queue work + +# Credentials for your image host. +registry: + # Specify the registry server, if you're not using Docker Hub + # server: registry.digitalocean.com / ghcr.io / ... + username: your-user + + # Always use an access token rather than real password when possible. + password: + - KAMAL_REGISTRY_PASSWORD + +# Inject ENV variables into containers (secrets come from .env). +# Remember to run `kamal env push` after making changes! +env: + secret: + - RAILS_MASTER_KEY + # clear: + # DB_HOST: 192.168.0.2 + + +# Use a persistent storage volume for sqlite database files and local Active Storage files. +# Recommended to change this to a mounted volume path that is backed up off server. +volumes: + - "my_app_storage:/rails/storage" + + +# Bridge fingerprinted assets, like JS and CSS, between versions to avoid +# hitting 404 on in-flight requests. Combines all files from new and old +# version inside the asset_path. +asset_path: /rails/public/assets + +# Use a different ssh user than root +# ssh: +# user: app + +# Configure builder setup (defaults to multi-arch images). +# builder: +# # Build same-arch image locally (use for x86->x86) +# multiarch: false +# +# # Build diff-arch image via remote server +# remote: +# arch: amd64 +# host: ssh://app@192.168.0.1 +# +# args: +# RUBY_VERSION: ruby-3.3.0 +# secrets: +# - GITHUB_TOKEN +# - RAILS_MASTER_KEY + +# Use accessory services (secrets come from .env). +# accessories: +# db: +# image: mysql:8.0 +# host: 192.168.0.2 +# port: 3306 +# env: +# clear: +# MYSQL_ROOT_HOST: '%' +# secret: +# - MYSQL_ROOT_PASSWORD +# files: +# - config/mysql/production.cnf:/etc/mysql/my.cnf +# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql +# directories: +# - data:/var/lib/mysql +# redis: +# image: redis:7.0 +# host: 192.168.0.2 +# port: 6379 +# directories: +# - data:/data diff --git a/test/apps/rails8/config/environment.rb b/test/apps/rails8/config/environment.rb new file mode 100644 index 0000000000..cac5315775 --- /dev/null +++ b/test/apps/rails8/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/test/apps/rails8/config/environments/development.rb b/test/apps/rails8/config/environments/development.rb new file mode 100644 index 0000000000..62f6722c10 --- /dev/null +++ b/test/apps/rails8/config/environments/development.rb @@ -0,0 +1,71 @@ +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.enable_reloading = true + + # 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 + + config.action_mailer.default_url_options = { host: "localhost", port: 3000 } + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # 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 + + # Highlight code that enqueued background job in logs. + config.active_job.verbose_enqueue_logs = 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 + + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true + + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. + # config.generators.apply_rubocop_autocorrect_after_generate! +end diff --git a/test/apps/rails8/config/environments/production.rb b/test/apps/rails8/config/environments/production.rb new file mode 100644 index 0000000000..9ef7bcb115 --- /dev/null +++ b/test/apps/rails8/config/environments/production.rb @@ -0,0 +1,94 @@ +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.enable_reloading = false + + # 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 ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = 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.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = true + + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + # Log to STDOUT by default + config.logger = ActiveSupport::Logger.new(STDOUT) + .tap { |logger| logger.formatter = ::Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + + # 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 = "my_app_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 + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } +end diff --git a/test/apps/rails8/config/environments/test.rb b/test/apps/rails8/config/environments/test.rb new file mode 100644 index 0000000000..83d1fa9cc5 --- /dev/null +++ b/test/apps/rails8/config/environments/test.rb @@ -0,0 +1,59 @@ +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. + + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false + + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly 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.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 + + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable + + # 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 + + # Unlike controllers, the mailer instance doesn't have any context about the + # incoming request so you'll need to provide the :host parameter yourself. + config.action_mailer.default_url_options = { host: "www.example.com" } + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # 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 + + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true +end diff --git a/test/apps/rails8/config/importmap.rb b/test/apps/rails8/config/importmap.rb new file mode 100644 index 0000000000..909dfc542d --- /dev/null +++ b/test/apps/rails8/config/importmap.rb @@ -0,0 +1,7 @@ +# Pin npm packages by running ./bin/importmap + +pin "application" +pin "@hotwired/turbo-rails", to: "turbo.min.js" +pin "@hotwired/stimulus", to: "stimulus.min.js" +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/test/apps/rails8/config/initializers/assets.rb b/test/apps/rails8/config/initializers/assets.rb new file mode 100644 index 0000000000..487324424f --- /dev/null +++ b/test/apps/rails8/config/initializers/assets.rb @@ -0,0 +1,7 @@ +# 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 diff --git a/test/apps/rails8/config/initializers/content_security_policy.rb b/test/apps/rails8/config/initializers/content_security_policy.rb new file mode 100644 index 0000000000..b3076b38fe --- /dev/null +++ b/test/apps/rails8/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# 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, inline scripts, and inline styles. +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src style-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/test/apps/rails8/config/initializers/filter_parameter_logging.rb b/test/apps/rails8/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000..c010b83ddd --- /dev/null +++ b/test/apps/rails8/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. +# Use this to limit dissemination of sensitive information. +# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/test/apps/rails8/config/initializers/inflections.rb b/test/apps/rails8/config/initializers/inflections.rb new file mode 100644 index 0000000000..3860f659ea --- /dev/null +++ b/test/apps/rails8/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/test/apps/rails8/config/initializers/permissions_policy.rb b/test/apps/rails8/config/initializers/permissions_policy.rb new file mode 100644 index 0000000000..7db3b9577e --- /dev/null +++ b/test/apps/rails8/config/initializers/permissions_policy.rb @@ -0,0 +1,13 @@ +# Be sure to restart your server when you modify this file. + +# 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 |policy| +# policy.camera :none +# policy.gyroscope :none +# policy.microphone :none +# policy.usb :none +# policy.fullscreen :self +# policy.payment :self, "https://secure.example.com" +# end diff --git a/test/apps/rails8/config/locales/en.yml b/test/apps/rails8/config/locales/en.yml new file mode 100644 index 0000000000..6c349ae5e3 --- /dev/null +++ b/test/apps/rails8/config/locales/en.yml @@ -0,0 +1,31 @@ +# 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. +# +# To learn more about the API, please read the Rails Internationalization guide +# at https://guides.rubyonrails.org/i18n.html. +# +# Be aware that YAML interprets the following case-insensitive strings as +# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings +# must be quoted to be interpreted as strings. For example: +# +# en: +# "yes": yup +# enabled: "ON" + +en: + hello: "Hello world" diff --git a/test/apps/rails8/config/master.key b/test/apps/rails8/config/master.key new file mode 100644 index 0000000000..922dbd5ec5 --- /dev/null +++ b/test/apps/rails8/config/master.key @@ -0,0 +1 @@ +14cad5d3e84a5abfc93a8d61873a7f66 \ No newline at end of file diff --git a/test/apps/rails8/config/puma.rb b/test/apps/rails8/config/puma.rb new file mode 100644 index 0000000000..f976b8aa37 --- /dev/null +++ b/test/apps/rails8/config/puma.rb @@ -0,0 +1,54 @@ +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. + +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. +# +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# prioritize throughput over latency. +# +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. +# +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. +# +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) +threads threads_count, threads_count + +# Specifies the `environment` that Puma will run in. +rails_env = ENV.fetch("RAILS_ENV", "development") +environment rails_env + +case rails_env +when "production" + # If you are running more than 1 thread per process, the workers count + # should be equal to the number of processors (CPU cores) in production. + # + # Automatically detect the number of available processors in production. + require "concurrent-ruby" + workers_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.available_processor_count }) + workers workers_count if workers_count > 1 + + preload_app! +when "development" + # Specifies a very generous `worker_timeout` so that the worker + # isn't killed by Puma when suspended by a debugger. + worker_timeout 3600 +end + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +port ENV.fetch("PORT", 3000) + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart + +# Only use a pidfile when requested +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/test/apps/rails8/config/routes.rb b/test/apps/rails8/config/routes.rb new file mode 100644 index 0000000000..33c9639036 --- /dev/null +++ b/test/apps/rails8/config/routes.rb @@ -0,0 +1,14 @@ +Rails.application.routes.draw do + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. + # Can be used by load balancers and uptime monitors to verify that the app is live. + get "up" => "rails/health#show", as: :rails_health_check + + # Render dynamic PWA files from app/views/pwa/* + get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker + get "manifest" => "rails/pwa#manifest", as: :pwa_manifest + + # Defines the root path route ("/") + # root "posts#index" +end diff --git a/test/apps/rails8/config/storage.yml b/test/apps/rails8/config/storage.yml new file mode 100644 index 0000000000..4942ab6694 --- /dev/null +++ b/test/apps/rails8/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/test/tests/alias_processor.rb b/test/tests/alias_processor.rb index e1f653a061..e1bb7aef91 100644 --- a/test/tests/alias_processor.rb +++ b/test/tests/alias_processor.rb @@ -1010,6 +1010,38 @@ def test_branch_with_self_assign_target INPUT end + def test_splat_assign + assert_alias '[[3, 4]]', <<-INPUT + x, y, *z = [1, 2, [3, 4]] + z + INPUT + + assert_alias '[3, 4]', <<-INPUT + x, y, *z = 1, 2, 3, 4 + z + INPUT + + assert_alias '[2, 3]', <<-INPUT + a, *b, c = 1, 2, 3, 4 + b + INPUT + + assert_alias '[2]', <<-INPUT + a, *b, c, d = 1, 2, 3, 4 + b + INPUT + + assert_alias '[]', <<-INPUT + a, *b, c, d = 1, 2, 3 + b + INPUT + + assert_alias '[[]]', <<-INPUT + *a = [[]] + a + INPUT + end + def test_presence_in_all_literals assert_alias "'1'", <<-INPUT x = '1'.presence_in ['1', '2', '3'] diff --git a/test/tests/options.rb b/test/tests/options.rb index e7ed28e30c..d49c4fdcc5 100644 --- a/test/tests/options.rb +++ b/test/tests/options.rb @@ -10,6 +10,7 @@ class BrakemanOptionsTest < Minitest::Test :rails5 => "-5", :rails6 => "-6", :rails7 => "-7", + :rails8 => "-8", :run_all_checks => "-A", :assume_all_routes => "-a", :escape_html => "-e", @@ -40,6 +41,7 @@ class BrakemanOptionsTest < Minitest::Test :rails5 => "--rails5", :rails6 => "--rails6", :rails7 => "--rails7", + :rails8 => "--rails8", :run_all_checks => "--run-all-checks", :escape_html => "--escape-html", :debug => "--debug", diff --git a/test/tests/rails8.rb b/test/tests/rails8.rb new file mode 100644 index 0000000000..39f388ec3d --- /dev/null +++ b/test/tests/rails8.rb @@ -0,0 +1,22 @@ +require_relative "../test" + +class Rails8Tests < Minitest::Test + include BrakemanTester::FindWarning + include BrakemanTester::CheckExpected + + def report + @@report ||= + Date.stub :today, Date.parse("2024-05-13") do + BrakemanTester.run_scan "rails8", "Rails 8", run_all_checks: true + end + end + + def expected + @@expected ||= { + controller: 0, + model: 0, + template: 0, + warning: 0 + } + end +end diff --git a/test/tests/report_generation.rb b/test/tests/report_generation.rb index 3aff3dfb6e..c8138ad7fd 100644 --- a/test/tests/report_generation.rb +++ b/test/tests/report_generation.rb @@ -19,7 +19,7 @@ def test_html_sanity def test_table_sanity require 'highline/io_console_compatible' # For StringIO compatibility - report = @@report.to_table + @@report.to_table end def test_json_sanity