Module: KairosMcp::Daemon::PolicyElevation
- Defined in:
- lib/kairos_mcp/daemon/policy_elevation.rb
Overview
PolicyElevation — temporary, single-shot policy override for daemon code-gen.
Design (P3.2 v0.2 §5, MF2+MF5 fix):
- Nest check BEFORE push (R2 residual: prevent override leak on ElevationNestError)
- Opaque ElevationToken with object identity comparison
- Single-threaded daemon assumption (documented)
NOTE: This module operates on a Safety-like object that supports push_policy_override / pop_policy_override. In the daemon context, DaemonPolicy installs deny-by-default policies on Safety. PolicyElevation temporarily overrides them for a single approved proposal.
Defined Under Namespace
Classes: ElevationNestError
Constant Summary collapse
- CAPABILITY_MAP =
{ l0: :can_modify_l0, l1: :can_modify_l1 }.freeze
Class Method Summary collapse
- .log(logger, level, msg) ⇒ Object
-
.with_elevation(safety, scope:, proposal_id:, granted_by:, logger: nil) {|ElevationToken| ... } ⇒ Object
Block’s return value.
Class Method Details
.log(logger, level, msg) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/kairos_mcp/daemon/policy_elevation.rb', line 66 def self.log(logger, level, msg) return unless logger logger.respond_to?(level) ? logger.public_send(level, msg) : nil rescue StandardError # never let logger crash mask elevation lifecycle end |
.with_elevation(safety, scope:, proposal_id:, granted_by:, logger: nil) {|ElevationToken| ... } ⇒ Object
Returns block’s return value.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/kairos_mcp/daemon/policy_elevation.rb', line 34 def self.with_elevation(safety, scope:, proposal_id:, granted_by:, logger: nil) cap = CAPABILITY_MAP[scope] raise ArgumentError, "scope #{scope} does not require elevation" unless cap # R2 fix: nest check BEFORE push to prevent override leak if ExecutionContext.current_elevation_token raise ElevationNestError, 'nested elevation forbidden' end token = ElevationToken.new( proposal_id: proposal_id, scope: scope, granted_by: granted_by ) safety.push_policy_override(cap) do |_user| active = ExecutionContext.current_elevation_token active&.matches?(token) || false end ExecutionContext.current_elevation_token = token log(logger, :info, "elevation_granted proposal=#{proposal_id} scope=#{scope} by=#{granted_by}") begin yield token ensure ExecutionContext.current_elevation_token = nil safety.pop_policy_override(cap) log(logger, :info, "elevation_revoked proposal=#{proposal_id}") end end |