Module: CommandTower::Audit::Attribution

Defined in:
lib/command_tower/audit/attribution.rb

Constant Summary collapse

MODES =
%i[self_service admin_direct impersonation system].freeze

Class Method Summary collapse

Class Method Details

.envelope(mode:, actor_user_id:, affected_user_id:) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/command_tower/audit/attribution.rb', line 77

def envelope(mode:, actor_user_id:, affected_user_id:)
  {
    attribution_mode: mode,
    actor_user_id:,
    affected_user_id:,
    effective_user_id: CommandTower::Current.effective_user_id || CommandTower::Current.user_id,
    originating_administrator_id: CommandTower::Current.originating_administrator_id,
    impersonation_active: CommandTower::Current.impersonation_active == true,
    user_id: CommandTower::Current.user_id
  }
end

.normalize_mode(value) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/command_tower/audit/attribution.rb', line 66

def normalize_mode(value)
  return nil if value.nil?

  mode = value.to_sym
  unless MODES.include?(mode)
    raise InvalidAttributionError, "invalid attribution_mode #{value.inspect}"
  end

  mode
end

.resolve(affected_user_id:, attribution_mode:) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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/command_tower/audit/attribution.rb', line 10

def resolve(affected_user_id:, attribution_mode:)
  requested = normalize_mode(attribution_mode)
  impersonating = CommandTower::Current.impersonation_active == true

  if impersonating
    if requested && requested != :impersonation
      raise InvalidAttributionError,
        "attribution_mode #{requested} conflicts with active impersonation"
    end

    originating = CommandTower::Current.originating_administrator_id
    if originating.nil?
      raise InvalidAttributionError, "impersonation requires originating_administrator_id"
    end

    return envelope(
      mode: :impersonation,
      actor_user_id: originating,
      affected_user_id:
    )
  end

  if requested == :impersonation
    raise InvalidAttributionError, "attribution_mode impersonation requires impersonation_active"
  end

  if requested == :system || (requested.nil? && CommandTower::Current.user_id.nil?)
    return envelope(mode: :system, actor_user_id: nil, affected_user_id:)
  end

  if requested == :admin_direct
    if CommandTower::Current.user_id.nil?
      raise InvalidAttributionError, "admin_direct requires a Current.user_id actor"
    end

    return envelope(mode: :admin_direct, actor_user_id: CommandTower::Current.user_id, affected_user_id:)
  end

  actor_id = CommandTower::Current.user_id
  if actor_id.nil?
    raise InvalidAttributionError, "self_service requires a Current.user_id actor"
  end

  if requested.nil? && !affected_user_id.nil? && actor_id != affected_user_id
    raise InvalidAttributionError,
      "attribution_mode must be explicit when actor and affected user differ"
  end

  if requested == :self_service && !affected_user_id.nil? && actor_id != affected_user_id
    raise InvalidAttributionError,
      "self_service requires Current.user_id to match affected_user_id"
  end

  envelope(mode: :self_service, actor_user_id: actor_id, affected_user_id:)
end