Class: Kobako::SandboxOptions
- Inherits:
-
Data
- Object
- Data
- Kobako::SandboxOptions
- Defined in:
- lib/kobako/sandbox_options.rb,
sig/kobako/sandbox_options.rbs
Overview
Kobako::SandboxOptions — immutable Value Object holding the four
per-Sandbox configuration caps and the requested isolation profile.
Built on the class X < Data.define(...) subclass form (the
Steep-friendly shape — see lib/kobako/outcome/panic.rb).
The initialize normalises every option before delegating to Data's
super: timeout to Float seconds, memory_limit / stdout_limit /
stderr_limit to positive Integer bytes. Each cap is +nil+-disablable
(an absent argument takes its DEFAULT; an explicit nil leaves the
bound off), so all four behave uniformly. profile is the one
non-cap: a Symbol on the PROFILES ladder naming the posture the
runtime builds, which is also the weakest the Host App accepts —
nil is rejected because the weakest posture is requested as an
explicit :permissive. Anything that survives SandboxOptions.new
is a wire-ready bundle the Kobako::Runtime constructor consumes
as-is. The options also own the ladder comparison
(+#enforce_floor!+) that Kobako::Sandbox delegates its
construction floor check to.
Constant Summary collapse
- DEFAULT_TIMEOUT_SECONDS =
Default wall-clock timeout for a single invocation: 60 seconds.
60.0- DEFAULT_MEMORY_LIMIT =
Default cap on the per-invocation guest linear-memory delta: 1 MiB. The mruby image's initial allocation and prior invocations' watermark sit outside this budget.
1 << 20
- DEFAULT_OUTPUT_LIMIT =
Default per-channel capture ceiling: 1 MiB.
1 << 20
- PROFILES =
The isolation ladder, weakest first — index order is rank order, so a floor check is an index comparison.
%i[permissive hermetic].freeze
- DEFAULT_PROFILE =
Default isolation profile: the strictest rung — opting down to
:permissiveis the Host App's explicit trade. :hermetic
Instance Attribute Summary collapse
-
#memory_limit ⇒ Integer?
readonly
Returns the value of attribute memory_limit.
-
#profile ⇒ Symbol
readonly
Returns the value of attribute profile.
-
#stderr_limit ⇒ Integer?
readonly
Returns the value of attribute stderr_limit.
-
#stdout_limit ⇒ Integer?
readonly
Returns the value of attribute stdout_limit.
-
#timeout ⇒ Float?
readonly
Returns the value of attribute timeout.
Class Method Summary collapse
Instance Method Summary collapse
-
#enforce_floor!(declared) ⇒ void
Enforce the requested
profileas the floor againstdeclared— the posture a runtime reports having built — so a runtime that cannot honor the request fails construction withKobako::SetupErrorinstead of weakening the posture silently. -
#initialize(timeout: DEFAULT_TIMEOUT_SECONDS, memory_limit: DEFAULT_MEMORY_LIMIT, stdout_limit: DEFAULT_OUTPUT_LIMIT, stderr_limit: DEFAULT_OUTPUT_LIMIT, profile: DEFAULT_PROFILE) ⇒ SandboxOptions
constructor
A new instance of SandboxOptions.
-
#normalize_memory_limit(memory_limit) ⇒ Integer?
Coerce
memory_limitinto the byte cap the ext expects, ornilto mean unbounded. -
#normalize_output_limit(limit, name) ⇒ Integer?
Coerce a per-channel output cap (+stdout_limit+ /
stderr_limit) into the byte cap the ext expects, ornilto leave the channel uncapped. -
#normalize_profile(profile) ⇒ Symbol
Validate
profileagainst the PROFILES ladder. -
#normalize_timeout(timeout) ⇒ Float?
Coerce
timeoutinto the Float seconds the ext expects, ornilto mean the cap is disabled.
Constructor Details
#initialize(timeout: DEFAULT_TIMEOUT_SECONDS, memory_limit: DEFAULT_MEMORY_LIMIT, stdout_limit: DEFAULT_OUTPUT_LIMIT, stderr_limit: DEFAULT_OUTPUT_LIMIT, profile: DEFAULT_PROFILE) ⇒ SandboxOptions
Returns a new instance of SandboxOptions.
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/kobako/sandbox_options.rb', line 44 def initialize(timeout: DEFAULT_TIMEOUT_SECONDS, memory_limit: DEFAULT_MEMORY_LIMIT, stdout_limit: DEFAULT_OUTPUT_LIMIT, stderr_limit: DEFAULT_OUTPUT_LIMIT, profile: DEFAULT_PROFILE) timeout = normalize_timeout(timeout) memory_limit = normalize_memory_limit(memory_limit) stdout_limit = normalize_output_limit(stdout_limit, "stdout_limit") stderr_limit = normalize_output_limit(stderr_limit, "stderr_limit") profile = normalize_profile(profile) super end |
Instance Attribute Details
#memory_limit ⇒ Integer? (readonly)
Returns the value of attribute memory_limit.
10 11 12 |
# File 'sig/kobako/sandbox_options.rbs', line 10 def memory_limit @memory_limit end |
#profile ⇒ Symbol (readonly)
Returns the value of attribute profile.
13 14 15 |
# File 'sig/kobako/sandbox_options.rbs', line 13 def profile @profile end |
#stderr_limit ⇒ Integer? (readonly)
Returns the value of attribute stderr_limit.
12 13 14 |
# File 'sig/kobako/sandbox_options.rbs', line 12 def stderr_limit @stderr_limit end |
#stdout_limit ⇒ Integer? (readonly)
Returns the value of attribute stdout_limit.
11 12 13 |
# File 'sig/kobako/sandbox_options.rbs', line 11 def stdout_limit @stdout_limit end |
#timeout ⇒ Float? (readonly)
Returns the value of attribute timeout.
9 10 11 |
# File 'sig/kobako/sandbox_options.rbs', line 9 def timeout @timeout end |
Class Method Details
.new ⇒ Object
15 |
# File 'sig/kobako/sandbox_options.rbs', line 15
def self.new: (
|
Instance Method Details
#enforce_floor!(declared) ⇒ void
This method returns an undefined value.
Enforce the requested profile as the floor against declared —
the posture a runtime reports having built — so a runtime that
cannot honor the request fails construction with
Kobako::SetupError instead of weakening the posture silently.
Both fallbacks fail closed: a declaration off the PROFILES ladder
ranks below every request, and a request off the ladder
(unreachable past initialize) refuses every declaration.
64 65 66 67 68 69 |
# File 'lib/kobako/sandbox_options.rb', line 64 def enforce_floor!(declared) return if (PROFILES.index(declared) || -1) >= (PROFILES.index(profile) || PROFILES.size) raise Kobako::SetupError, "runtime declares isolation profile #{declared.inspect}, " \ "below the requested floor #{profile.inspect}" end |
#normalize_memory_limit(memory_limit) ⇒ Integer?
Coerce memory_limit into the byte cap the ext expects, or nil
to mean unbounded. Must be a positive Integer when set; Float or
zero/negative values are rejected.
91 92 93 94 95 96 97 98 |
# File 'lib/kobako/sandbox_options.rb', line 91 def normalize_memory_limit(memory_limit) return nil if memory_limit.nil? unless memory_limit.is_a?(Integer) && memory_limit.positive? raise ArgumentError, "memory_limit must be a positive Integer or nil, got #{memory_limit.inspect}" end memory_limit end |
#normalize_output_limit(limit, name) ⇒ Integer?
Coerce a per-channel output cap (+stdout_limit+ / stderr_limit)
into the byte cap the ext expects, or nil to leave the channel
uncapped. Same shape as normalize_memory_limit: a positive Integer
when set, Float / zero / negative rejected. name tags the
ArgumentError with the offending keyword.
105 106 107 108 109 110 111 112 |
# File 'lib/kobako/sandbox_options.rb', line 105 def normalize_output_limit(limit, name) return nil if limit.nil? unless limit.is_a?(Integer) && limit.positive? raise ArgumentError, "#{name} must be a positive Integer or nil, got #{limit.inspect}" end limit end |
#normalize_profile(profile) ⇒ Symbol
Validate profile against the PROFILES ladder. Unlike the caps
there is no nil form: the weakest posture is requested as an
explicit :permissive, so anything off the ladder — nil
included — is rejected.
118 119 120 121 122 |
# File 'lib/kobako/sandbox_options.rb', line 118 def normalize_profile(profile) return profile if PROFILES.include?(profile) raise ArgumentError, "profile must be one of #{PROFILES.map(&:inspect).join(", ")}, got #{profile.inspect}" end |
#normalize_timeout(timeout) ⇒ Float?
Coerce timeout into the Float seconds the ext expects, or nil
to mean the cap is disabled. Any finite non-positive value is
rejected — a zero or negative timeout would either fire instantly
or never, both of which would surprise callers more than an early
ArgumentError.
78 79 80 81 82 83 84 85 86 |
# File 'lib/kobako/sandbox_options.rb', line 78 def normalize_timeout(timeout) return nil if timeout.nil? raise ArgumentError, "timeout must be Numeric or nil, got #{timeout.class}" unless timeout.is_a?(Numeric) seconds = timeout.to_f raise ArgumentError, "timeout must be > 0 (got #{timeout})" unless seconds.positive? && seconds.finite? seconds end |