diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6553e3a..90f4e35 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Setup Ruby and install gems uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3.3 + ruby-version: 3.3.4 bundler-cache: true - name: Run rubocop run: | @@ -53,7 +53,7 @@ jobs: - name: Setup Ruby and install gems uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3.3 + ruby-version: 3.3.4 bundler-cache: true - name: Setup test database env: diff --git a/.ruby-version b/.ruby-version index 619b537..a0891f5 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.3 +3.3.4 diff --git a/Gemfile b/Gemfile index 6e0e128..bd99405 100644 --- a/Gemfile +++ b/Gemfile @@ -3,25 +3,3 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in audits1984.gemspec. gemspec - -gem 'sqlite3' -gem 'pg' -gem 'mysql2' - -group :development do - gem 'rubocop-rails-omakase', require: false -end - -group :test do - gem 'minitest' - - gem 'rails' - gem 'sprockets-rails' - gem 'puma' - - gem 'capybara' - gem 'cuprite' -end - -# To use a debugger -# gem 'byebug', group: [:development, :test] diff --git a/Gemfile.lock b/Gemfile.lock index 986d48c..819b319 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,7 @@ PATH specs: audits1984 (0.1.7) console1984 + importmap-rails (>= 1.2.1) rinku rouge turbo-rails @@ -99,6 +100,9 @@ GEM capybara (~> 3.0) ferrum (~> 0.14.0) date (3.3.4) + debug (1.9.2) + irb (~> 1.10) + reline (>= 0.3.8) erubi (1.12.0) ferrum (0.14) addressable (~> 2.5) @@ -109,6 +113,10 @@ GEM activesupport (>= 5.0) i18n (1.14.1) concurrent-ruby (~> 1.0) + importmap-rails (2.0.3) + actionpack (>= 6.0.0) + activesupport (>= 6.0.0) + railties (>= 6.0.0) io-console (0.7.2) irb (1.14.0) rdoc (>= 4.0.0) @@ -133,6 +141,7 @@ GEM date net-protocol net-pop (0.1.2) + net-protocol net-protocol (0.2.2) timeout net-smtp (0.4.0) @@ -145,6 +154,11 @@ GEM parser (3.2.2.1) ast (~> 2.4.1) pg (1.5.3) + propshaft (1.1.0) + actionpack (>= 7.0.0) + activesupport (>= 7.0.0) + rack + railties (>= 7.0.0) psych (5.1.2) stringio public_suffix (5.0.1) @@ -220,13 +234,6 @@ GEM rubocop-performance rubocop-rails ruby-progressbar (1.13.0) - sprockets (4.2.0) - concurrent-ruby (~> 1.0) - rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) sqlite3 (1.6.3) mini_portile2 (~> 2.8.0) stringio (3.1.1) @@ -257,14 +264,16 @@ DEPENDENCIES audits1984! capybara cuprite + debug minitest mysql2 pg + propshaft puma - rails + rubocop (~> 1.52.0) + rubocop-performance rubocop-rails-omakase - sprockets-rails sqlite3 BUNDLED WITH - 2.2.33 + 2.5.23 diff --git a/README.md b/README.md index b0bb779..c74db61 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,21 @@ Mount the engine in your `routes.rb`: mount Audits1984::Engine => "/console" ``` +### API-only apps or apps using `vite_rails` and other asset pipelines outside Rails + +If you want to use this gem with an [API-only Rails app](https://guides.rubyonrails.org/api_app.html) or an app that's using `vite_ruby`/`vite_rails`, or some other custom asset pipeline different from Sprockets and Propshaft, you need just one more thing: configure an asset pipeline so you can serve the JavaScript and CSS included in this gem. We recommend to use [`Propshaft`](https://github.com/rails/propshaft). You simply need to add this line to your application's Gemfile: + +```ruby +gem "propshaft" +``` + +Then execute +```bash +$ bundle install +``` + +And you should be ready to go. + ### Authenticate auditors By default, the library controllers will inherit from the host application's `ApplicationController`. To authenticate auditors, you need to implement a method `#find_current_auditor` in your `ApplicationController`. This method must return a record representing the auditing user. It can be any model but it has to respond to `#name`. diff --git a/app/assets/javascripts/audits1984/application.js b/app/assets/javascripts/audits1984/application.js deleted file mode 100644 index fb85420..0000000 --- a/app/assets/javascripts/audits1984/application.js +++ /dev/null @@ -1,3 +0,0 @@ -//= include turbo - -//= require_directory . \ No newline at end of file diff --git a/app/controllers/audits1984/application_controller.rb b/app/controllers/audits1984/application_controller.rb index 7ec2eae..b308d5b 100644 --- a/app/controllers/audits1984/application_controller.rb +++ b/app/controllers/audits1984/application_controller.rb @@ -1,9 +1,16 @@ module Audits1984 class ApplicationController < Audits1984.base_controller_class.constantize + ActionController::Base::MODULES.each do |mod| + include mod unless self < mod + end + before_action :authenticate_auditor layout "audits1984/application" + helper Audits1984::ApplicationHelper unless self < Audits1984::ApplicationHelper + helper Importmap::ImportmapTagsHelper unless self < Importmap::ImportmapTagsHelper + private def authenticate_auditor unless respond_to?(:find_current_auditor, true) diff --git a/app/javascript/audits1984/application.js b/app/javascript/audits1984/application.js new file mode 100644 index 0000000..e524d16 --- /dev/null +++ b/app/javascript/audits1984/application.js @@ -0,0 +1,2 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "@hotwired/turbo-rails" diff --git a/app/views/audits1984/sessions/index.html.erb b/app/views/audits1984/sessions/index.html.erb index 3463b56..6337f45 100644 --- a/app/views/audits1984/sessions/index.html.erb +++ b/app/views/audits1984/sessions/index.html.erb @@ -1,8 +1,6 @@ <%= render "audits1984/sessions/filter", filtered_sessions: @filtered_sessions %> <%= render "audits1984/sessions/summary", sessions: @sessions %> - -
- <%= render partial: "audits1984/sessions/session", collection: @sessions, cached: true %> -
-
+
+ <%= render partial: "audits1984/sessions/session", collection: @sessions, cached: true %> +
diff --git a/app/views/layouts/audits1984/application.html.erb b/app/views/layouts/audits1984/application.html.erb index 594beb4..13bb11b 100644 --- a/app/views/layouts/audits1984/application.html.erb +++ b/app/views/layouts/audits1984/application.html.erb @@ -4,11 +4,11 @@ <%= @title || "Audits1984" %> - <%= stylesheet_link_tag "audits1984/bulma.min" %> <%= csrf_meta_tags %> - <%= javascript_include_tag "audits1984/application", nonce: true, data: { turbo_track: :reload } %> + <%= stylesheet_link_tag "audits1984/bulma.min" %> + <%= javascript_importmap_tags "application", importmap: Audits1984.importmap %> <%= stylesheet_link_tag "audits1984/application", media: :all, data: { turbo_track: :reload } %> diff --git a/audits1984.gemspec b/audits1984.gemspec index c1b6228..490869b 100644 --- a/audits1984.gemspec +++ b/audits1984.gemspec @@ -20,7 +20,21 @@ Gem::Specification.new do |spec| spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] spec.add_dependency "rouge" + spec.add_dependency "importmap-rails", ">= 1.2.1" spec.add_dependency "turbo-rails" spec.add_dependency "rinku" spec.add_dependency "console1984" + + spec.add_development_dependency "sqlite3" + spec.add_development_dependency "pg" + spec.add_development_dependency "mysql2" + spec.add_development_dependency "debug" + spec.add_development_dependency "rubocop", "~> 1.52.0" + spec.add_development_dependency "rubocop-performance" + spec.add_development_dependency "rubocop-rails-omakase" + spec.add_development_dependency "propshaft" + spec.add_development_dependency "puma" + spec.add_development_dependency "minitest" + spec.add_development_dependency "capybara" + spec.add_development_dependency "cuprite" end diff --git a/bin/setup b/bin/setup index b404283..5c540c0 100755 --- a/bin/setup +++ b/bin/setup @@ -2,8 +2,14 @@ set -eu cd "$(dirname "${BASH_SOURCE[0]}")" -docker-compose up -d --remove-orphans -docker-compose ps +if docker compose version &> /dev/null; then + DOCKER_COMPOSE_CMD="docker compose" +else + DOCKER_COMPOSE_CMD="docker-compose" +fi + +$DOCKER_COMPOSE_CMD up -d --remove-orphans +$DOCKER_COMPOSE_CMD ps bundle diff --git a/config/importmap.rb b/config/importmap.rb new file mode 100644 index 0000000..acc37d8 --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,2 @@ +pin "application", to: "audits1984/application.js", preload: true +pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true diff --git a/docker-compose.yml b/docker-compose.yml index 87077ef..fa7dcea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,12 +5,12 @@ volumes: services: mysql: - image: percona:5.7.22 + image: mysql:8.0.31 environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" volumes: - db:/var/lib/mysql - ports: [ "127.0.0.1:33307:3306" ] + ports: [ "127.0.0.1:33060:3306" ] postgres: image: postgres:13.4 environment: diff --git a/lib/audits1984.rb b/lib/audits1984.rb index 2f66d3c..18f21de 100644 --- a/lib/audits1984.rb +++ b/lib/audits1984.rb @@ -9,4 +9,5 @@ module Audits1984 mattr_accessor :auditor_class, default: "::User" mattr_accessor :auditor_name_attribute, default: :name mattr_accessor :base_controller_class, default: "::ApplicationController" + mattr_accessor :importmap, default: Importmap::Map.new end diff --git a/lib/audits1984/engine.rb b/lib/audits1984/engine.rb index cf6a58c..eb01dff 100644 --- a/lib/audits1984/engine.rb +++ b/lib/audits1984/engine.rb @@ -1,10 +1,19 @@ require "console1984" -require 'rinku' +require "importmap-rails" +require "turbo-rails" +require "rinku" module Audits1984 class Engine < ::Rails::Engine isolate_namespace Audits1984 + initializer "audits1984.middleware" do |app| + if app.config.api_only + app.middleware.use ActionDispatch::Flash + app.middleware.use ::Rack::MethodOverride + end + end + config.audits1984 = ActiveSupport::OrderedOptions.new initializer "audits1984.config" do @@ -19,8 +28,19 @@ class Engine < ::Rails::Engine end end - initializer "audits1984.assets.precompile" do |app| + initializer "audits1984.assets" do |app| + app.config.assets.paths << root.join("app/assets/stylesheets") + app.config.assets.paths << root.join("app/javascript") app.config.assets.precompile << "audits1984_manifest.js" end + + initializer "audits1984.importmap", after: "importmap" do |app| + Audits1984.importmap.draw(root.join("config/importmap.rb")) + Audits1984.importmap.cache_sweeper(watches: root.join("app/javascript")) + + ActiveSupport.on_load(:action_controller_base) do + before_action { Audits1984.importmap.cache_sweeper.execute_if_updated } + end + end end end diff --git a/test/dummy/app/assets/config/manifest.js b/test/dummy/app/assets/config/manifest.js deleted file mode 100644 index 558723b..0000000 --- a/test/dummy/app/assets/config/manifest.js +++ /dev/null @@ -1,3 +0,0 @@ -//= link_tree ../images -//= link_directory ../stylesheets .css -//= link audits1984_manifest.js diff --git a/test/dummy/app/javascript/packs/application.js b/test/dummy/app/javascript/packs/application.js deleted file mode 100644 index 67ce467..0000000 --- a/test/dummy/app/javascript/packs/application.js +++ /dev/null @@ -1,15 +0,0 @@ -// This is a manifest file that'll be compiled into application.js, which will include all the files -// listed below. -// -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. -// -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// compiled file. JavaScript code in this file should be added after the last require_* statement. -// -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details -// about supported directives. -// -//= require rails-ujs -//= require activestorage -//= require_tree . diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 5869611..1d883bf 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -1,6 +1,7 @@ require_relative "boot" require "rails/all" +require "propshaft" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. diff --git a/test/dummy/db/seeds.rb b/test/dummy/db/seeds.rb new file mode 100644 index 0000000..1d0be49 --- /dev/null +++ b/test/dummy/db/seeds.rb @@ -0,0 +1,65 @@ +# Clear existing data to avoid duplication +Console1984::User.destroy_all +Console1984::Session.destroy_all +Console1984::Command.destroy_all +Console1984::SensitiveAccess.destroy_all + +# Seed Users +users = [ + { username: "alice_wonder" }, + { username: "bob_builder" }, + { username: "charlie_day" } +].map do |user_attrs| + Console1984::User.create!(user_attrs) +end + +puts "#{Console1984::User.count} users created!" + +# Seed Sessions +sessions = users.map do |user| + Array.new(2) do # Create 2 sessions per user + Console1984::Session.create!( + user: user, + reason: [ "Debugging issue", "Performance testing", "Feature testing" ].sample, + created_at: rand(1..30).days.ago, + updated_at: Time.now + ) + end +end.flatten + +puts "#{Console1984::Session.count} sessions created!" + +# Seed SensitiveAccess +sensitive_accesses = sessions.map do |session| + Array.new(2) do # Create 2 sensitive accesses per session + Console1984::SensitiveAccess.create!( + session: session, + justification: [ "Accessing protected data", "Investigating security issues" ].sample, + created_at: rand(1..30).days.ago, + updated_at: Time.now + ) + end +end.flatten + +puts "#{Console1984::SensitiveAccess.count} sensitive accesses created!" + +# Seed Commands with Ruby statements +commands = sessions.map do |session| + Array.new(5) do # Create 5 commands per session + Console1984::Command.create!( + session: session, + sensitive_access: [ nil, sensitive_accesses.sample ].sample, # Randomly associate with a sensitive access or not + statements: [ + "User.find_by(username: 'alice_wonder')", + "Project.all.map(&:name)", + "User.last.update!(admin: true)", + "Order.pending.count", + "Rails.logger.info 'Debugging session started'" + ].sample, + created_at: rand(1..30).days.ago, + updated_at: Time.now + ) + end +end.flatten + +puts "#{Console1984::Command.count} commands created!"