From f8d63ba0a3b78f3e0dc73642bf884929d6e4988c Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 11:30:10 -0400 Subject: [PATCH 01/22] APP_ENV => RACK_ENV --- Rakefile | 2 +- config.ru | 2 +- config/deploy.rb | 4 ---- lib/application_configuration.rb | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Rakefile b/Rakefile index eff8250..5134565 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,7 @@ $LOAD_PATH.unshift File.join(__dir__, 'lib') require 'bundler' -env = ENV['APP_ENV'] || 'development' +env = ENV['RACK_ENV'] || 'development' Bundler.require(:default, env) require 'application_configuration' diff --git a/config.ru b/config.ru index b51d6cb..21b2e9a 100644 --- a/config.ru +++ b/config.ru @@ -3,7 +3,7 @@ $LOAD_PATH.unshift File.join(__dir__, 'lib') require 'bundler' -env = ENV['APP_ENV'] = ENV.fetch('RACK_ENV', 'development') +env = ENV.fetch('RACK_ENV', 'development') Bundler.require(:default, env) require 'application_configuration' diff --git a/config/deploy.rb b/config/deploy.rb index 855bf36..76c4d69 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -6,10 +6,6 @@ set :application, 'dev-training-web' set :repo_url, 'https://github.com/umts/dev-training-web.git' set :branch, 'main' - -set :app_env, fetch(:stage) -set :default_env, { APP_ENV: fetch(:app_env) } - set :deploy_to, "/srv/#{fetch :application}" set :keep_releases, 5 diff --git a/lib/application_configuration.rb b/lib/application_configuration.rb index a81a7cc..2b80aff 100644 --- a/lib/application_configuration.rb +++ b/lib/application_configuration.rb @@ -16,7 +16,7 @@ def self.load! Figaro.adapter = Figaro::Application Figaro.application = Figaro::Application.new( path: config_file, - environment: ENV['APP_ENV'] || 'development' + environment: ENV['RACK_ENV'] || 'development' ) Figaro.load end From b0232bcd597b2ba066e344edfd0c38a8faae5026 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 11:35:24 -0400 Subject: [PATCH 02/22] load app via environment file --- Rakefile | 6 +----- config.ru | 8 ++------ config/environment.rb | 5 +++++ script/console | 5 +---- spec/spec_helper.rb | 6 ++---- 5 files changed, 11 insertions(+), 19 deletions(-) create mode 100644 config/environment.rb diff --git a/Rakefile b/Rakefile index 5134565..65fff5d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,10 +1,6 @@ # frozen_string_literal: true -$LOAD_PATH.unshift File.join(__dir__, 'lib') - -require 'bundler' -env = ENV['RACK_ENV'] || 'development' -Bundler.require(:default, env) +require_relative 'config/environment' require 'application_configuration' ApplicationConfiguration.load! diff --git a/config.ru b/config.ru index 21b2e9a..5256b0c 100644 --- a/config.ru +++ b/config.ru @@ -1,10 +1,6 @@ # frozen_string_literal: true -$LOAD_PATH.unshift File.join(__dir__, 'lib') - -require 'bundler' -env = ENV.fetch('RACK_ENV', 'development') -Bundler.require(:default, env) +require_relative 'config/environment' require 'application_configuration' ApplicationConfiguration.load! @@ -12,5 +8,5 @@ ApplicationConfiguration.load! require 'application_assets' require 'dev_training_application' -map(ApplicationAssets::ASSET_ROOT) { run ApplicationAssets.new } unless env == 'production' +map(ApplicationAssets::ASSET_ROOT) { run ApplicationAssets.new } if ENV.fetch('RACK_ENV', 'development') != 'production' map('/') { run DevTrainingApplication } diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..413c35a --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path('../lib', __dir__) +require 'bundler/setup' +Bundler.require(:default, ENV.fetch('RACK_ENV', 'development')) diff --git a/script/console b/script/console index 36e69d7..df34a17 100755 --- a/script/console +++ b/script/console @@ -1,10 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'bundler' - -$LOAD_PATH.unshift File.join(__dir__, '..', 'lib') -Bundler.require(:default, :development) +require_relative '../config/environment' require 'application_configuration' ApplicationConfiguration.load! diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8b9bbde..fb645d8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -require 'bundler' -Bundler.require(:default, :test) - SimpleCov.start do enable_coverage :branch load_profile 'test_frameworks' @@ -10,7 +7,8 @@ track_files 'lib/**/*.rb' end -$LOAD_PATH.unshift File.join(__dir__, '..', 'lib') +ENV['RACK_ENV'] = 'test' +require_relative 'config/environment' Dir.glob(File.join(__dir__, 'support/**/*.rb')).each { |f| require f } From f083d3033a57571e856e3bebd23af1fb33224fe9 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 11:39:58 -0400 Subject: [PATCH 03/22] fix rakefile --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 65fff5d..8b45475 100644 --- a/Rakefile +++ b/Rakefile @@ -23,7 +23,7 @@ namespace :assets do end # rubocop:enable Rake/Desc -unless env == 'production' +unless ENV.fetch('RACK_ENV', 'development') == 'production' require 'fileutils' require 'haml_lint/rake_task' require 'rdoc/task' From 049ab145eb4755c4faf8ca389528045451664622 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:00:30 -0400 Subject: [PATCH 04/22] typoed simplecov... somehow --- spec/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fb645d8..e481347 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -SimpleCov.start do +Simplecov.start do enable_coverage :branch load_profile 'test_frameworks' add_filter %r{^/vendor/} From e46eb71f18cf3b3d58319dfe7fe97c43bf7f999c Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:01:23 -0400 Subject: [PATCH 05/22] try best to not interrupt deployment --- config/deploy.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/deploy.rb b/config/deploy.rb index 76c4d69..cf43434 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -8,6 +8,9 @@ set :branch, 'main' set :deploy_to, "/srv/#{fetch :application}" +set :app_env, fetch(:stage) +set :default_env, { RACK_ENV: fetch(:app_env) } + set :keep_releases, 5 append :linked_files, 'config/application.yml' From feff4392aa72dcffdc337b6435e8469c2f6f0035 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:15:54 -0400 Subject: [PATCH 06/22] actually fix spec --- coverage/.last_run.json | 2 +- spec/spec_helper.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/coverage/.last_run.json b/coverage/.last_run.json index ed8dbab..3c48834 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,6 +1,6 @@ { "result": { - "line": 98.11, + "line": 98.13, "branch": 85.71 } } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e481347..62649ff 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -Simplecov.start do +require 'simplecov' +SimpleCov.start do enable_coverage :branch load_profile 'test_frameworks' add_filter %r{^/vendor/} @@ -8,7 +9,7 @@ end ENV['RACK_ENV'] = 'test' -require_relative 'config/environment' +require_relative '../config/environment' Dir.glob(File.join(__dir__, 'support/**/*.rb')).each { |f| require f } From b6a1a2b1f282b96fba7be7759eb80a75d82d00e9 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 11:48:27 -0400 Subject: [PATCH 07/22] set up credentials infrastructure --- .gitignore | 2 + Gemfile | 2 + Gemfile.lock | 122 ++++++++++++++++++++++---------- Rakefile | 30 ++++++++ config/credentials.rb | 10 +++ config/dev-training-web.yml.enc | 1 + config/environment.rb | 1 + 7 files changed, 131 insertions(+), 37 deletions(-) create mode 100644 config/credentials.rb create mode 100644 config/dev-training-web.yml.enc diff --git a/.gitignore b/.gitignore index aec881a..677acf3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ /node_modules /public/assets /spec/examples.txt + +*.key diff --git a/Gemfile b/Gemfile index c8cfb15..fbf3c49 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,7 @@ source 'https://rubygems.org' ruby file: '.ruby-version' +gem 'activesupport', require: 'active_support/all' gem 'faraday-retry' gem 'figaro' gem 'haml' @@ -33,6 +34,7 @@ group :development do gem 'ed25519', require: false gem 'haml_lint', require: false gem 'irb' + gem 'railties', require: false gem 'rdoc', require: false gem 'rubocop', require: false gem 'rubocop-rake', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 0198094..1e8d1d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,35 @@ GEM remote: https://rubygems.org/ specs: + actionpack (8.1.3) + actionview (= 8.1.3) + activesupport (= 8.1.3) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actionview (8.1.3) + activesupport (= 8.1.3) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activesupport (8.1.3) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.9) public_suffix (>= 2.0.2, < 8.0) airbrussh (1.6.0) @@ -9,8 +38,8 @@ GEM base64 (0.3.0) bcrypt_pbkdf (1.1.2) bcrypt_pbkdf (1.1.2-arm64-darwin) - bcrypt_pbkdf (1.1.2-x86_64-darwin) bigdecimal (4.0.1) + builder (3.3.0) capistrano (3.20.0) airbrussh (>= 1.0.0) i18n @@ -26,14 +55,18 @@ GEM capistrano (~> 3.1) capistrano-bundler (>= 1.1, < 3) concurrent-ruby (1.3.6) + connection_pool (3.0.2) + crass (1.0.6) date (3.5.1) debug (1.11.1) irb (~> 1.10) reline (>= 0.3.8) diff-lcs (1.6.2) docile (1.4.0) + drb (2.2.3) ed25519 (1.4.0) erb (6.0.1) + erubi (1.13.1) faker (3.6.1) i18n (>= 1.8.11, < 2) faraday (2.14.1) @@ -49,15 +82,6 @@ GEM google-protobuf (4.34.1-arm64-darwin) bigdecimal rake (~> 13.3) - google-protobuf (4.34.1-x86-linux-gnu) - bigdecimal - rake (~> 13.3) - google-protobuf (4.34.1-x86_64-darwin) - bigdecimal - rake (~> 13.3) - google-protobuf (4.34.1-x86_64-linux-gnu) - bigdecimal - rake (~> 13.3) haml (7.2.0) temple (>= 0.8.2) thor @@ -82,7 +106,12 @@ GEM language_server-protocol (3.17.0.5) lint_roller (1.1.0) logger (1.7.0) - mini_portile2 (2.8.9) + loofah (2.25.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + minitest (6.0.3) + drb (~> 2.0) + prism (~> 1.5) multi_xml (0.8.1) bigdecimal (>= 3.1, < 5) mustermann (3.0.4) @@ -95,15 +124,8 @@ GEM net-ssh (>= 5.0.0, < 8.0.0) net-ssh (7.3.0) nio4r (2.7.5) - nokogiri (1.19.1) - mini_portile2 (~> 2.8.2) - racc (~> 1.4) nokogiri (1.19.1-arm64-darwin) racc (~> 1.4) - nokogiri (1.19.1-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.19.1-x86_64-linux-gnu) - racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) @@ -150,6 +172,24 @@ GEM rack (>= 3.0.0) rack-test (2.2.0) rack (>= 1.3) + rackup (2.3.1) + rack (>= 3) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.3.1) rdoc (7.2.0) @@ -202,13 +242,10 @@ GEM rake (>= 13) sass-embedded (1.98.0-arm64-darwin) google-protobuf (~> 4.31) - sass-embedded (1.98.0-x86_64-darwin) - google-protobuf (~> 4.31) - sass-embedded (1.98.0-x86_64-linux-gnu) - google-protobuf (~> 4.31) sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) + securerandom (0.4.1) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -245,20 +282,22 @@ GEM thor (1.5.0) tilt (2.7.0) tsort (0.2.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.2.0) uri (1.1.1) + useragent (0.16.11) version_gem (1.1.3) + zeitwerk (2.7.5) PLATFORMS arm64-darwin arm64-darwin-22 - x86-linux-gnu - x86_64-darwin - x86_64-linux DEPENDENCIES + activesupport bcrypt_pbkdf capistrano (~> 3.20) capistrano-bundler @@ -277,6 +316,7 @@ DEPENDENCIES omniauth-github puma rack-test + railties rake rdoc rspec @@ -291,35 +331,39 @@ DEPENDENCIES tilt CHECKSUMS + actionpack (8.1.3) sha256=af998cae4d47c5d581a2cc363b5c77eb718b7c4b45748d81b1887b25621c29a3 + actionview (8.1.3) sha256=1347c88c7f3edb38100c5ce0e9fb5e62d7755f3edc1b61cce2eb0b2c6ea2fd5d + activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e addressable (2.8.9) sha256=cc154fcbe689711808a43601dee7b980238ce54368d23e127421753e46895485 airbrussh (1.6.0) sha256=7e2cf581f2319d2c2b2b672c9fc486efb4dfcfed4bd2dadbef5f10b8b2a000d0 ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b bcrypt_pbkdf (1.1.2) sha256=c2414c23ce66869b3eb9f643d6a3374d8322dfb5078125c82792304c10b94cf6 bcrypt_pbkdf (1.1.2-arm64-darwin) sha256=afdd6feb6ed5a97b8e44caacb3f2d641b98af78e6a516d4a3520b69af5cf9fea - bcrypt_pbkdf (1.1.2-x86_64-darwin) sha256=35f5639d0058e6c2cc2f856f9c0b14080543268d3047abe6bc81c513093caa0e bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7 + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f capistrano (3.20.0) sha256=0113e58dda99add0342e56a244f664734c59f442c5ed734f5303b0b559b479c9 capistrano-bundler (2.2.0) sha256=47b4cf2ea17ea132bb0a5cabc5663443f5190a54f4da5b322d04e1558ff1468c capistrano-passenger (0.2.1) sha256=07a1d25edd5c1d909c19d4fe45fe2ea5f11200569f6967f6bff1d605ade98e13 capistrano-pending (0.2.0) sha256=f9e8c1e6b6a2ce760ed49ccb470c474f802c1d453704fb62d67ca4c1ee547066 capistrano-rails (1.7.0) sha256=aca57455e8c5435785e0f938e16aa5b79c263694a755e1dca1c5d1743b40aae7 concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab + connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a + crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 docile (1.4.0) sha256=5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3 + drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 ed25519 (1.4.0) sha256=16e97f5198689a154247169f3453ef4cfd3f7a47481fde0ae33206cdfdcac506 erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5 + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 faker (3.6.1) sha256=c513d23c1d26b426283e913b25e0b714576011d7c1ad368a9ac6ea2113a1ccde faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe figaro (1.3.0) sha256=3d44396f080255663f183572d7aefa419fd8936b6fb5cc30f962345a02781396 google-protobuf (4.34.1-arm64-darwin) sha256=2745061f973119e6e7f3c81a0c77025d291a3caa6585a2cd24a25bbc7bedb267 - google-protobuf (4.34.1-x86-linux-gnu) sha256=b6da7891fe96b13038e5435d8ac8b8a84d78a468147a48a377fe8da40aba1c88 - google-protobuf (4.34.1-x86_64-darwin) sha256=4dc498376e218871613589c4d872400d42ad9ae0c700bdb2606fe1c77a593075 - google-protobuf (4.34.1-x86_64-linux-gnu) sha256=87088c9fd8e47b5b40ca498fc1195add6149e941ff7e81c532a5b0b8876d4cc9 haml (7.2.0) sha256=87fd2b71f7feab1724337b090a7d767f5ab2d42f08c974f3ead673f18cfcd55a haml_lint (0.72.0) sha256=23acb3f5db1602eb99bccec8009372465321702e1229017cca53272957bfc9c8 hashie (5.0.0) sha256=9d6c4e51f2a36d4616cbc8a322d619a162d8f42815a792596039fc95595603da @@ -331,7 +375,8 @@ CHECKSUMS language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 - mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 + loofah (2.25.1) sha256=d436c73dbd0c1147b16c4a41db097942d217303e1f7728704b37e4df9f6d2e04 + minitest (6.0.3) sha256=88ac8a1de36c00692420e7cb3cc11a0773bbcb126aee1c249f320160a7d11411 multi_xml (0.8.1) sha256=addba0290bac34e9088bfe73dc4878530297a82a7bbd66cb44dcd0a4b86edf5a mustermann (3.0.4) sha256=85fadcb6b3c6493a8b511b42426f904b7f27b282835502233dd154daab13aa22 net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996 @@ -339,10 +384,7 @@ CHECKSUMS net-sftp (4.0.0) sha256=65bb91c859c2f93b09826757af11b69af931a3a9155050f50d1b06d384526364 net-ssh (7.3.0) sha256=172076c4b30ce56fb25a03961b0c4da14e1246426401b0f89cba1a3b54bf3ef0 nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 - nokogiri (1.19.1) sha256=598b327f36df0b172abd57b68b18979a6e14219353bca87180c31a51a00d5ad3 nokogiri (1.19.1-arm64-darwin) sha256=dfe2d337e6700eac47290407c289d56bcf85805d128c1b5a6434ddb79731cb9e - nokogiri (1.19.1-x86_64-darwin) sha256=7093896778cc03efb74b85f915a775862730e887f2e58d6921e3fa3d981e68bf - nokogiri (1.19.1-x86_64-linux-gnu) sha256=1a4902842a186b4f901078e692d12257678e6133858d0566152fe29cdb98456a oauth2 (2.0.9) sha256=b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb octokit (10.0.0) sha256=82e99a539b7637b7e905e6d277bb0c1a4bed56735935cc33db6da7eae49a24e8 omniauth (2.1.2) sha256=def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce @@ -362,6 +404,10 @@ CHECKSUMS rack-protection (4.2.1) sha256=cf6e2842df8c55f5e4d1a4be015e603e19e9bc3a7178bae58949ccbb58558bac rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9 rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 + rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 + rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d + rails-html-sanitizer (1.7.0) sha256=28b145cceaf9cc214a9874feaa183c3acba036c9592b19886e0e45efc62b1e89 + railties (8.1.3) sha256=913eb0e0cb520aac687ffd74916bd726d48fa21f47833c6292576ef6a286de22 rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192 @@ -381,9 +427,8 @@ CHECKSUMS ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef sass-embedded (1.98.0) sha256=397dcd0071170f079eb97562a035fa113358af10e3ff759a57bc7eef763e9f94 sass-embedded (1.98.0-arm64-darwin) sha256=fed4ee6de2f30b14e7a678ca648730aa78acc86be7a555e16ba3fdbc5e6aca69 - sass-embedded (1.98.0-x86_64-darwin) sha256=a0b5b64f0157e2f1d713ac5ea75474c8507c464f0923090094471c33d4244484 - sass-embedded (1.98.0-x86_64-linux-gnu) sha256=36b72021e00cfdd91ccb9eb490cff6addc376424cf9c2786f01392c8d0f0d4a0 sawyer (0.9.2) sha256=fa3a72d62a4525517b18857ddb78926aab3424de0129be6772a8e2ba240e7aca + securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5 simplecov-html (0.12.3) sha256=4b1aad33259ffba8b29c6876c12db70e5750cb9df829486e4c6e5da4fa0aa07b simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 @@ -398,13 +443,16 @@ CHECKSUMS thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3 tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42 unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 + useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 version_gem (1.1.3) sha256=07ba4b679abc44198950d191a994d5a504f8f6aad470178e491467f638d0df60 + zeitwerk (2.7.5) sha256=d8da92128c09ea6ec62c949011b00ed4a20242b255293dd66bf41545398f73dd RUBY VERSION - ruby 3.4.8p72 + ruby 3.4.8p72 BUNDLED WITH - 4.0.3 + 4.0.3 diff --git a/Rakefile b/Rakefile index 8b45475..ecb84f9 100644 --- a/Rakefile +++ b/Rakefile @@ -23,6 +23,36 @@ namespace :assets do end # rubocop:enable Rake/Desc +namespace :credentials do + desc 'Outputs the credentials stored in `ARGV[1]` (used by diff helper)' + task :diff do + credentials = ActiveSupport::EncryptedConfiguration.new( + config_path: File.expand_path(ARGV[1], __dir__), + key_path: CREDENTIALS.key_path, + env_key: CREDENTIALS.env_key, + raise_if_missing_key: false + ) + begin + puts credentials.read.presence || credentials.content_path.read + rescue ActiveSupport::MessageEncryptor::InvalidMessage + puts credentials.content_path.read + end + end + + desc 'Edit the credentials file using the system editor' + task :edit do + require 'rails/command/helpers/editor' + include Rails::Command::Helpers::Editor + + using_system_editor { CREDENTIALS.change { |tempfile| system_editor(tempfile) } } + end + + desc 'Show the credentials stored in the credentials file' + task :show do + puts CREDENTIALS.read.presence || 'No decryptable credentials found' + end +end + unless ENV.fetch('RACK_ENV', 'development') == 'production' require 'fileutils' require 'haml_lint/rake_task' diff --git a/config/credentials.rb b/config/credentials.rb new file mode 100644 index 0000000..4b58275 --- /dev/null +++ b/config/credentials.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'active_support/encrypted_configuration' + +CREDENTIALS = ActiveSupport::EncryptedConfiguration.new( + config_path: File.expand_path('dev-training-web.yml.enc', __dir__), + key_path: File.expand_path('dev-training-web.key', __dir__), + env_key: 'MASTER_KEY', + raise_if_missing_key: false +) diff --git a/config/dev-training-web.yml.enc b/config/dev-training-web.yml.enc new file mode 100644 index 0000000..ba405bd --- /dev/null +++ b/config/dev-training-web.yml.enc @@ -0,0 +1 @@ +MPiSCh4=--ArXAlqTfoT1OgGMY--NLmLNJ6iu8NP6M78wFjflQ== \ No newline at end of file diff --git a/config/environment.rb b/config/environment.rb index 413c35a..d4c9569 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -3,3 +3,4 @@ $LOAD_PATH.unshift File.expand_path('../lib', __dir__) require 'bundler/setup' Bundler.require(:default, ENV.fetch('RACK_ENV', 'development')) +require_relative 'credentials' From 83aa39080a35cba79f228084425ef56115bbfb89 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 11:53:39 -0400 Subject: [PATCH 08/22] write production secrets --- config/dev-training-web.yml.enc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/dev-training-web.yml.enc b/config/dev-training-web.yml.enc index ba405bd..9cb2b74 100644 --- a/config/dev-training-web.yml.enc +++ b/config/dev-training-web.yml.enc @@ -1 +1 @@ -MPiSCh4=--ArXAlqTfoT1OgGMY--NLmLNJ6iu8NP6M78wFjflQ== \ No newline at end of file +YynZDONO7hVxzFtqmWG/jS+gvGDIeeXI8k1w96+hqpt4Un21ejPs2oX5QC6atuqtg7YVeA120QcT0MGjywtq/uKQ1pk4/RO85rWOlOd/+kvAVxSKsPNSDCtJ2iZzVj671fIZJe9+gh9f5wY8Rq3I0WOtpVhQ73D0sLQmFmPLmqL2O4FA+pwpx9xSUHeC143Z+KlQh4hYGo1LUmWGCyt7liJtoWhhlt+1HGtfg0tDIiI0OD0BONRM9sTVLaVhVPX2p6FsR3OO+F8ekEiCD38EhiE/iejYjQZrV+KJcJPMiiEDbCIyrDXfEA7TzPYbI3JAS8Wrjr1l--7DDqARDFnEmmUn+Z--nYFJbDi62FzlV0DT83Fmyg== \ No newline at end of file From 0eac84d944b9b68219edd7e9c01ad7322bb5b978 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:00:04 -0400 Subject: [PATCH 09/22] set up dotenv --- .gitignore | 1 + Gemfile | 1 + Gemfile.lock | 3 +++ config/environment.rb | 4 +++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 677acf3..4cd8376 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /spec/examples.txt *.key +*.local diff --git a/Gemfile b/Gemfile index fbf3c49..0989a51 100644 --- a/Gemfile +++ b/Gemfile @@ -42,5 +42,6 @@ group :development do end group :development, :test do + gem 'dotenv' gem 'debug' end diff --git a/Gemfile.lock b/Gemfile.lock index 1e8d1d2..e21a8ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -63,6 +63,7 @@ GEM reline (>= 0.3.8) diff-lcs (1.6.2) docile (1.4.0) + dotenv (3.2.0) drb (2.2.3) ed25519 (1.4.0) erb (6.0.1) @@ -305,6 +306,7 @@ DEPENDENCIES capistrano-pending capistrano-rails debug + dotenv ed25519 faker faraday-retry @@ -354,6 +356,7 @@ CHECKSUMS debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 docile (1.4.0) sha256=5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3 + dotenv (3.2.0) drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 ed25519 (1.4.0) sha256=16e97f5198689a154247169f3453ef4cfd3f7a47481fde0ae33206cdfdcac506 erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5 diff --git a/config/environment.rb b/config/environment.rb index d4c9569..2124121 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true +env = ENV.fetch('RACK_ENV', 'development') $LOAD_PATH.unshift File.expand_path('../lib', __dir__) require 'bundler/setup' -Bundler.require(:default, ENV.fetch('RACK_ENV', 'development')) +Bundler.require(:default, env) +Dotenv.load('.env', '.env.local', ".env.#{env}", ".env.#{env}.local") if defined?(Dotenv) require_relative 'credentials' From cdbf3c1c3b1b00c51aef1cfe3eeb3a86cdcfed72 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:14:59 -0400 Subject: [PATCH 10/22] switch secret reading --- Rakefile | 3 --- config.ru | 3 --- lib/application_configuration.rb | 23 ---------------- lib/application_secrets.rb | 17 ++++++++++++ lib/dev_training_application.rb | 7 ++--- script/console | 5 +--- spec/lib/application_configuration_spec.rb | 27 ------------------- .../requests/dev_training_application_spec.rb | 4 ++- 8 files changed, 25 insertions(+), 64 deletions(-) delete mode 100644 lib/application_configuration.rb create mode 100644 lib/application_secrets.rb delete mode 100644 spec/lib/application_configuration_spec.rb diff --git a/Rakefile b/Rakefile index ecb84f9..2b83fcf 100644 --- a/Rakefile +++ b/Rakefile @@ -2,9 +2,6 @@ require_relative 'config/environment' -require 'application_configuration' -ApplicationConfiguration.load! - require 'application_assets' require 'rake/sprocketstask' diff --git a/config.ru b/config.ru index 5256b0c..99e0cb0 100644 --- a/config.ru +++ b/config.ru @@ -2,9 +2,6 @@ require_relative 'config/environment' -require 'application_configuration' -ApplicationConfiguration.load! - require 'application_assets' require 'dev_training_application' diff --git a/lib/application_configuration.rb b/lib/application_configuration.rb deleted file mode 100644 index 2b80aff..0000000 --- a/lib/application_configuration.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'figaro' - -## -# helper module for loading Figaro configuration in the environment in a non- -# Rails application. -module ApplicationConfiguration - def self.config_file # :nodoc: - File.join(__dir__, '..', 'config', 'application.yml') - end - - ## - # Read the `config/application.yml` file and load it into `ENV` - def self.load! - Figaro.adapter = Figaro::Application - Figaro.application = Figaro::Application.new( - path: config_file, - environment: ENV['RACK_ENV'] || 'development' - ) - Figaro.load - end -end diff --git a/lib/application_secrets.rb b/lib/application_secrets.rb new file mode 100644 index 0000000..6587f16 --- /dev/null +++ b/lib/application_secrets.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +## +# helper module for loading secret values from environment/credentials. +module ApplicationSecrets + class << self + def sessions = production? ? { secret: CREDENTIALS['session_secret'] } : {} + + def github_key = production? ? CREDENTIALS['github_key'] : ENV.fetch('GITHUB_KEY', nil) + + def github_secret = production? ? CREDENTIALS['github_secret'] : ENV.fetch('GITHUB_SECRET', nil) + + private + + def production? = ENV['RACK_ENV'] == 'production' + end +end diff --git a/lib/dev_training_application.rb b/lib/dev_training_application.rb index bce7c01..0bd1e62 100644 --- a/lib/dev_training_application.rb +++ b/lib/dev_training_application.rb @@ -2,6 +2,7 @@ require 'app_client' require 'application_assets' +require 'application_secrets' require 'dev_training' require 'logger' require 'rack/common_logger' @@ -25,11 +26,11 @@ class DevTrainingApplication < Sinatra::Base set :qualifications, proc { File.join root, 'config', 'qualifications.yml' } set :readme, proc { File.join root, 'config', 'README.md.erb' } set :app_client, (proc do - AppClient.new ENV.fetch('github_key'), ENV.fetch('github_secret') + AppClient.new ApplicationSecrets.github_key, ApplicationSecrets.github_secret end) set :sprockets, ApplicationAssets.new - set :sessions, (ENV['session_secret'] ? { secret: ENV['session_secret'] } : {}) + set :sessions, ApplicationSecrets.sessions set :haml, layout: :application configure do @@ -57,7 +58,7 @@ def asset_path(file) # :nodoc: use OmniAuth::Builder do options = { scope: 'user:email, repo' } options[:provider_ignores_state] = true if ENV['RACK_ENV'] == 'development' - provider :github, ENV.fetch('github_key'), ENV.fetch('github_secret'), options + provider :github, ApplicationSecrets.github_key, ApplicationSecrets.github_secret, options end use Rack::Protection, use: %i[authenticity_token cookie_tossing form_token remote_referrer] diff --git a/script/console b/script/console index df34a17..e415909 100755 --- a/script/console +++ b/script/console @@ -3,11 +3,8 @@ require_relative '../config/environment' -require 'application_configuration' -ApplicationConfiguration.load! - require 'dev_training' -@training = DevTraining.new(ENV['console_token']) if ENV['console_token'] +@training = DevTraining.new(ENV['GITHUB_TOKEN']) if ENV['GITHUB_TOKEN'] $stdout.sync = true IRB.setup nil diff --git a/spec/lib/application_configuration_spec.rb b/spec/lib/application_configuration_spec.rb deleted file mode 100644 index 52d43d5..0000000 --- a/spec/lib/application_configuration_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require 'application_configuration' - -RSpec.describe ApplicationConfiguration do - include MockYamlFile - - let(:config_file) { mock_yaml('application.yml', { 'test_key' => 'test_value' }) } - - before do - allow(described_class).to receive(:config_file).and_return(config_file) - end - - describe '.load!' do - subject(:call) { described_class.load! } - - before { call } - - it 'populates the Figaro store' do - expect(Figaro.env.test_key).to eq('test_value') - end - - it 'populates ENV' do - expect(ENV.fetch('test_key', nil)).to eq('test_value') - end - end -end diff --git a/spec/requests/dev_training_application_spec.rb b/spec/requests/dev_training_application_spec.rb index ea05d77..c3f73d0 100644 --- a/spec/requests/dev_training_application_spec.rb +++ b/spec/requests/dev_training_application_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'app_client' +require 'application_secrets' require 'dev_training/repository' require 'dev_training/training' require 'dev_training_application' @@ -18,7 +19,8 @@ app.set :app_client, app_client app.set :host_authorization, { allow_if: ->(_) { true } } allow(app_client).to receive(:token_valid?).and_return(true) - stub_const 'ENV', { 'github_key' => 'key', 'github_secret' => 'secret' } + allow(ApplicationSecrets).to receive(:github_key).and_return('key') + allow(ApplicationSecrets).to receive(:github_secret).and_return('secret') OmniAuth.config.test_mode = true end From 1affdfb8b0a485dc88da217a9d47c0e976803896 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:17:38 -0400 Subject: [PATCH 11/22] figaro no more --- .gitignore | 1 - Gemfile | 1 - Gemfile.lock | 6 +----- config/deploy.rb | 2 +- script/setup | 2 -- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 4cd8376..0679451 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/config/application.yml /coverage/* !/coverage/.last_run.json /log diff --git a/Gemfile b/Gemfile index 0989a51..1c3c556 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,6 @@ ruby file: '.ruby-version' gem 'activesupport', require: 'active_support/all' gem 'faraday-retry' -gem 'figaro' gem 'haml' gem 'octokit' gem 'omniauth-github' diff --git a/Gemfile.lock b/Gemfile.lock index e21a8ad..a6894ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -78,8 +78,6 @@ GEM net-http (~> 0.5) faraday-retry (2.4.0) faraday (~> 2.0) - figaro (1.3.0) - thor (>= 0.14.0, < 2) google-protobuf (4.34.1-arm64-darwin) bigdecimal rake (~> 13.3) @@ -310,7 +308,6 @@ DEPENDENCIES ed25519 faker faraday-retry - figaro haml haml_lint irb @@ -356,7 +353,7 @@ CHECKSUMS debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 docile (1.4.0) sha256=5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3 - dotenv (3.2.0) + dotenv (3.2.0) sha256=e375b83121ea7ca4ce20f214740076129ab8514cd81378161f11c03853fe619d drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 ed25519 (1.4.0) sha256=16e97f5198689a154247169f3453ef4cfd3f7a47481fde0ae33206cdfdcac506 erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5 @@ -365,7 +362,6 @@ CHECKSUMS faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe - figaro (1.3.0) sha256=3d44396f080255663f183572d7aefa419fd8936b6fb5cc30f962345a02781396 google-protobuf (4.34.1-arm64-darwin) sha256=2745061f973119e6e7f3c81a0c77025d291a3caa6585a2cd24a25bbc7bedb267 haml (7.2.0) sha256=87fd2b71f7feab1724337b090a7d767f5ab2d42f08c974f3ead673f18cfcd55a haml_lint (0.72.0) sha256=23acb3f5db1602eb99bccec8009372465321702e1229017cca53272957bfc9c8 diff --git a/config/deploy.rb b/config/deploy.rb index cf43434..b3006a2 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -13,7 +13,7 @@ set :keep_releases, 5 -append :linked_files, 'config/application.yml' +append :linked_files, 'config/dev-training-web.key' append :linked_dirs, 'log', 'public/assets' before 'git:check', 'git:allow_shared' diff --git a/script/setup b/script/setup index 98439a8..2485054 100755 --- a/script/setup +++ b/script/setup @@ -17,6 +17,4 @@ FileUtils.chdir APP_ROOT do system('bundle check') || system!('bundle install') system('if command -v rbenv &> /dev/null; then rbenv rehash; fi') system 'npm install' - - FileUtils.cp 'config/application.yml.example', 'config/application.yml' unless File.exist?('config/application.yml') end From bbde6a59dfc35c461d71ff46800989335cb1732c Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:29:46 -0400 Subject: [PATCH 12/22] update readme --- README.md | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 21b8f98..b738927 100644 --- a/README.md +++ b/README.md @@ -20,19 +20,6 @@ script/setup Configuration ============= -`application.yml` ------------------ - -You'll need an OAuth app on GitHub in order to interact with the GitHub -API. See "[Creating an OAuth App][oaa]" for more information. For local -development, create an app with an "authorization callback URL" of -`http://localhost:9292/auth/github/callback`. - -Finally, if you want to interact with the GitHub API in the developer console, -You can create a [Personal Access Token][pat] (PAT). This is optional, but if -it's defined in the config, then `@training` in the console will be initialized -with that token. - `collaborators.yml` ------------------- @@ -62,6 +49,28 @@ instance of `DevTraining::Readme`, see the documentation for more information. Running the App =============== +You'll need an OAuth app on GitHub in order to interact with the GitHub +API. See "[Creating an OAuth App][oaa]" for more information. For local +development, create an app with an "authorization callback URL" of +`http://localhost:9292/auth/github/callback`. + +Finally, if you want to interact with the GitHub API in the developer console, +You can create a [Personal Access Token][pat] (PAT). This is optional, but if +it's defined in the config, then `@training` in the console will be initialized +with that token. + +```shell +# .env.local + +GITHUB_KEY=your_key +GITHUB_SECRET=your_secret + +# if using console PAT +GITHUB_TOKEN=your_token +``` + +Once your secrets are configured, + ```bash script/server ``` @@ -79,8 +88,7 @@ Developer Console script/console ``` -will load the `ApplicationConfiguration`, require the `DevTraining` libraries, -and (if possible) initialize a `DevTraining` with your PAT to `@training`. +will require the `DevTraining` libraries, and (if possible) initialize a `DevTraining` with your PAT to `@training`. Docs ---- From 32897b5ab53948af681aac83793ff07db6cae421 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:46:49 -0400 Subject: [PATCH 13/22] clean up scripts/binstubs --- bin/bundle | 114 -------------------------------------------------- bin/puma | 27 ------------ bin/rake | 15 +------ script/server | 13 +----- 4 files changed, 3 insertions(+), 166 deletions(-) delete mode 100755 bin/bundle delete mode 100755 bin/puma diff --git a/bin/bundle b/bin/bundle deleted file mode 100755 index 5b593cb..0000000 --- a/bin/bundle +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application 'bundle' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "rubygems" - -m = Module.new do - module_function - - def invoked_as_script? - File.expand_path($0) == File.expand_path(__FILE__) - end - - def env_var_version - ENV["BUNDLER_VERSION"] - end - - def cli_arg_version - return unless invoked_as_script? # don't want to hijack other binstubs - return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` - bundler_version = nil - update_index = nil - ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN - bundler_version = a - end - next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ - bundler_version = $1 - update_index = i - end - bundler_version - end - - def gemfile - gemfile = ENV["BUNDLE_GEMFILE"] - return gemfile if gemfile && !gemfile.empty? - - File.expand_path("../../Gemfile", __FILE__) - end - - def lockfile - lockfile = - case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) - else "#{gemfile}.lock" - end - File.expand_path(lockfile) - end - - def lockfile_version - return unless File.file?(lockfile) - lockfile_contents = File.read(lockfile) - return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ - Regexp.last_match(1) - end - - def bundler_requirement - @bundler_requirement ||= - env_var_version || cli_arg_version || - bundler_requirement_for(lockfile_version) - end - - def bundler_requirement_for(version) - return "#{Gem::Requirement.default}.a" unless version - - bundler_gem_version = Gem::Version.new(version) - - requirement = bundler_gem_version.approximate_recommendation - - return requirement unless Gem.rubygems_version < Gem::Version.new("2.7.0") - - requirement += ".a" if bundler_gem_version.prerelease? - - requirement - end - - def load_bundler! - ENV["BUNDLE_GEMFILE"] ||= gemfile - - activate_bundler - end - - def activate_bundler - gem_error = activation_error_handling do - gem "bundler", bundler_requirement - end - return if gem_error.nil? - require_error = activation_error_handling do - require "bundler/version" - end - return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) - warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" - exit 42 - end - - def activation_error_handling - yield - nil - rescue StandardError, LoadError => e - e - end -end - -m.load_bundler! - -if m.invoked_as_script? - load Gem.bin_path("bundler", "bundle") -end diff --git a/bin/puma b/bin/puma deleted file mode 100755 index 01a92a3..0000000 --- a/bin/puma +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application 'puma' 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("puma", "puma") diff --git a/bin/rake b/bin/rake index 9275675..9efbee9 100755 --- a/bin/rake +++ b/bin/rake @@ -8,20 +8,7 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -bundle_binstub = File.expand_path("../bundle", __FILE__) - -if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /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 +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) require "rubygems" require "bundler/setup" diff --git a/script/server b/script/server index a285218..ef73eac 100755 --- a/script/server +++ b/script/server @@ -1,12 +1,3 @@ -#!/usr/bin/env ruby +#!/usr/bin/env bash -# frozen_string_literal: true - -require 'fileutils' - -# path to your application root. -APP_ROOT = File.expand_path('..', __dir__) - -FileUtils.chdir APP_ROOT do - system 'bin/puma config.ru' -end +bundle exec puma config.ru "$@" From 4f7ce01d16e85688ef5e9658f9cb08769d6dabbe Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:46:59 -0400 Subject: [PATCH 14/22] set node version --- .node-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .node-version diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..8e35034 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.14.1 From e095b02f49b90dda474ff50f0142cad16d942b61 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:47:08 -0400 Subject: [PATCH 15/22] add platform --- Gemfile.lock | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index a6894ff..f399c66 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -78,6 +78,9 @@ GEM net-http (~> 0.5) faraday-retry (2.4.0) faraday (~> 2.0) + google-protobuf (4.34.1-aarch64-linux-gnu) + bigdecimal + rake (~> 13.3) google-protobuf (4.34.1-arm64-darwin) bigdecimal rake (~> 13.3) @@ -123,6 +126,8 @@ GEM net-ssh (>= 5.0.0, < 8.0.0) net-ssh (7.3.0) nio4r (2.7.5) + nokogiri (1.19.1-aarch64-linux-gnu) + racc (~> 1.4) nokogiri (1.19.1-arm64-darwin) racc (~> 1.4) oauth2 (2.0.9) @@ -239,6 +244,8 @@ GEM sass-embedded (1.98.0) google-protobuf (~> 4.31) rake (>= 13) + sass-embedded (1.98.0-aarch64-linux-gnu) + google-protobuf (~> 4.31) sass-embedded (1.98.0-arm64-darwin) google-protobuf (~> 4.31) sawyer (0.9.2) @@ -292,6 +299,7 @@ GEM zeitwerk (2.7.5) PLATFORMS + aarch64-linux arm64-darwin arm64-darwin-22 @@ -362,6 +370,7 @@ CHECKSUMS faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe + google-protobuf (4.34.1-aarch64-linux-gnu) sha256=f9c07607dc139c895f2792a7740fcd01cd94d4d7b0e0a939045b50d7999f0b1d google-protobuf (4.34.1-arm64-darwin) sha256=2745061f973119e6e7f3c81a0c77025d291a3caa6585a2cd24a25bbc7bedb267 haml (7.2.0) sha256=87fd2b71f7feab1724337b090a7d767f5ab2d42f08c974f3ead673f18cfcd55a haml_lint (0.72.0) sha256=23acb3f5db1602eb99bccec8009372465321702e1229017cca53272957bfc9c8 @@ -383,6 +392,7 @@ CHECKSUMS net-sftp (4.0.0) sha256=65bb91c859c2f93b09826757af11b69af931a3a9155050f50d1b06d384526364 net-ssh (7.3.0) sha256=172076c4b30ce56fb25a03961b0c4da14e1246426401b0f89cba1a3b54bf3ef0 nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + nokogiri (1.19.1-aarch64-linux-gnu) sha256=cfdb0eafd9a554a88f12ebcc688d2b9005f9fce42b00b970e3dc199587b27f32 nokogiri (1.19.1-arm64-darwin) sha256=dfe2d337e6700eac47290407c289d56bcf85805d128c1b5a6434ddb79731cb9e oauth2 (2.0.9) sha256=b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb octokit (10.0.0) sha256=82e99a539b7637b7e905e6d277bb0c1a4bed56735935cc33db6da7eae49a24e8 @@ -425,6 +435,7 @@ CHECKSUMS ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef sass-embedded (1.98.0) sha256=397dcd0071170f079eb97562a035fa113358af10e3ff759a57bc7eef763e9f94 + sass-embedded (1.98.0-aarch64-linux-gnu) sha256=019baa4ee850f9d6f3f53125fd4ee56b13ea5191bc8f8f9436825ec3e171b02d sass-embedded (1.98.0-arm64-darwin) sha256=fed4ee6de2f30b14e7a678ca648730aa78acc86be7a555e16ba3fdbc5e6aca69 sawyer (0.9.2) sha256=fa3a72d62a4525517b18857ddb78926aab3424de0129be6772a8e2ba240e7aca securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 From b2ffc5ba22172e61314469bf8ed876513ad7adf3 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 12:50:14 -0400 Subject: [PATCH 16/22] dockerfile --- .dockerignore | 18 ++++++++++++ Dockerfile | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..167daad --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +* + +!/bin/ +!/config/ +!/lib/ +!/public/ +!/script/console +!/script/server +!/views +!/.ruby-version +!/config.ru +!/Gemfile +!/Gemfile.lock +!/package.json +!/package-lock.json +!/Rakefile + +**/*.key diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b28db5c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +# syntax=docker/dockerfile:1 +# check=error=true + +# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: +# docker build --tag dev-training-web --build-arg RUBY_VERSION="$(cat .ruby-version)" --build-arg NODE_VERSION=$(cat .node-version) . +# docker run --interactive --tty --publish 80:80 --env MASTER_KEY="$(cat config/dev-training-web.key)" dev-training-web + +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version +ARG RUBY_VERSION=OVERRIDE_ME +FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base + +# App lives here +WORKDIR /app + +# Install base packages +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y curl libjemalloc2 && \ + ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Set production environment variables and enable jemalloc for reduced memory usage and latency +ENV RACK_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ + BUNDLE_ONLY="default production" \ + NODE_ENV="production" \ + LD_PRELOAD="/usr/local/lib/libjemalloc.so" + + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build gems +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Install JavaScript dependencies +ARG NODE_VERSION=OVERRIDE_ME +ENV PATH=/usr/local/node/bin:$PATH +RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \ + /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \ + rm -rf /tmp/node-build-master + +# Install application gems +COPY .ruby-version Gemfile Gemfile.lock ./ + +RUN bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git + +# Install node modules +COPY package.json package-lock.json ./ +RUN npm ci + +# Copy application code +COPY . . + +# Precompiling assets for production without requiring secret RAILS_MASTER_KEY +RUN ./bin/rake assets:precompile + +RUN rm -rf node_modules + + +# Final stage for app image +FROM base + +# Copy built artifacts: gems, application +COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" +COPY --from=build /app /app + +# Run and own only the runtime files as a non-root user for security +RUN groupadd --system --gid 1000 dev-training-web && \ + useradd dev-training-web --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ + mkdir -p /app/log /app/tmp && chown -R dev-training-web:dev-training-web /app/log /app/tmp +USER 1000:1000 + +EXPOSE 80 +CMD ["script/server", "--port=80"] From 1a9b140970777166ae5e9d277fa64de27a524343 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 13:00:29 -0400 Subject: [PATCH 17/22] assets needs to be in there --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 167daad..79af7b0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ * +!/assets/ !/bin/ !/config/ !/lib/ From c59a22e7146c8006e6815229cde1faae5b060b2e Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 13:35:12 -0400 Subject: [PATCH 18/22] set session secret according to docs? --- lib/application_secrets.rb | 6 +++++- lib/dev_training_application.rb | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/application_secrets.rb b/lib/application_secrets.rb index 6587f16..cfb99c4 100644 --- a/lib/application_secrets.rb +++ b/lib/application_secrets.rb @@ -1,10 +1,14 @@ # frozen_string_literal: true +require 'securerandom' + ## # helper module for loading secret values from environment/credentials. module ApplicationSecrets class << self - def sessions = production? ? { secret: CREDENTIALS['session_secret'] } : {} + def session_secret + production? ? CREDENTIALS['session_secret'] : ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) } + end def github_key = production? ? CREDENTIALS['github_key'] : ENV.fetch('GITHUB_KEY', nil) diff --git a/lib/dev_training_application.rb b/lib/dev_training_application.rb index 0bd1e62..8354ce6 100644 --- a/lib/dev_training_application.rb +++ b/lib/dev_training_application.rb @@ -30,7 +30,8 @@ class DevTrainingApplication < Sinatra::Base end) set :sprockets, ApplicationAssets.new - set :sessions, ApplicationSecrets.sessions + enable :sessions + set :session_secret, ApplicationSecrets.session_secret set :haml, layout: :application configure do From 820f8955f72947a9ab1cba3cee798b2f8a2cecfa Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 13:35:31 -0400 Subject: [PATCH 19/22] dotenv in wrong order --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1c3c556..a0641d3 100644 --- a/Gemfile +++ b/Gemfile @@ -41,6 +41,6 @@ group :development do end group :development, :test do - gem 'dotenv' gem 'debug' + gem 'dotenv' end From b3f69dc81d01278650bd252dbb4ac772f5d65899 Mon Sep 17 00:00:00 2001 From: benmelz Date: Fri, 3 Apr 2026 14:25:14 -0400 Subject: [PATCH 20/22] try thruster --- Dockerfile | 2 +- Gemfile | 16 ++++++++++------ Gemfile.lock | 5 +++++ bin/thrust | 5 +++++ lib/dev_training_application.rb | 7 +------ 5 files changed, 22 insertions(+), 13 deletions(-) create mode 100755 bin/thrust diff --git a/Dockerfile b/Dockerfile index b28db5c..998a529 100644 --- a/Dockerfile +++ b/Dockerfile @@ -75,4 +75,4 @@ RUN groupadd --system --gid 1000 dev-training-web && \ USER 1000:1000 EXPOSE 80 -CMD ["script/server", "--port=80"] +CMD ["./bin/thrust", "./script/server", "--port=3000"] diff --git a/Gemfile b/Gemfile index a0641d3..7af1eb6 100644 --- a/Gemfile +++ b/Gemfile @@ -15,12 +15,8 @@ gem 'sprockets' gem 'sprockets-sass_embedded' gem 'tilt' -group :test do - gem 'faker' - gem 'rack-test', require: 'rack/test' - gem 'rspec' - gem 'rspec-html-matchers' - gem 'simplecov' +group :production do + gem 'thruster' end group :development do @@ -44,3 +40,11 @@ group :development, :test do gem 'debug' gem 'dotenv' end + +group :test do + gem 'faker' + gem 'rack-test', require: 'rack/test' + gem 'rspec' + gem 'rspec-html-matchers' + gem 'simplecov' +end diff --git a/Gemfile.lock b/Gemfile.lock index f399c66..baf1352 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -286,6 +286,8 @@ GEM sysexits (1.2.0) temple (0.10.4) thor (1.5.0) + thruster (0.1.20-aarch64-linux) + thruster (0.1.20-arm64-darwin) tilt (2.7.0) tsort (0.2.0) tzinfo (2.0.6) @@ -335,6 +337,7 @@ DEPENDENCIES sinatra sprockets sprockets-sass_embedded + thruster tilt CHECKSUMS @@ -451,6 +454,8 @@ CHECKSUMS sysexits (1.2.0) sha256=598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662 temple (0.10.4) sha256=b7a1e94b6f09038ab0b6e4fe0126996055da2c38bec53a8a336f075748fff72c thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 + thruster (0.1.20-aarch64-linux) sha256=754f1701061235235165dde31e7a3bc87ec88066a02981ff4241fcda0d76d397 + thruster (0.1.20-arm64-darwin) sha256=630cf8c273f562063b92ea5ccd7a721d7ba6130cc422c823727f4744f6d0770e tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3 tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b diff --git a/bin/thrust b/bin/thrust new file mode 100755 index 0000000..36bde2d --- /dev/null +++ b/bin/thrust @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("thruster", "thrust") diff --git a/lib/dev_training_application.rb b/lib/dev_training_application.rb index 8354ce6..b2b96cb 100644 --- a/lib/dev_training_application.rb +++ b/lib/dev_training_application.rb @@ -33,18 +33,13 @@ class DevTrainingApplication < Sinatra::Base enable :sessions set :session_secret, ApplicationSecrets.session_secret set :haml, layout: :application + set :static, false configure do enable :logging use Rack::CommonLogger, settings.access_log end - # :nocov: - configure :production do - set :static, false - end - # :nocov: - before do @csrf_token = request.env['rack.session']['csrf'] request.env['rack.errors'] = settings.error_log From 1762a4e77910b7c86a6aae2d8b2eb37814c000d4 Mon Sep 17 00:00:00 2001 From: benmelz Date: Tue, 5 May 2026 17:42:57 -0400 Subject: [PATCH 21/22] support asset serving with thruster --- .dockerignore | 3 +++ lib/dev_training_application.rb | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.dockerignore b/.dockerignore index 79af7b0..943c324 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,6 +14,9 @@ !/Gemfile.lock !/package.json !/package-lock.json +!/postcss.config.js !/Rakefile +/assets/builds/ +/public/assets/ **/*.key diff --git a/lib/dev_training_application.rb b/lib/dev_training_application.rb index 218d12d..b004ddd 100644 --- a/lib/dev_training_application.rb +++ b/lib/dev_training_application.rb @@ -36,13 +36,9 @@ class DevTrainingApplication < Sinatra::Base enable :sessions set :session_secret, ApplicationSecrets.session_secret set :haml, layout: :application - set :static, false - # :nocov: - configure :production do - set :static, false - end - # :nocov: + use Rack::Sendfile + set :static_cache_control, [:public, immutable: true, max_age: 31_536_000] set :asset_assembly, AssetAssembly.new configure :development, :test do use Propshaft::Server, settings.asset_assembly From 7910dc904bd179825a17955a922d77979e4b7f5d Mon Sep 17 00:00:00 2001 From: benmelz Date: Wed, 6 May 2026 10:39:45 -0400 Subject: [PATCH 22/22] cache control only for public/assets/ --- lib/dev_training_application.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/dev_training_application.rb b/lib/dev_training_application.rb index b004ddd..f7d1e25 100644 --- a/lib/dev_training_application.rb +++ b/lib/dev_training_application.rb @@ -38,7 +38,6 @@ class DevTrainingApplication < Sinatra::Base set :haml, layout: :application use Rack::Sendfile - set :static_cache_control, [:public, immutable: true, max_age: 31_536_000] set :asset_assembly, AssetAssembly.new configure :development, :test do use Propshaft::Server, settings.asset_assembly @@ -49,6 +48,10 @@ class DevTrainingApplication < Sinatra::Base request.env['rack.errors'] = settings.error_log end + before '/public/assets/*' do + cache_control :public, :immutable, max_age: 31_536_000 + end + helpers do def asset_path(file) # :nodoc: settings.asset_assembly.resolver.resolve(file) || raise(Propshaft::MissingAssetError, file)