Class: RailsAiBridge::Tools::ReadLogs::LogLocator
- Inherits:
-
Object
- Object
- RailsAiBridge::Tools::ReadLogs::LogLocator
- Defined in:
- lib/rails_ai_bridge/tools/read_logs/log_locator.rb
Overview
Resolves a client-supplied relative file name to a path under the app's +log/ directory and rejects anything that would escape it.
Constant Summary collapse
- EMPTY_FILE_ERROR =
'error: file name must not be empty'
Class Method Summary collapse
-
.open_file(candidate) ⇒ Array(File, nil)
Opens the validated candidate file in binary mode without following a final-component symlink.
Instance Method Summary collapse
-
#initialize(file, root) ⇒ LogLocator
constructor
A new instance of LogLocator.
-
#locate ⇒ Array(File, nil), Array(nil, String)
Resolves the file against the log directory and opens it in binary mode without following a final-component symlink.
Constructor Details
#initialize(file, root) ⇒ LogLocator
Returns a new instance of LogLocator.
15 16 17 18 |
# File 'lib/rails_ai_bridge/tools/read_logs/log_locator.rb', line 15 def initialize(file, root) @file = file.to_s @log_dir = Pathname.new(File.(File.join(root, 'log'))) end |
Class Method Details
.open_file(candidate) ⇒ Array(File, nil)
Opens the validated candidate file in binary mode without following a final-component symlink. The log directory is application-owned and must not be writable by untrusted users; Ruby has no portable openat API for atomically resolving every parent component from a directory descriptor.
rubocop:disable Style/FileOpen
42 43 44 45 46 |
# File 'lib/rails_ai_bridge/tools/read_logs/log_locator.rb', line 42 def self.open_file(candidate) file_io = File.open(candidate, File::RDONLY | File::NOFOLLOW) # rubocop:enable Style/FileOpen [file_io, nil] end |
Instance Method Details
#locate ⇒ Array(File, nil), Array(nil, String)
Resolves the file against the log directory and opens it in binary mode without following a final-component symlink.
25 26 27 28 29 30 31 |
# File 'lib/rails_ai_bridge/tools/read_logs/log_locator.rb', line 25 def locate return empty_error if @file.strip.empty? validate_and_open rescue Errno::ENOENT [nil, "error: log file not found: #{sanitize_filename}"] end |