katalyst-thermite 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +41 -0
  4. data/lib/generators/thermite/install/active_storage/USAGE +28 -0
  5. data/lib/generators/thermite/install/active_storage/active_storage_generator.rb +79 -0
  6. data/lib/generators/thermite/install/active_storage/templates/app/controllers/active_storage/authenticated_direct_uploads_controller.rb +29 -0
  7. data/lib/generators/thermite/install/active_storage/templates/config/routes/overrides.rb +15 -0
  8. data/lib/generators/thermite/install/active_storage/templates/config/storage.yml.tt +12 -0
  9. data/lib/generators/thermite/install/active_storage/templates/spec/requests/active_storage/authenticated_direct_uploads_controller_spec.rb +70 -0
  10. data/lib/generators/thermite/install/content_security_policy/USAGE +21 -0
  11. data/lib/generators/thermite/install/content_security_policy/content_security_policy_generator.rb +18 -0
  12. data/lib/generators/thermite/install/content_security_policy/templates/config/initializers/content_security_policy.rb +72 -0
  13. data/lib/generators/thermite/install/docker/USAGE +8 -0
  14. data/lib/generators/thermite/install/docker/docker_generator.rb +35 -0
  15. data/lib/generators/thermite/install/docker/templates/Dockerfile.tt +119 -0
  16. data/lib/generators/thermite/install/docker/templates/bin/docker-entrypoint +21 -0
  17. data/lib/generators/thermite/install/permissions_policy/USAGE +11 -0
  18. data/lib/generators/thermite/install/permissions_policy/permissions_policy_generator.rb +18 -0
  19. data/lib/generators/thermite/install/permissions_policy/templates/config/initializers/permissions_policy.rb +11 -0
  20. data/lib/generators/thermite/install/sentry/USAGE +18 -0
  21. data/lib/generators/thermite/install/sentry/sentry_generator.rb +46 -0
  22. data/lib/generators/thermite/install/sentry/templates/config/initializers/sentry.rb.tt +50 -0
  23. data/lib/generators/thermite/install/solid_cable/USAGE +16 -0
  24. data/lib/generators/thermite/install/solid_cable/solid_cable_generator.rb +98 -0
  25. data/lib/generators/thermite/install/solid_cable/templates/add_solid_cable.rb.tt +7 -0
  26. data/lib/generators/thermite/install/solid_cable/templates/config/cable.yml.tt +16 -0
  27. data/lib/generators/thermite/install/solid_queue/USAGE +18 -0
  28. data/lib/generators/thermite/install/solid_queue/solid_queue_generator.rb +94 -0
  29. data/lib/generators/thermite/install/solid_queue/templates/add_solid_queue.rb.tt +7 -0
  30. data/lib/generators/thermite/install/solid_queue/templates/config/queue.yml.tt +14 -0
  31. data/lib/generators/thermite/install/solid_queue/templates/config/recurring.yml.tt +9 -0
  32. data/lib/katalyst-thermite.rb +3 -0
  33. data/lib/thermite/engine.rb +11 -0
  34. data/lib/thermite/tasks.rb +20 -0
  35. data/lib/thermite.rb +17 -0
  36. metadata +102 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '02089b926bee271fd703e7ac9aab79a4adf886f627f212d518427a4d3263bfe8'
4
+ data.tar.gz: 4782edfbf124fd1b63f8bc959072de74c2e2bb49ec9f2a0e4c87196d2dcd28d3
5
+ SHA512:
6
+ metadata.gz: d3971994ede5200b2798773970002b161b3a62beb0c6e2d79c04078f63913bd3639b81dc1cc66a9cf39970bf948fbcba9a7e2cf1dc0524a0176b61365f6421e2
7
+ data.tar.gz: 804df729abc85ba29fe70a859a1e7000c0c6b9b4719c045fc7d2ccd958fd4705cdca2a7740c0ff22b4eed0c30f2ed1315736619f7de1357503da19c21395a7d5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Katalyst Interactive
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Katalyst::Thermite
2
+
3
+ Katalyst Thermite provides tools for adding and updating libraries and frameworks following Katalyst best practices.
4
+
5
+ ## Installation
6
+
7
+ Add the gem to the `development` group in your Gemfile:
8
+
9
+ ```ruby
10
+ group :development do
11
+ gem "katalyst-thermite"
12
+ end
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Run installers to add common frameworks and libraries to your Rails app, for example:
18
+
19
+ ```shell
20
+ bin/rails thermite:install:koi
21
+ ```
22
+
23
+ Available installers:
24
+
25
+ ```shell
26
+ bin/rails thermite:install:active_storage
27
+ bin/rails thermite:install:content_security_policy
28
+ bin/rails thermite:install:docker
29
+ bin/rails thermite:install:permissions_policy
30
+ bin/rails thermite:install:sentry
31
+ bin/rails thermite:install:solid_cable
32
+ bin/rails thermite:install:solid_queue
33
+ ```
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/katalyst/thermite.
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,28 @@
1
+ Description:
2
+ Installs Active Storage following Katalyst conventions, on fresh or existing apps.
3
+
4
+ Writes a Katalyst-flavoured config/storage.yml (Disk locally, S3 elsewhere) and
5
+ points config.active_storage.service at :s3 for every non dev/test environment.
6
+
7
+ Also secures direct uploads: the POST /rails/active_storage/direct_uploads endpoint
8
+ is routed through an authenticated controller, and the disk service routes are
9
+ disabled unless storage is served from local disk. Authentication is app-specific, so
10
+ the controller ships locked down (every upload rejected) and the generated request
11
+ spec leaves the authenticated examples pending for you to complete.
12
+
13
+ To use the S3 service in deployed environments, add `aws-sdk-s3` to your Gemfile.
14
+
15
+ Example:
16
+ bin/rails thermite:install:active_storage
17
+
18
+ This will:
19
+ Create config/storage.yml
20
+ Install the Active Storage migrations
21
+ Set the Active Storage service to :s3 (non dev/test environments)
22
+ Add app/controllers/active_storage/authenticated_direct_uploads_controller.rb
23
+ Add config/routes/overrides.rb and draw it from config/routes.rb
24
+ Add spec/requests/active_storage/authenticated_direct_uploads_controller_spec.rb
25
+
26
+ After running, enable uploads for your authenticated users:
27
+ Permit your principals in #current_user in the authenticated direct uploads controller
28
+ Complete the pending examples in the generated request spec
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+
6
+ # Installs Active Storage following Katalyst conventions, on fresh or existing apps.
7
+ module Thermite
8
+ module Install
9
+ class ActiveStorageGenerator < Rails::Generators::Base
10
+ def self.source_root
11
+ File.expand_path("templates", __dir__)
12
+ end
13
+
14
+ def copy_storage_config
15
+ template "config/storage.yml"
16
+ end
17
+
18
+ # Lock the direct upload endpoint behind authentication and disable the disk
19
+ # service routes when storage isn't served from local disk. The authentication
20
+ # stubs are left for the app to complete (see the generated controller and spec).
21
+ def secure_direct_uploads
22
+ copy_file "app/controllers/active_storage/authenticated_direct_uploads_controller.rb"
23
+ copy_file "config/routes/overrides.rb"
24
+ copy_file "spec/requests/active_storage/authenticated_direct_uploads_controller_spec.rb"
25
+ draw_overrides
26
+ end
27
+
28
+ # update tops up an existing install; install lays the base for a new one.
29
+ def install_migrations
30
+ rails_command active_storage_installed? ? "active_storage:update" : "active_storage:install"
31
+ end
32
+
33
+ def configure_services
34
+ environments.each do |pathname|
35
+ next if local?(pathname)
36
+
37
+ gsub_file pathname, /(# )?config\.active_storage\.service\s*=.*/,
38
+ "config.active_storage.service = :s3", verbose: false
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # Wire config/routes/overrides.rb into the app's router with `draw :overrides`,
45
+ # inserted just inside the routes block. Idempotent and a no-op without routes.rb.
46
+ def draw_overrides
47
+ routes = Pathname(destination_root).join("config/routes.rb")
48
+ return unless routes.exist?
49
+ return if routes.read.include?("draw :overrides")
50
+
51
+ inject_into_file "config/routes.rb", " draw :overrides\n",
52
+ after: /^\s*Rails\.application\.routes\.draw do\n/, verbose: false
53
+ end
54
+
55
+ def environments
56
+ Pathname(destination_root).join("config/environments").glob("*.rb")
57
+ end
58
+
59
+ def active_storage_installed?
60
+ Pathname(destination_root).join("db/migrate").glob("*create_active_storage_tables*").any?
61
+ end
62
+
63
+ def local?(pathname)
64
+ %w[development test].include?(pathname.basename(".rb").to_s)
65
+ end
66
+
67
+ # Overridable at runtime via RAILS_ASSETS_BUCKET_ID (see storage.yml).
68
+ def asset_bucket_name
69
+ name = if defined?(Rails.application) && Rails.application
70
+ Rails.application.class.module_parent_name
71
+ else
72
+ File.basename(destination_root)
73
+ end
74
+
75
+ "#{name.to_s.underscore.dasherize}-web-assets"
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ # Active Storage's default direct upload endpoint (POST /rails/active_storage/direct_uploads)
5
+ # mints a signed URL that lets the caller PUT a file straight into the storage service.
6
+ # Left unauthenticated, it is an open door for anyone to fill the asset bucket.
7
+ # @see https://guides.rubyonrails.org/active_storage_overview.html#authenticated-controllers
8
+ #
9
+ # This controller restricts the endpoint to authenticated principals and rate limits
10
+ # requests using #current_user to identify a database-backed principal for authorisation and
11
+ # request throttling. If no principal is returned requests fail with :unauthorized.
12
+ # @see config/routes/overrides.rb
13
+ class AuthenticatedDirectUploadsController < ActiveStorage::DirectUploadsController
14
+ before_action :authenticate_user!
15
+ rate_limit to: 20, within: 10.seconds, by: -> { current_user.to_gid }
16
+
17
+ private
18
+
19
+ # Reject any request we can't attribute to a #current_user.
20
+ def authenticate_user!
21
+ head(:unauthorized) if current_user.nil?
22
+ end
23
+
24
+ # The authenticated principal for the current request, or nil when the request is anonymous.
25
+ def current_user
26
+ nil
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Drawn from config/routes.rb via `draw :overrides`.
4
+
5
+ # Only authenticated users can post files.
6
+ # @see app/controllers/active_storage/authenticated_direct_uploads_controller.rb
7
+ post "/rails/active_storage/direct_uploads", to: "active_storage/authenticated_direct_uploads#create"
8
+
9
+ # Disable the disk service routes unless files are actually served from local disk.
10
+ unless %i[local test].include?(Rails.application.config.active_storage.service)
11
+ no_route = ->(req) { raise ActionController::RoutingError, "No route matches #{req['REQUEST_PATH']}" }
12
+
13
+ get "/rails/active_storage/disk/:encoded_key/*filename", to: no_route
14
+ put "/rails/active_storage/disk/:encoded_token", to: no_route
15
+ end
@@ -0,0 +1,12 @@
1
+ test:
2
+ service: Disk
3
+ root: <%%= Rails.root.join("tmp/storage") %>
4
+
5
+ local:
6
+ service: Disk
7
+ root: <%%= Rails.root.join("storage") %>
8
+
9
+ s3:
10
+ service: S3
11
+ region: ap-southeast-2
12
+ bucket: <%%= ENV.fetch("RAILS_ASSETS_BUCKET_ID", "<%= asset_bucket_name %>") %>
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_helper"
4
+
5
+ RSpec.describe ActiveStorage::AuthenticatedDirectUploadsController do
6
+ let(:action) { post(rails_direct_uploads_path, params:) }
7
+ let(:file) { StringIO.new("example") }
8
+ let(:params) do
9
+ {
10
+ blob: {
11
+ filename: "example.txt",
12
+ content_type: "text/plain",
13
+ byte_size: file.string.bytesize,
14
+ checksum: OpenSSL::Digest::MD5.new(file.string).base64digest,
15
+ },
16
+ }
17
+ end
18
+
19
+ it "rejects uploads from anonymous users" do
20
+ action
21
+
22
+ expect(response).to have_http_status(:unauthorized)
23
+ end
24
+
25
+ context "as a signed-in admin", pending: "requires admin session setup" do
26
+ # include_context "with admin session"
27
+
28
+ it "permits the upload" do
29
+ action
30
+
31
+ expect(response).to have_http_status(:ok)
32
+ end
33
+ end
34
+
35
+ context "as a signed-in user", pending: "requires user session setup" do
36
+ # before { sign_in(create(:user)) }
37
+
38
+ it "permits the upload" do
39
+ action
40
+
41
+ expect(response).to have_http_status(:ok)
42
+ end
43
+ end
44
+
45
+ describe "rate limiting", pending: "requires a user session" do
46
+ # rate_limit captures the cache in a lambda at class-load time, so stub the call not the object.
47
+ let(:cache) { ActiveSupport::Cache::MemoryStore.new }
48
+ let(:rate_limit) { 20 }
49
+
50
+ before do
51
+ allow(Rails.cache).to receive(:increment) do |name, amount = 1, **options|
52
+ cache.increment(name, amount, **options)
53
+ end
54
+ end
55
+
56
+ # include_context "with admin session"
57
+
58
+ it "throttles bursts of uploads with 429 Too Many Requests" do
59
+ aggregate_failures do
60
+ rate_limit.times do
61
+ post(rails_direct_uploads_path, params:, headers:)
62
+ expect(response).to have_http_status(:ok)
63
+ end
64
+
65
+ post(rails_direct_uploads_path, params:, headers:)
66
+ expect(response).to have_http_status(:too_many_requests)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,21 @@
1
+ Description:
2
+ Installs the Katalyst content security policy configuration.
3
+
4
+ Generates config/initializers/content_security_policy.rb with a
5
+ nonce-based policy controlled per deployment via CONTENT_SECURITY_POLICY:
6
+
7
+ - enforce (default): the policy is enforced
8
+ - report: policy violations are reported but not enforced — use this to
9
+ trial policy changes and review violations in Sentry before enforcing
10
+ - none: no policy header is sent — set this on existing apps that have
11
+ not yet reviewed the policy against their content
12
+
13
+ Violation reports are delivered to Sentry when SENTRY_DSN is set and the
14
+ Sentry initializer registers the report URI (see thermite:install:sentry).
15
+
16
+ See https://docs.sentry.io/platforms/ruby/guides/rails/security-policy-reporting/
17
+ and the project's Sentry Project Settings > SDK Setup > Security Headers page
18
+ (https://<org>.sentry.io/settings/projects/<project>/security-headers/).
19
+
20
+ Example:
21
+ bin/rails generate thermite:install:content_security_policy
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+
6
+ module Thermite
7
+ module Install
8
+ class ContentSecurityPolicyGenerator < Rails::Generators::Base
9
+ def self.source_root
10
+ File.expand_path("templates", __dir__)
11
+ end
12
+
13
+ def copy_files
14
+ copy_file "config/initializers/content_security_policy.rb"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Be sure to restart your server when you modify this file.
4
+
5
+ # Define an application-wide content security policy.
6
+ # See the Securing Rails Applications Guide for more information:
7
+ # https://guides.rubyonrails.org/security.html#content-security-policy-header
8
+
9
+ # Enforced by default. Set CONTENT_SECURITY_POLICY=report per deployment to
10
+ # trial policy changes and review violations in Sentry, or =none for existing
11
+ # apps that have not yet reviewed the policy against their content.
12
+ CSP_MODE = ENV.fetch("CONTENT_SECURITY_POLICY", "enforce").freeze
13
+
14
+ warn "Unknown configuration CONTENT_SECURITY_POLICY=#{CSP_MODE}" unless CSP_MODE.in?(%w[none report enforce])
15
+
16
+ return if CSP_MODE == "none"
17
+
18
+ # Deliver violation reports to Sentry (see config/initializers/sentry.rb)
19
+ # https://docs.sentry.io/platforms/ruby/guides/rails/security-policy-reporting/
20
+ # Sentry's report endpoint is shown under Project Settings > SDK Setup > Security Headers,
21
+ # e.g. https://<org>.sentry.io/settings/projects/<project>/security-headers/
22
+ reporting = if ENV.key?("SENTRY_DSN")
23
+ sentry_uri = "https://#{URI(ENV.fetch('SENTRY_DSN')).hostname}"
24
+ [sentry_uri, sentry_uri.gsub("ingest.sentry", "ingest.us.sentry")]
25
+ else
26
+ []
27
+ end
28
+
29
+ Rails.application.configure do
30
+ config.content_security_policy do |policy|
31
+ policy.default_src(:self)
32
+ policy.frame_ancestors(:self)
33
+
34
+ # Permissive policy, many browser plugins use custom fonts
35
+ policy.font_src(:self, :data, :https)
36
+
37
+ # Permissive policy, allow data URLs and https (hotlinking, tracking pixels)
38
+ policy.img_src(:self, :data, :https)
39
+
40
+ # Block legacy embeds, such as flash
41
+ policy.object_src(:none)
42
+
43
+ # Restricted policy, all scripts should have nonce or SRI. strict-dynamic
44
+ # allows scripts to load children (CSP-3); unsafe-inline and https are
45
+ # fallbacks for legacy browsers, ignored when nonces are supported.
46
+ policy.script_src(:self, :strict_dynamic, :wasm_unsafe_eval, :unsafe_inline, :https)
47
+
48
+ # Permissive policy, browser plugins inject inline styles.
49
+ # Safari < 26.0 does not support -attr and -elem (https://bugs.webkit.org/show_bug.cgi?id=276931)
50
+ policy.style_src(:self, :unsafe_inline, :https)
51
+
52
+ # Permissive policy, allows external embeds and user browser plugins
53
+ policy.frame_src(:self, :https)
54
+
55
+ # Permissive policy, many browser plugins use connect
56
+ policy.connect_src(:self, :data, :https, *reporting)
57
+ end
58
+
59
+ # Generate nonces for permitted importmap, inline scripts, and inline styles.
60
+ # A fresh nonce per request is incompatible with conditional GET caching; apps
61
+ # that create a session on every request can use the session id instead, see
62
+ # https://guides.rubyonrails.org/security.html#adding-a-nonce
63
+ config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) }
64
+ config.content_security_policy_nonce_directives = %w[script-src style-src-elem]
65
+
66
+ # Automatically add `nonce` to `javascript_tag`, `javascript_include_tag`, and `stylesheet_link_tag`
67
+ # if the corresponding directives are specified in `content_security_policy_nonce_directives`.
68
+ config.content_security_policy_nonce_auto = true
69
+
70
+ # Report violations without enforcing the policy.
71
+ config.content_security_policy_report_only = true if CSP_MODE == "report"
72
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Installs the Katalyst Docker container setup.
3
+
4
+ Example:
5
+ bin/rails generate thermite:install:docker
6
+
7
+ This creates a root Dockerfile, bin/docker-entrypoint, .dockerignore,
8
+ and removes the legacy Koi 4-era docker directory (if it exists)
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+
6
+ module Thermite
7
+ module Install
8
+ class DockerGenerator < Rails::Generators::Base
9
+ def self.source_root
10
+ File.expand_path("templates", __dir__)
11
+ end
12
+
13
+ def copy_docker_files
14
+ template "Dockerfile.tt", "Dockerfile"
15
+ copy_file ".dockerignore"
16
+ copy_file "bin/docker-entrypoint"
17
+ chmod "bin/docker-entrypoint", 0o755 & ~File.umask, verbose: false
18
+ end
19
+
20
+ def remove_legacy_docker_directory
21
+ remove_dir "docker" if Pathname(destination_root).join("docker").directory?
22
+ end
23
+
24
+ private
25
+
26
+ def application_name
27
+ if defined?(Rails.application) && Rails.application
28
+ Rails.application.class.module_parent_name.to_s.underscore.dasherize
29
+ else
30
+ File.basename(destination_root).underscore.dasherize
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,119 @@
1
+ # syntax=docker/dockerfile:1
2
+ # check=error=true
3
+
4
+ ARG APPLICATION_NAME="<%= application_name %>"
5
+ ARG RUBY_VERSION=4.0
6
+ FROM ruby:$RUBY_VERSION-slim AS base
7
+
8
+ ARG PACKAGES="curl libvips libjemalloc2 postgresql-client"
9
+
10
+ # Rails app lives here
11
+ WORKDIR /rails
12
+
13
+ # Install base packages
14
+ RUN apt-get update -qq && \
15
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $PACKAGES && \
16
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
17
+
18
+ ARG APPLICATION_NAME
19
+ ARG APPLICATION_VERSION
20
+ ARG APPLICATION_REVISION
21
+
22
+ # Set production environment
23
+ ENV APPLICATION_NAME="${APPLICATION_NAME}" \
24
+ BUNDLE_DEPLOYMENT="1" \
25
+ BUNDLE_PATH="/usr/local/bundle" \
26
+ BUNDLE_WITHOUT="development:test" \
27
+ EXECJS_RUNTIME="Disabled" \
28
+ RAILS_ENV="production" \
29
+ PUMA_SSL="1" \
30
+ TZ="Australia/Adelaide"
31
+
32
+ # Create a rails group and user for non-privileged access
33
+ RUN groupadd --system --gid 1000 rails && \
34
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
35
+ echo "$APPLICATION_NAME ($APPLICATION_VERSION) [$APPLICATION_REVISION]" > /etc/motd && \
36
+ echo "PS1='\u@\${APPLICATION_NAME}-\${RAILS_ENV}:\w\$ '" >> /etc/bash.bashrc && \
37
+ echo "cat /etc/motd" >> /etc/bash.bashrc
38
+
39
+ # Build rails gems and assets in a throw-away build stage to reduce size of final image
40
+ FROM base AS build
41
+
42
+ # Install packages needed to build gems
43
+ ARG BUILD_PACKAGES="build-essential git libcurl4-openssl-dev libpq-dev libyaml-dev pkg-config zlib1g-dev"
44
+ RUN apt-get update -qq && \
45
+ apt-get install --no-install-recommends -y $BUILD_PACKAGES && \
46
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
47
+
48
+ # Install application gems
49
+ COPY Gemfile Gemfile.lock ./
50
+ RUN bundle install && \
51
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
52
+ bundle exec bootsnap precompile --gemfile
53
+
54
+ # Copy application code
55
+ COPY --link . .
56
+
57
+ # Precompile bootsnap code for faster boot times
58
+ RUN bundle exec bootsnap precompile app/ lib/
59
+
60
+ # If set, assets will be compiled into a subdirectory of public/ with this prefix
61
+ ARG CDN_ASSET_PREFIX=""
62
+
63
+ # Precompile assets for production
64
+ RUN DATABASE_URL="postgresql://localhost" \
65
+ SECRET_KEY_BASE_DUMMY=1 \
66
+ ./bin/rails assets:precompile
67
+
68
+ # END OF BUILD ##
69
+
70
+ # Copy assets to the CDN
71
+ FROM amazon/aws-cli:latest AS cdn
72
+
73
+ ARG AWS_DEFAULT_REGION="ap-southeast-2"
74
+ ARG CDN_ASSET_PREFIX=""
75
+ ARG S3_ASSETS_BUCKET=""
76
+
77
+ COPY --from=build /rails/public public
78
+ RUN --mount=type=secret,id=aws-key-id,env=AWS_ACCESS_KEY_ID \
79
+ --mount=type=secret,id=aws-secret-key,env=AWS_SECRET_ACCESS_KEY \
80
+ --mount=type=secret,id=aws-session-token,env=AWS_SESSION_TOKEN \
81
+ if [ -n "$CDN_ASSET_PREFIX" ] && [ -n "$S3_ASSETS_BUCKET" ]; then \
82
+ aws s3 sync --only-show-errors --cache-control "public, max-age=31536000, immutable" \
83
+ public/$CDN_ASSET_PREFIX s3://$S3_ASSETS_BUCKET/$CDN_ASSET_PREFIX; \
84
+ fi
85
+
86
+ # END OF CDN ##
87
+
88
+ # Assemble everything into a single layer
89
+ FROM base AS assemble
90
+
91
+ ARG APPLICATION_VERSION
92
+ ARG APPLICATION_REVISION
93
+
94
+ COPY --link . .
95
+ COPY --from=build /rails/tmp/cache/bootsnap tmp/cache/bootsnap
96
+ COPY --from=cdn /aws/public public
97
+ RUN echo $APPLICATION_VERSION > VERSION && \
98
+ echo $APPLICATION_REVISION > REVISION && \
99
+ mkdir -p db log ssl storage tmp/pids tmp/sockets && \
100
+ chown -R rails:rails db log ssl storage tmp
101
+
102
+ # Final stage for app image
103
+ FROM base
104
+
105
+ ARG CDN_ASSET_PREFIX
106
+
107
+ # Puma and Rails configuration for a small server setup with puma in single mode with 5 workers
108
+ ENV CDN_ASSET_PREFIX=$CDN_ASSET_PREFIX \
109
+ WEB_CONCURRENCY=0 \
110
+ RAILS_MAX_THREADS=5
111
+
112
+ # Assemble layers
113
+ COPY --from=build --link "${BUNDLE_PATH}" "${BUNDLE_PATH}"
114
+ COPY --from=assemble --link /rails .
115
+
116
+ USER 1000:1000
117
+ EXPOSE 4443
118
+ ENTRYPOINT ["/rails/bin/docker-entrypoint"]
119
+ CMD ["./bin/rails", "server"]
@@ -0,0 +1,21 @@
1
+ #!/bin/bash -e
2
+
3
+ # Enable jemalloc for reduced memory usage and latency.
4
+ if [ -z "${LD_PRELOAD+x}" ]; then
5
+ LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit)
6
+ export LD_PRELOAD
7
+ fi
8
+
9
+ # If running the rails server then create or migrate existing database
10
+ if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then
11
+ ./bin/rails db:prepare
12
+
13
+ # create a self-signed certificate for puma
14
+ mkdir -p ~/.ssl
15
+ openssl req -x509 -newkey rsa:2048 -nodes -days 730 \
16
+ -subj '/CN=docker/' \
17
+ -keyout ~/.ssl/docker.key \
18
+ -out ~/.ssl/docker.crt
19
+ fi
20
+
21
+ exec "${@}"
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Installs the Katalyst permissions policy configuration.
3
+
4
+ Generates config/initializers/permissions_policy.rb with a restrictive
5
+ Permissions-Policy header: camera, microphone, geolocation, payment,
6
+ gyroscope, and usb are denied, and fullscreen is limited to the app
7
+ itself. Allow specific features (e.g. geolocation, payment) only for apps
8
+ that use them. The header applies as soon as it is deployed.
9
+
10
+ Example:
11
+ bin/rails generate thermite:install:permissions_policy
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+
6
+ module Thermite
7
+ module Install
8
+ class PermissionsPolicyGenerator < Rails::Generators::Base
9
+ def self.source_root
10
+ File.expand_path("templates", __dir__)
11
+ end
12
+
13
+ def copy_files
14
+ copy_file "config/initializers/permissions_policy.rb"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.permissions_policy do |policy|
4
+ policy.camera :none
5
+ policy.fullscreen :self
6
+ policy.geolocation :none
7
+ policy.gyroscope :none
8
+ policy.microphone :none
9
+ policy.payment :none
10
+ policy.usb :none
11
+ end
@@ -0,0 +1,18 @@
1
+ Description:
2
+ Installs the Katalyst Sentry configuration.
3
+
4
+ Generates config/initializers/sentry.rb with the standard errors-only
5
+ data posture for sentry-ruby/sentry-rails 7.x:
6
+
7
+ - structured logging disabled (no request/SQL logs sent to Sentry)
8
+ - explicit data_collection settings (no user info, cookies, bodies,
9
+ query params, or database query values)
10
+ - error events sanitized with the app's parameter filter
11
+ - CSP violations reported to Sentry when a content security policy is
12
+ configured (see thermite:install:content_security_policy and
13
+ https://docs.sentry.io/platforms/ruby/guides/rails/security-policy-reporting/)
14
+ - tracing and profiling off unless enabled per deployment via
15
+ SENTRY_TRACES_SAMPLE_RATE / SENTRY_PROFILES_SAMPLE_RATE
16
+
17
+ Example:
18
+ bin/rails generate thermite:install:sentry
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+
6
+ module Thermite
7
+ module Install
8
+ class SentryGenerator < Rails::Generators::Base
9
+ def self.source_root
10
+ File.expand_path("templates", __dir__)
11
+ end
12
+
13
+ # Fail early with a helpful message when sentry-rails isn't available.
14
+ def verify_sentry!
15
+ require "sentry-rails"
16
+ rescue LoadError
17
+ raise Thor::Error, <<~MSG.strip
18
+ thermite:install:sentry requires the sentry-rails gem, which is not available.
19
+ Add it to your Gemfile and run `bundle install`:
20
+
21
+ gem "sentry-rails"
22
+ MSG
23
+ end
24
+
25
+ def copy_files
26
+ template "config/initializers/sentry.rb"
27
+ end
28
+
29
+ private
30
+
31
+ # The environments Sentry should report from: every deployed environment,
32
+ # derived from config/environments/*.rb so we don't hard-code names like
33
+ # "staging" / "uat".
34
+ def enabled_environments
35
+ environments
36
+ .map { |pathname| pathname.basename(".rb").to_s }
37
+ .reject { |environment| %w[development test].include?(environment) }
38
+ .sort_by { |environment| environment == "production" ? 1 : 0 }
39
+ end
40
+
41
+ def environments
42
+ Pathname(destination_root).join("config/environments").glob("*.rb")
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Sanitize error events with the application's parameter filter
4
+ filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
5
+ sanitize = lambda do |event, _hint|
6
+ event.extra = filter.filter(event.extra) if event.extra
7
+ event.user = filter.filter(event.user) if event.user
8
+ event.contexts = filter.filter(event.contexts) if event.contexts
9
+ event
10
+ end
11
+
12
+ ActiveSupport.on_load(:active_record) do
13
+ version = Rails.root.join("VERSION")
14
+
15
+ # DSN is set via SENTRY_DSN in ENV
16
+ Sentry.init do |config|
17
+ config.enabled_environments = %w[<%= enabled_environments.join(" ") %>]
18
+ config.release = File.read(version).strip.split("/").last if version.exist?
19
+
20
+ # Errors only: structured logging sends a log event for every request and
21
+ # SQL query. Collecting logs is a per-client data decision.
22
+ config.rails.structured_logging.enabled = false
23
+
24
+ # Data collection posture, based on sentry-ruby 7's `send_default_pii`
25
+ pii_headers = %w[forwarded -ip _ip remote via _user -user]
26
+
27
+ config.data_collection.user_info = false
28
+ config.data_collection.cookies.mode = :off
29
+ config.data_collection.http_headers.request.terms = pii_headers
30
+ config.data_collection.http_headers.response.terms = pii_headers
31
+ config.data_collection.http_bodies = []
32
+ config.data_collection.url_query_params.mode = :off
33
+ config.data_collection.database_query_data = false
34
+ config.data_collection.queues = false
35
+
36
+ config.before_send = sanitize
37
+
38
+ # Report CSP violations to Sentry (requires a content security policy)
39
+ # https://docs.sentry.io/platforms/ruby/guides/rails/security-policy-reporting/
40
+ if (policy = Rails.application.config.content_security_policy).present? && config.csp_report_uri.present?
41
+ policy.report_uri(config.csp_report_uri)
42
+ end
43
+
44
+ # Tracing and profiling, off unless enabled per deployment.
45
+ # Profiling requires the vernier gem.
46
+ config.traces_sample_rate = ENV.fetch("SENTRY_TRACES_SAMPLE_RATE", "0").to_f
47
+ config.profiles_sample_rate = ENV.fetch("SENTRY_PROFILES_SAMPLE_RATE", "0").to_f
48
+ config.profiler_class = Sentry::Vernier::Profiler
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ Description:
2
+ Installs Solid Cable using a single, shared database (Katalyst's preferred setup).
3
+
4
+ Unlike `solid_cable:install`, this does not provision a separate cable
5
+ database. The solid_cable tables are added to the primary database via a
6
+ normal migration in db/migrate, and config/cable.yml uses the solid_cable
7
+ adapter without a `connects_to` configuration.
8
+
9
+ Requires the solid_cable gem to be present in the host application.
10
+
11
+ Example:
12
+ bin/rails thermite:install:solid_cable
13
+
14
+ This will:
15
+ Create config/cable.yml
16
+ Create a db/migrate migration for the solid_cable tables
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+ require "rails/generators/active_record/migration"
6
+
7
+ require "active_record"
8
+ require "yaml"
9
+
10
+ # For a single-database install, solid cable's documented setup is to copy the contents
11
+ # of db/cable_schema.rb into a normal migration, delete db/cable_schema.rb,
12
+ # remove connects_to from config/cable.yml, then run db:migrate.
13
+ # Thermite follows that path by generating the migration directly.
14
+ #
15
+ # solid_cable is an optional dependency: it is required lazily in #verify_solid_cable!
16
+ # so the generator still loads (and lists) when solid_cable is absent.
17
+ module Thermite
18
+ module Install
19
+ class SolidCableGenerator < Rails::Generators::Base
20
+ # Provides migration_template, next_migration_number (timestamped) and the
21
+ # CreateMigration action that makes re-runs safe: identical content is
22
+ # skipped, a same-named migration with different content raises a conflict.
23
+ include ActiveRecord::Generators::Migration
24
+
25
+ # Reuse solid_cable's own templates. Resolved lazily so the class loads
26
+ # without solid_cable present; populated once #verify_solid_cable! requires it.
27
+ def self.source_root
28
+ ::SolidCable::InstallGenerator.source_root if defined?(::SolidCable::InstallGenerator)
29
+ end
30
+
31
+ # Search our own templates (the migration) first, then solid_cable's
32
+ # (cable.yml).
33
+ def self.source_paths
34
+ [File.expand_path("templates", __dir__), source_root].compact
35
+ end
36
+
37
+ # Our source_root points into solid_cable, so the inherited USAGE lookup
38
+ # would resolve to solid_cable's USAGE. Point it at ours instead.
39
+ def self.usage_path
40
+ File.expand_path("USAGE", __dir__)
41
+ end
42
+
43
+ # Fail early with a helpful message when solid_cable isn't available.
44
+ def verify_solid_cable!
45
+ require "solid_cable/version"
46
+ require "generators/solid_cable/install/install_generator"
47
+ rescue LoadError
48
+ raise Thor::Error, <<~MSG.strip
49
+ thermite:install:solid_cable requires the solid_cable gem, which is not available.
50
+ Add it to your Gemfile and run `bundle install`:
51
+
52
+ gem "solid_cable"
53
+ MSG
54
+ end
55
+
56
+ # Based on SolidCable::InstallGenerator#copy_files but writing schema to a migration instead
57
+ # @see https://github.com/rails/solid_cable#single-database-configuration
58
+ def copy_files
59
+ template "config/cable.yml"
60
+ migration_template "add_solid_cable.rb", "db/migrate/add_solid_cable.rb", skip: true
61
+ end
62
+
63
+ private
64
+
65
+ # The application's extra environments, derived from config/environments/*.rb so
66
+ # we don't hard-code names like "staging" / "uat".
67
+ def extra_environments
68
+ environments
69
+ .reject { |pathname| local?(pathname) || production?(pathname) }
70
+ .map { |path| path.basename(".rb").to_s }
71
+ end
72
+
73
+ def environments
74
+ Pathname(destination_root).join("config/environments").glob("*.rb")
75
+ end
76
+
77
+ def local?(pathname)
78
+ %w[development test].include?(pathname.basename(".rb").to_s)
79
+ end
80
+
81
+ def production?(pathname)
82
+ pathname.basename(".rb").to_s == "production"
83
+ end
84
+
85
+ def solid_cable_schema_body
86
+ schema = File.read(File.join(self.class.source_root, "db/cable_schema.rb"))
87
+
88
+ schema
89
+ # Keep only the schema block body.
90
+ .sub(%r{\A.*ActiveRecord::Schema[^\n]+do\n}, "")
91
+ .sub(/\nend\n?\z/, "")
92
+ .lines
93
+ .map { |line| line == "\n" ? line : " #{line}" }
94
+ .join
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
+ def change
5
+ <%= solid_cable_schema_body.chomp %>
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ development:
2
+ adapter: async
3
+
4
+ test:
5
+ adapter: test
6
+
7
+ production: &production
8
+ adapter: solid_cable
9
+ polling_interval: 0.1.seconds
10
+ message_retention: 1.day
11
+
12
+ <% extra_environments.each do |environment| -%>
13
+
14
+ <%= environment %>:
15
+ <<: *production
16
+ <% end -%>
@@ -0,0 +1,18 @@
1
+ Description:
2
+ Installs Solid Queue using a single, shared database (Katalyst's preferred setup).
3
+
4
+ Unlike `solid_queue:install`, this does not provision a separate queue
5
+ database. The solid_queue tables are added to the primary database via a
6
+ normal migration in db/migrate, and `config.active_job.queue_adapter` is set
7
+ to :solid_queue without a `connects_to` configuration.
8
+
9
+ Requires the solid_queue gem to be present in the host application.
10
+
11
+ Example:
12
+ bin/rails thermite:install:solid_queue
13
+
14
+ This will:
15
+ Create config/queue.yml and config/recurring.yml
16
+ Create a db/migrate migration for the solid_queue tables
17
+ Install the bin/jobs binstub
18
+ Set the Active Job queue adapter to :solid_queue (non dev/test environments)
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails/generators"
5
+ require "rails/generators/active_record/migration"
6
+
7
+ require "active_record"
8
+
9
+ # For a single-database install, solid queue's documented setup is to copy the contents
10
+ # of db/queue_schema.rb into a normal migration, delete db/queue_schema.rb,
11
+ # remove config.solid_queue.connects_to, then run db:migrate.
12
+ module Thermite
13
+ module Install
14
+ class SolidQueueGenerator < Rails::Generators::Base
15
+ include ActiveRecord::Generators::Migration
16
+
17
+ # Reuse solid_queue's own templates. Resolved lazily so the class loads
18
+ # without solid_queue present; populated once #verify_solid_queue! requires it.
19
+ def self.source_root
20
+ ::SolidQueue::InstallGenerator.source_root if defined?(::SolidQueue::InstallGenerator)
21
+ end
22
+
23
+ # Search our own templates (the migration) first, then solid_queue's
24
+ # (queue.yml, recurring.yml, bin/jobs).
25
+ def self.source_paths
26
+ [File.expand_path("templates", __dir__), source_root].compact
27
+ end
28
+
29
+ # Our source_root points into solid_queue, so the inherited USAGE lookup
30
+ # would resolve to solid_queue's USAGE. Point it at ours instead.
31
+ def self.usage_path
32
+ File.expand_path("USAGE", __dir__)
33
+ end
34
+
35
+ # Fail early with a helpful message when solid_queue isn't available.
36
+ def verify_solid_queue!
37
+ require "solid_queue/version"
38
+ require "generators/solid_queue/install/install_generator"
39
+ rescue LoadError
40
+ raise Thor::Error, <<~MSG.strip
41
+ thermite:install:solid_queue requires the solid_queue gem, which is not available.
42
+ Add it to your Gemfile and run `bundle install`:
43
+
44
+ gem "solid_queue"
45
+ MSG
46
+ end
47
+
48
+ # Based on SolidQueue::InstallGenerator#copy_files but writing schema to a migration instead
49
+ # @see https://github.com/rails/solid_queue#single-database-configuration
50
+ def copy_files
51
+ template "config/queue.yml"
52
+ template "config/recurring.yml"
53
+ migration_template "add_solid_queue.rb", "db/migrate/add_solid_queue.rb", skip: true
54
+ template "bin/jobs"
55
+ chmod "bin/jobs", 0o755 & ~File.umask, verbose: false
56
+ end
57
+
58
+ # Based on SolidQueue::InstallGenerator#configure_adapter but without connects_to configuration
59
+ # @see https://github.com/rails/solid_queue#single-database-configuration
60
+ def configure_adapter
61
+ Pathname(destination_root).join("config/environments").glob("*.rb").each do |pathname|
62
+ next if %w[development.rb test.rb].include?(pathname.basename.to_s)
63
+
64
+ gsub_file pathname, /\n\s*config\.solid_queue\.connects_to\s+=.*\n/, "\n", verbose: false
65
+ gsub_file pathname, /(# )?config\.active_job\.queue_adapter\s+=.*\n/,
66
+ "config.active_job.queue_adapter = :solid_queue\n"
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ # The application's environments, derived from config/environments/*.rb so
73
+ # we don't hard-code names like "staging" / "uat".
74
+ def application_environments
75
+ Pathname(destination_root).join("config/environments")
76
+ .glob("*.rb")
77
+ .map { |path| path.basename(".rb").to_s }
78
+ .sort
79
+ end
80
+
81
+ def solid_queue_schema_body
82
+ schema = File.read(File.join(self.class.source_root, "db/queue_schema.rb"))
83
+
84
+ schema
85
+ # Keep only the schema block body.
86
+ .sub(%r{\A.*ActiveRecord::Schema[^\n]+do\n}, "")
87
+ .sub(/\nend\n?\z/, "")
88
+ .lines
89
+ .map { |line| line == "\n" ? line : " #{line}" }
90
+ .join
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
+ def change
5
+ <%= solid_queue_schema_body.chomp %>
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ default: &default
2
+ dispatchers:
3
+ - polling_interval: 1
4
+ batch_size: 500
5
+ workers:
6
+ - queues: "*"
7
+ threads: 3
8
+ processes: <%%= ENV.fetch("JOB_CONCURRENCY", 1) %>
9
+ polling_interval: 0.1
10
+ <% application_environments.each do |environment| -%>
11
+
12
+ <%= environment %>:
13
+ <<: *default
14
+ <% end -%>
@@ -0,0 +1,9 @@
1
+ production: &production
2
+ clear_solid_queue_finished_jobs:
3
+ command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)"
4
+ schedule: every hour at minute 12
5
+ <% (application_environments - %w[development test production]).each do |environment| -%>
6
+
7
+ <%= environment %>:
8
+ <<: *production
9
+ <% end -%>
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thermite"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thermite
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Thermite
6
+
7
+ rake_tasks do
8
+ load "thermite/tasks.rb"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :thermite do
4
+ namespace :install do
5
+ desc "Install Solid Queue"
6
+ task :solid_queue do
7
+ Rails::Command.invoke :generate, ["thermite:install:solid_queue"]
8
+ end
9
+
10
+ desc "Install Active Storage"
11
+ task :active_storage do
12
+ Rails::Command.invoke :generate, ["thermite:install:active_storage"]
13
+ end
14
+
15
+ desc "Install Solid Cable"
16
+ task :solid_cable do
17
+ Rails::Command.invoke :generate, ["thermite:install:solid_cable"]
18
+ end
19
+ end
20
+ end
data/lib/thermite.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thermite/engine"
4
+
5
+ require "active_support"
6
+
7
+ require "zeitwerk"
8
+
9
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
10
+ loader.ignore("#{__dir__}/generators")
11
+ loader.ignore("#{__dir__}/katalyst-thermite.rb")
12
+ loader.ignore("#{__dir__}/thermite/tasks.rb")
13
+ loader.setup
14
+
15
+ module Thermite
16
+ extend self
17
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: katalyst-thermite
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Katalyst Interactive
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: railties
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ email:
41
+ - developers@katalyst.com.au
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - LICENSE
47
+ - README.md
48
+ - lib/generators/thermite/install/active_storage/USAGE
49
+ - lib/generators/thermite/install/active_storage/active_storage_generator.rb
50
+ - lib/generators/thermite/install/active_storage/templates/app/controllers/active_storage/authenticated_direct_uploads_controller.rb
51
+ - lib/generators/thermite/install/active_storage/templates/config/routes/overrides.rb
52
+ - lib/generators/thermite/install/active_storage/templates/config/storage.yml.tt
53
+ - lib/generators/thermite/install/active_storage/templates/spec/requests/active_storage/authenticated_direct_uploads_controller_spec.rb
54
+ - lib/generators/thermite/install/content_security_policy/USAGE
55
+ - lib/generators/thermite/install/content_security_policy/content_security_policy_generator.rb
56
+ - lib/generators/thermite/install/content_security_policy/templates/config/initializers/content_security_policy.rb
57
+ - lib/generators/thermite/install/docker/USAGE
58
+ - lib/generators/thermite/install/docker/docker_generator.rb
59
+ - lib/generators/thermite/install/docker/templates/Dockerfile.tt
60
+ - lib/generators/thermite/install/docker/templates/bin/docker-entrypoint
61
+ - lib/generators/thermite/install/permissions_policy/USAGE
62
+ - lib/generators/thermite/install/permissions_policy/permissions_policy_generator.rb
63
+ - lib/generators/thermite/install/permissions_policy/templates/config/initializers/permissions_policy.rb
64
+ - lib/generators/thermite/install/sentry/USAGE
65
+ - lib/generators/thermite/install/sentry/sentry_generator.rb
66
+ - lib/generators/thermite/install/sentry/templates/config/initializers/sentry.rb.tt
67
+ - lib/generators/thermite/install/solid_cable/USAGE
68
+ - lib/generators/thermite/install/solid_cable/solid_cable_generator.rb
69
+ - lib/generators/thermite/install/solid_cable/templates/add_solid_cable.rb.tt
70
+ - lib/generators/thermite/install/solid_cable/templates/config/cable.yml.tt
71
+ - lib/generators/thermite/install/solid_queue/USAGE
72
+ - lib/generators/thermite/install/solid_queue/solid_queue_generator.rb
73
+ - lib/generators/thermite/install/solid_queue/templates/add_solid_queue.rb.tt
74
+ - lib/generators/thermite/install/solid_queue/templates/config/queue.yml.tt
75
+ - lib/generators/thermite/install/solid_queue/templates/config/recurring.yml.tt
76
+ - lib/katalyst-thermite.rb
77
+ - lib/thermite.rb
78
+ - lib/thermite/engine.rb
79
+ - lib/thermite/tasks.rb
80
+ homepage: https://github.com/katalyst/thermite
81
+ licenses:
82
+ - MIT
83
+ metadata:
84
+ rubygems_mfa_required: 'true'
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '4.0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubygems_version: 4.0.16
100
+ specification_version: 4
101
+ summary: Katalyst tools for integrating common patterns into Rails apps
102
+ test_files: []