Class: Rubino::Run::AttachmentDownloader
- Inherits:
-
Object
- Object
- Rubino::Run::AttachmentDownloader
- Defined in:
- lib/rubino/run/attachment_downloader.rb
Overview
Fetches the URLs passed as ‘attachments` on a run and saves them under <workspace>/uploads/<run_id>/. The runner then tells the model “you have these local files” instead of forcing it to do tool calls (webfetch was crashing on binaries — see v0.2.5 fix —and even when it worked the model paid context for the bytes).
SSRF guard: only URLs whose host appears in attachments.allowed_hosts (config) or ENV (comma-separated) are fetched. Empty config + empty env = block everything. The list is case-insensitive and matched exactly against the URI host (no port, no path, no subdomain magic) so an admin knows exactly what is allowed without re-reading regex semantics.
Constant Summary collapse
- MAX_BYTES_PER_FILE =
50 MB hard cap, matches uploads
50 * 1024 * 1024
- HTTP_TIMEOUT =
30- LOOPBACK_HOSTS =
When an HTTP client is co-located on the same host as the agent, attachment URLs are loopback (localhost:3000/…). These are always allowed IN ADDITION to attachments.allowed_hosts so the common case works out of the box without opening the guard to arbitrary external hosts. SSRF risk is bounded: only the local host is reachable, which the agent could already talk to via the shell.
%w[localhost 127.0.0.1 ::1].freeze
Instance Method Summary collapse
-
#fetch_all(run_id:, urls:) ⇒ Array<String>
Absolute paths of successfully saved files.
-
#initialize(workspace_root: nil, allowed_hosts: nil) ⇒ AttachmentDownloader
constructor
A new instance of AttachmentDownloader.
Constructor Details
#initialize(workspace_root: nil, allowed_hosts: nil) ⇒ AttachmentDownloader
Returns a new instance of AttachmentDownloader.
33 34 35 36 |
# File 'lib/rubino/run/attachment_downloader.rb', line 33 def initialize(workspace_root: nil, allowed_hosts: nil) @workspace_root = workspace_root || Rubino::Workspace.primary_root @allowed_hosts = normalize_hosts(allowed_hosts || default_allowed_hosts) end |
Instance Method Details
#fetch_all(run_id:, urls:) ⇒ Array<String>
Returns absolute paths of successfully saved files.
39 40 41 42 43 44 45 46 |
# File 'lib/rubino/run/attachment_downloader.rb', line 39 def fetch_all(run_id:, urls:) list = Array(urls).reject { |u| u.to_s.strip.empty? } return [] if list.empty? dir = File.join(@workspace_root, "uploads", run_id.to_s) FileUtils.mkdir_p(dir) list.filter_map { |url| fetch_one(dir, url) } end |