Module: FiberAudit::Runtime::Environment
- Defined in:
- lib/fiber_audit/runtime/environment.rb
Overview
rubocop:disable Metrics/ModuleLength
Defined Under Namespace
Classes: Settings
Constant Summary collapse
- PROTOCOL_VERSION =
1- ACTIVATION_KEY =
'FIBER_AUDIT_RUNTIME_BOOT'- SETTINGS_KEY =
'FIBER_AUDIT_RUNTIME_SETTINGS'- FAILURE_MODE_KEY =
'FIBER_AUDIT_RUNTIME_FAILURE_MODE'- WATCHDOG_SETTINGS_KEY =
'FIBER_AUDIT_RUNTIME_WATCHDOG_SETTINGS'- OPERATION_LIVENESS_SETTINGS_KEY =
'FIBER_AUDIT_RUNTIME_OPERATION_LIVENESS_SETTINGS'- PROBES_KEY =
'FIBER_AUDIT_RUNTIME_PROBES'- BOOT_REQUIRE =
'-rfiber_audit/runtime/boot'- MAX_SETTINGS_BYTES =
16_384- MAX_WATCHDOG_SETTINGS_BYTES =
1_024- MAX_OPERATION_LIVENESS_SETTINGS_BYTES =
1_024- SETTINGS_KEYS =
%w[protocol_version launch_id project_root output_directory policy].freeze
- POLICY_KEYS =
%w[ redaction sampling_rate max_events_per_second max_events_per_session max_record_bytes max_session_bytes fail_open ].freeze
- WATCHDOG_KEYS =
%w[ protocol_version enabled heartbeat_interval_ms stall_threshold_ms max_frames ].freeze
- OPERATION_LIVENESS_KEYS =
%w[ protocol_version enabled poll_interval_ms long_active_threshold_ms ].freeze
Class Method Summary collapse
- .activated?(environment = ENV) ⇒ Boolean
- .build(policy:, output_directory:, project_root:, launch_id: SecureRandom.uuid) ⇒ Object
- .child_environment(settings:, watchdog_policy: nil, operation_liveness_policy: nil, probes_enabled: false, base_environment: ENV, library_path: default_library_path) ⇒ Object
- .dump(settings) ⇒ Object
- .dump_operation_liveness_policy(policy) ⇒ Object
- .dump_watchdog_policy(policy) ⇒ Object
- .failure_mode(environment = ENV) ⇒ Object
- .load(environment = ENV) ⇒ Object
- .load_operation_liveness_policy(environment = ENV) ⇒ Object
- .load_watchdog_policy(environment = ENV) ⇒ Object
- .normalize_directory(value, field) ⇒ Object
- .prepare_output_directory(path) ⇒ Object
- .probes_enabled?(environment = ENV) ⇒ Boolean
Class Method Details
.activated?(environment = ENV) ⇒ Boolean
194 195 196 197 198 199 200 |
# File 'lib/fiber_audit/runtime/environment.rb', line 194 def activated?(environment = ENV) marker = environment[ACTIVATION_KEY] return false if marker.nil? return true if marker == '1' raise RuntimeContractError, "#{ACTIVATION_KEY} must be 1" end |
.build(policy:, output_directory:, project_root:, launch_id: SecureRandom.uuid) ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/fiber_audit/runtime/environment.rb', line 63 def build(policy:, output_directory:, project_root:, launch_id: SecureRandom.uuid) Settings.new( protocol_version: PROTOCOL_VERSION, launch_id: launch_id, project_root: project_root, output_directory: output_directory, policy: policy ) end |
.child_environment(settings:, watchdog_policy: nil, operation_liveness_policy: nil, probes_enabled: false, base_environment: ENV, library_path: default_library_path) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/fiber_audit/runtime/environment.rb', line 218 def child_environment( settings:, watchdog_policy: nil, operation_liveness_policy: nil, probes_enabled: false, base_environment: ENV, library_path: default_library_path ) require_settings!(settings) require_watchdog_policy!(watchdog_policy) if watchdog_policy require_operation_liveness_policy!(operation_liveness_policy) if operation_liveness_policy raise RuntimeContractError, 'probes_enabled must be a Boolean' unless [true, false].include?(probes_enabled) raise RuntimeContractError, 'base_environment must be a Hash-like object' unless base_environment.respond_to?(:[]) environment = { ACTIVATION_KEY => '1', SETTINGS_KEY => dump(settings), FAILURE_MODE_KEY => settings.policy.fail_open? ? 'open' : 'closed', 'RUBYOPT' => prepend_token(base_environment['RUBYOPT'], BOOT_REQUIRE, separator: ' '), 'RUBYLIB' => prepend_token(base_environment['RUBYLIB'], library_path, separator: File::PATH_SEPARATOR) } environment[WATCHDOG_SETTINGS_KEY] = dump_watchdog_policy(watchdog_policy) if watchdog_policy if operation_liveness_policy environment[OPERATION_LIVENESS_SETTINGS_KEY] = dump_operation_liveness_policy(operation_liveness_policy) end environment[PROBES_KEY] = '1' if probes_enabled environment.transform_values(&:freeze).freeze end |
.dump(settings) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/fiber_audit/runtime/environment.rb', line 73 def dump(settings) require_settings!(settings) payload = { 'protocol_version' => settings.protocol_version, 'launch_id' => settings.launch_id, 'project_root' => settings.project_root, 'output_directory' => settings.output_directory, 'policy' => policy_payload(settings.policy) } encoded = JSON.generate(payload) raise RuntimeSafetyError, 'runtime activation settings are too large' if encoded.bytesize > MAX_SETTINGS_BYTES encoded.freeze end |
.dump_operation_liveness_policy(policy) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/fiber_audit/runtime/environment.rb', line 155 def dump_operation_liveness_policy(policy) require_operation_liveness_policy!(policy) payload = { 'protocol_version' => PROTOCOL_VERSION, 'enabled' => policy.enabled, 'poll_interval_ms' => policy.poll_interval_ms, 'long_active_threshold_ms' => policy.long_active_threshold_ms } encoded = JSON.generate(payload) if encoded.bytesize > MAX_OPERATION_LIVENESS_SETTINGS_BYTES raise RuntimeSafetyError, 'runtime operation-liveness activation settings are too large' end encoded.freeze end |
.dump_watchdog_policy(policy) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/fiber_audit/runtime/environment.rb', line 115 def dump_watchdog_policy(policy) require_watchdog_policy!(policy) payload = { 'protocol_version' => PROTOCOL_VERSION, 'enabled' => policy.enabled, 'heartbeat_interval_ms' => policy.heartbeat_interval_ms, 'stall_threshold_ms' => policy.stall_threshold_ms, 'max_frames' => policy.max_frames } encoded = JSON.generate(payload) if encoded.bytesize > MAX_WATCHDOG_SETTINGS_BYTES raise RuntimeSafetyError, 'runtime watchdog activation settings are too large' end encoded.freeze end |
.failure_mode(environment = ENV) ⇒ Object
202 203 204 205 206 207 208 |
# File 'lib/fiber_audit/runtime/environment.rb', line 202 def failure_mode(environment = ENV) value = environment[FAILURE_MODE_KEY] return :open if value.nil? || value == 'open' return :closed if value == 'closed' raise RuntimeContractError, "#{FAILURE_MODE_KEY} must be open or closed" end |
.load(environment = ENV) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/fiber_audit/runtime/environment.rb', line 88 def load(environment = ENV) return unless activated?(environment) value = environment.fetch(SETTINGS_KEY) do raise RuntimeContractError, "missing runtime activation variable: #{SETTINGS_KEY}" end unless value.is_a?(String) && value.valid_encoding? && value.bytesize <= MAX_SETTINGS_BYTES raise RuntimeContractError, 'runtime activation settings are invalid' end payload = JSON.parse(value) require_exact_keys!(payload, SETTINGS_KEYS, 'runtime activation settings') policy_values = payload.fetch('policy') require_exact_keys!(policy_values, POLICY_KEYS, 'runtime activation policy') settings = Settings.new( protocol_version: payload.fetch('protocol_version'), launch_id: payload.fetch('launch_id'), project_root: payload.fetch('project_root'), output_directory: payload.fetch('output_directory'), policy: Policy.new(**symbolize_policy(policy_values)) ) validate_failure_mode!(environment, settings.policy) settings rescue JSON::ParserError, ArgumentError => e raise RuntimeContractError, "invalid runtime activation settings: #{e.}" end |
.load_operation_liveness_policy(environment = ENV) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/fiber_audit/runtime/environment.rb', line 171 def load_operation_liveness_policy(environment = ENV) value = environment[OPERATION_LIVENESS_SETTINGS_KEY] return OperationLivenessPolicy::DISABLED if value.nil? unless value.is_a?(String) && value.valid_encoding? && value.bytesize <= MAX_OPERATION_LIVENESS_SETTINGS_BYTES raise RuntimeContractError, 'runtime operation-liveness activation settings are invalid' end payload = JSON.parse(value) require_exact_keys!(payload, OPERATION_LIVENESS_KEYS, 'runtime operation-liveness activation settings') unless payload.fetch('protocol_version') == PROTOCOL_VERSION raise RuntimeContractError, "runtime operation-liveness activation protocol must be #{PROTOCOL_VERSION}" end OperationLivenessPolicy.new( enabled: payload.fetch('enabled'), poll_interval_ms: payload.fetch('poll_interval_ms'), long_active_threshold_ms: payload.fetch('long_active_threshold_ms') ) rescue JSON::ParserError, ArgumentError => e raise RuntimeContractError, "invalid runtime operation-liveness activation settings: #{e.}" end |
.load_watchdog_policy(environment = ENV) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/fiber_audit/runtime/environment.rb', line 132 def load_watchdog_policy(environment = ENV) value = environment[WATCHDOG_SETTINGS_KEY] return WatchdogPolicy::DISABLED if value.nil? unless value.is_a?(String) && value.valid_encoding? && value.bytesize <= MAX_WATCHDOG_SETTINGS_BYTES raise RuntimeContractError, 'runtime watchdog activation settings are invalid' end payload = JSON.parse(value) require_exact_keys!(payload, WATCHDOG_KEYS, 'runtime watchdog activation settings') unless payload.fetch('protocol_version') == PROTOCOL_VERSION raise RuntimeContractError, "runtime watchdog activation protocol must be #{PROTOCOL_VERSION}" end WatchdogPolicy.new( enabled: payload.fetch('enabled'), heartbeat_interval_ms: payload.fetch('heartbeat_interval_ms'), stall_threshold_ms: payload.fetch('stall_threshold_ms'), max_frames: payload.fetch('max_frames') ) rescue JSON::ParserError, ArgumentError => e raise RuntimeContractError, "invalid runtime watchdog activation settings: #{e.}" end |
.normalize_directory(value, field) ⇒ Object
262 263 264 265 266 267 |
# File 'lib/fiber_audit/runtime/environment.rb', line 262 def normalize_directory(value, field) normalized = normalize_absolute_path(value, field) raise RuntimeContractError, "#{field} must be an existing directory" unless File.directory?(normalized) normalized.freeze end |
.prepare_output_directory(path) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/fiber_audit/runtime/environment.rb', line 247 def prepare_output_directory(path) normalized = normalize_absolute_path(path, 'output directory') if File.exist?(normalized) raise RuntimeSafetyError, "runtime output is not a directory: #{normalized}" unless File.directory?(normalized) return normalized end FileUtils.mkdir_p(normalized, mode: 0o700) File.chmod(0o700, normalized) normalized rescue SystemCallError => e raise RuntimeSafetyError, "cannot prepare runtime output directory: #{e.}" end |
.probes_enabled?(environment = ENV) ⇒ Boolean
210 211 212 213 214 215 216 |
# File 'lib/fiber_audit/runtime/environment.rb', line 210 def probes_enabled?(environment = ENV) value = environment[PROBES_KEY] return false if value.nil? return true if value == '1' raise RuntimeContractError, "#{PROBES_KEY} must be 1 when present" end |