Module: ActiveJob::Temporal::RailsEnvironmentLoader
- Defined in:
- lib/activejob/temporal/rails_environment_loader.rb
Defined Under Namespace
Constant Summary collapse
- UNSAFE_WRITE_BITS =
0o022
Class Method Summary collapse
- .canonicalize_paths(*paths) ⇒ Object
- .eager_load_rails_application ⇒ Object
- .group_or_world_writable?(path) ⇒ Boolean
- .load!(rails_root:, warning_io: $stderr, require_environment: Kernel.method(:require)) ⇒ Object
- .missing_root_result(expanded_root, explicit_root) ⇒ Object
- .non_rails_result(canonical_root, rails_root, explicit_root) ⇒ Object
- .non_rails_warnings(rails_root) ⇒ Object
- .owner_warnings(paths) ⇒ Object
- .path_under_root?(canonical_root, path) ⇒ Boolean
- .rails_paths(canonical_root) ⇒ Object
- .resolve(rails_root) ⇒ Object
- .resolve_existing_root(rails_root, explicit_root, canonical_root) ⇒ Object
- .validate_paths_not_writable_by_group_or_world!(paths) ⇒ Object
- .validate_paths_stay_under_root!(canonical_root, canonical_paths) ⇒ Object
Class Method Details
.canonicalize_paths(*paths) ⇒ Object
82 83 84 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 82 def canonicalize_paths(*paths) paths.to_h { |path| [path, File.realpath(path)] } end |
.eager_load_rails_application ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 128 def eager_load_rails_application return unless Object.const_defined?(:Rails) rails = Object.const_get(:Rails) return unless rails.respond_to?(:application) && rails.respond_to?(:env) environment = rails.env return unless environment.respond_to?(:development?) && environment.respond_to?(:test?) return unless environment.development? || environment.test? application = rails.application application.eager_load! if application.respond_to?(:eager_load!) end |
.group_or_world_writable?(path) ⇒ Boolean
104 105 106 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 104 def group_or_world_writable?(path) File.stat(path).mode.anybits?(UNSAFE_WRITE_BITS) end |
.load!(rails_root:, warning_io: $stderr, require_environment: Kernel.method(:require)) ⇒ Object
18 19 20 21 22 23 24 25 26 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 18 def load!(rails_root:, warning_io: $stderr, require_environment: Kernel.method(:require)) result = resolve(rails_root) result.warnings.each { |warning| warning_io.puts(warning) } return result unless result.loaded? require_environment.call(result.environment_path) eager_load_rails_application result end |
.missing_root_result(expanded_root, explicit_root) ⇒ Object
71 72 73 74 75 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 71 def missing_root_result(, explicit_root) raise Error, "Cannot find Rails application at: #{}" if explicit_root Result.new(loaded: false, rails_root: , environment_path: nil, warnings: []) end |
.non_rails_result(canonical_root, rails_root, explicit_root) ⇒ Object
77 78 79 80 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 77 def non_rails_result(canonical_root, rails_root, explicit_root) warnings = explicit_root ? non_rails_warnings(rails_root) : [] Result.new(loaded: false, rails_root: canonical_root, environment_path: nil, warnings: warnings) end |
.non_rails_warnings(rails_root) ⇒ Object
121 122 123 124 125 126 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 121 def non_rails_warnings(rails_root) [ "Warning: #{rails_root} does not appear to be a Rails application", "Continuing without Rails environment. Job classes may not be available." ] end |
.owner_warnings(paths) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 108 def owner_warnings(paths) current_uid = Process.uid unsafe_owner_path = paths.find do |path| owner_uid = File.stat(path).uid owner_uid != current_uid && !owner_uid.zero? end return [] unless unsafe_owner_path [ "Warning: Rails environment path is not owned by the current user or root: #{unsafe_owner_path}" ] end |
.path_under_root?(canonical_root, path) ⇒ Boolean
100 101 102 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 100 def path_under_root?(canonical_root, path) path == canonical_root || path.start_with?("#{canonical_root}#{File::SEPARATOR}") end |
.rails_paths(canonical_root) ⇒ Object
62 63 64 65 66 67 68 69 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 62 def rails_paths(canonical_root) config_path = File.join(canonical_root, "config") { config: config_path, application: File.join(config_path, "application.rb"), environment: File.join(config_path, "environment.rb") } end |
.resolve(rails_root) ⇒ Object
28 29 30 31 32 33 34 35 36 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 28 def resolve(rails_root) explicit_root = rails_root != "." = File.(rails_root) return missing_root_result(, explicit_root) unless File.directory?() resolve_existing_root(rails_root, explicit_root, File.realpath()) rescue Errno::EACCES => e raise Error, "Cannot inspect Rails application at: #{} (#{e.})" end |
.resolve_existing_root(rails_root, explicit_root, canonical_root) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 38 def resolve_existing_root(rails_root, explicit_root, canonical_root) paths = rails_paths(canonical_root) return non_rails_result(canonical_root, rails_root, explicit_root) unless File.file?(paths.fetch(:application)) environment_path = paths.fetch(:environment) raise Error, "Cannot find Rails environment at: #{environment_path}" unless File.file?(environment_path) canonical_paths = canonicalize_paths( canonical_root, paths.fetch(:config), paths.fetch(:application), environment_path ) validate_paths_stay_under_root!(canonical_root, canonical_paths) validate_paths_not_writable_by_group_or_world!(canonical_paths) Result.new( loaded: true, rails_root: canonical_root, environment_path: canonical_paths.fetch(environment_path), warnings: owner_warnings(canonical_paths.values) ) end |
.validate_paths_not_writable_by_group_or_world!(paths) ⇒ Object
93 94 95 96 97 98 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 93 def validate_paths_not_writable_by_group_or_world!(paths) unsafe_path = paths.values.find { |path| group_or_world_writable?(path) } return unless unsafe_path raise Error, "refusing to load Rails environment from group- or world-writable path: #{unsafe_path}" end |
.validate_paths_stay_under_root!(canonical_root, canonical_paths) ⇒ Object
86 87 88 89 90 91 |
# File 'lib/activejob/temporal/rails_environment_loader.rb', line 86 def validate_paths_stay_under_root!(canonical_root, canonical_paths) escaped_path = canonical_paths.values.find { |path| !path_under_root?(canonical_root, path) } return unless escaped_path raise Error, "Refusing to load Rails environment path outside RAILS_ROOT: #{escaped_path}" end |