lex-governance 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c49ec8c4434d925672bf24d03d0d568673dba8007ea72303b5d345fb87a5142c
4
- data.tar.gz: 85e0ccc337f078cdc9cd7f8b4f2abf0c311f66c1bc9fc15ed0e6483f4c187290
3
+ metadata.gz: 3189a600f236fa9cc937e52c9c5591b62e8c99468d061b9eb4fdc69c3ee26d04
4
+ data.tar.gz: 1d55e9b3727a66c33e7414a19719c5326387abe784ca8a1d88e52e73ac1f2778
5
5
  SHA512:
6
- metadata.gz: 16ce4ad3ee7c08f7feeaf9e48efc9ff7ac15a1636be69e7cf59103a61684f3f77f296b2ee791be8c11caa4443e5b5790d55acc31f96899f77c96e7d932847b72
7
- data.tar.gz: 42ef43f72cfd53b14b3095128b441809568fb03a6885631e3607089b69a2d8c0a981db3e788724d3b5f4164333c5bf3b142735d33e7a6ced5d9739d16740354b
6
+ metadata.gz: bd0099e5d6c31ede525c9fdb9856d70101bba628b7ffa99acdd863c81d3cd5549ce57c2ec35a668329b07886e6b17919fe3b871fd962bd83f669ffff4557348d
7
+ data.tar.gz: 8f894c7e5624de924d69a1eb3a30c0fd21bab6d8d1eacb20a1e042a6c699c4f97ccb2bb2f8c333c28bf6d44a8c6f4cd828fabfcb522a60c9d599810078b03088
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Governance
6
+ module Helpers
7
+ module Authority
8
+ AUTHORITY_REQUIRED = {
9
+ %w[active paused] => :owner_or_manager,
10
+ %w[paused active] => :owner_or_manager,
11
+ %w[active retired] => :owner_or_manager
12
+ }.freeze
13
+
14
+ module_function
15
+
16
+ def check_authority(principal_id:, from_state:, to_state:, worker_owner: nil, **)
17
+ required = authority_for(from_state, to_state)
18
+ return { allowed: true, reason: :no_authority_required } unless required
19
+ return { allowed: true, reason: :system_principal } if principal_id == 'system'
20
+ return { allowed: false, reason: :authority_required, required: required } if principal_id.nil?
21
+
22
+ case required
23
+ when :owner_or_manager
24
+ if principal_id == worker_owner
25
+ { allowed: true, reason: :owner_match }
26
+ else
27
+ { allowed: false, reason: :authority_required, required: required,
28
+ principal_id: principal_id, worker_owner: worker_owner }
29
+ end
30
+ else
31
+ { allowed: false, reason: :authority_required, required: required }
32
+ end
33
+ end
34
+
35
+ def authority_for(from_state, to_state)
36
+ AUTHORITY_REQUIRED[[from_state, to_state]]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Governance
6
+ module Helpers
7
+ module Council
8
+ module_function
9
+
10
+ def council_approved?(worker_id:, from_state:, to_state:, **)
11
+ return { allowed: true, reason: :audit_not_loaded } unless defined?(Legion::Extensions::Audit::Runners::ApprovalQueue)
12
+
13
+ record = find_approved_record(worker_id: worker_id, from_state: from_state, to_state: to_state)
14
+ if record
15
+ { allowed: true, reason: :council_approved, approval_id: record[:id] }
16
+ else
17
+ { allowed: false, reason: :council_approval_required,
18
+ worker_id: worker_id, from_state: from_state, to_state: to_state }
19
+ end
20
+ end
21
+
22
+ def submit_approval(worker_id:, from_state:, to_state:, requester_id:, **)
23
+ unless defined?(Legion::Extensions::Audit::Runners::ApprovalQueue)
24
+ return { success: false, reason: :audit_not_loaded }
25
+ end
26
+
27
+ Legion::Extensions::Audit::Runners::ApprovalQueue.submit(
28
+ approval_type: 'lifecycle_transition',
29
+ payload: { worker_id: worker_id, from_state: from_state, to_state: to_state },
30
+ requester_id: requester_id
31
+ )
32
+ end
33
+
34
+ def find_approved_record(**)
35
+ nil
36
+ rescue StandardError
37
+ nil
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -5,6 +5,23 @@ module Legion
5
5
  module Governance
6
6
  module Runners
7
7
  module Governance
8
+ def review_transition(worker_id:, from_state:, to_state:, principal_id: nil, worker_owner: nil, **)
9
+ return { allowed: true, skipped: true } unless governance_enabled?
10
+
11
+ results = []
12
+ results << check_airb_approval(worker_id: worker_id)
13
+ results << check_council_approval(worker_id: worker_id, from_state: from_state, to_state: to_state)
14
+ results << check_authority_level(principal_id: principal_id, from_state: from_state, to_state: to_state,
15
+ worker_owner: worker_owner)
16
+
17
+ blocked = results.reject { |r| r[:allowed] }
18
+ return { allowed: true, checks: results } if blocked.empty?
19
+
20
+ auto = try_auto_submit(blocked, worker_id: worker_id, from_state: from_state, to_state: to_state,
21
+ requester_id: principal_id || 'system')
22
+ { allowed: false, reasons: blocked.map { |r| r[:reason] }, checks: results, auto_submitted: auto }
23
+ end
24
+
8
25
  def check_airb_approval(worker_id:, **)
9
26
  require_relative '../helpers/airb'
10
27
  record = Helpers::Airb.fetch(worker_id: worker_id)
@@ -21,6 +38,72 @@ module Legion
21
38
  reason: allowed ? :airb_cleared : :airb_blocked
22
39
  }
23
40
  end
41
+
42
+ def check_council_approval(worker_id:, from_state:, to_state:, **)
43
+ require_relative '../helpers/council'
44
+ required = council_required?(from_state, to_state)
45
+ return { allowed: true, reason: :no_council_required } unless required
46
+
47
+ Helpers::Council.council_approved?(worker_id: worker_id, from_state: from_state, to_state: to_state)
48
+ end
49
+
50
+ def check_authority_level(principal_id:, from_state:, to_state:, worker_owner: nil, **)
51
+ require_relative '../helpers/authority'
52
+ Helpers::Authority.check_authority(
53
+ principal_id: principal_id, from_state: from_state, to_state: to_state,
54
+ worker_owner: worker_owner
55
+ )
56
+ end
57
+
58
+ def governance_enabled?
59
+ gov = Legion::Settings[:governance]
60
+ return false if gov.is_a?(Hash) && gov.key?(:enabled) && gov[:enabled] == false
61
+
62
+ if Legion::Settings.dig(:governance, :bypass_in_dev) && Legion::Settings.respond_to?(:dev_mode?) && Legion::Settings.dev_mode?
63
+ return false
64
+ end
65
+
66
+ true
67
+ end
68
+
69
+ def auto_submit?
70
+ gov = Legion::Settings[:governance]
71
+ return true unless gov.is_a?(Hash) && gov.key?(:auto_submit_approval)
72
+
73
+ gov[:auto_submit_approval]
74
+ end
75
+
76
+ def council_required_transitions
77
+ Legion::Settings.dig(:governance, :council, :required_transitions)
78
+ end
79
+
80
+ private
81
+
82
+ def try_auto_submit(blocked, worker_id:, from_state:, to_state:, requester_id:)
83
+ return false unless auto_submit? && blocked.any? { |r| r[:reason] == :council_approval_required }
84
+
85
+ require_relative '../helpers/council'
86
+ Helpers::Council.submit_approval(worker_id: worker_id, from_state: from_state, to_state: to_state,
87
+ requester_id: requester_id)
88
+ true
89
+ end
90
+
91
+ def council_required?(from_state, to_state)
92
+ custom = council_required_transitions
93
+ if custom
94
+ custom.any? { |pair| pair == [from_state, to_state] }
95
+ else
96
+ governance_required_defaults.key?([from_state, to_state])
97
+ end
98
+ end
99
+
100
+ def governance_required_defaults
101
+ if defined?(Legion::DigitalWorker::Lifecycle::GOVERNANCE_REQUIRED)
102
+ Legion::DigitalWorker::Lifecycle::GOVERNANCE_REQUIRED
103
+ else
104
+ { %w[retired terminated] => :council_approval, %w[active terminated] => :council_approval }
105
+ end
106
+ end
24
107
  end
25
108
  end
26
109
  end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Governance
6
- VERSION = '0.2.1'
6
+ VERSION = '0.3.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-governance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -18,6 +18,8 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - lib/legion/extensions/governance.rb
20
20
  - lib/legion/extensions/governance/helpers/airb.rb
21
+ - lib/legion/extensions/governance/helpers/authority.rb
22
+ - lib/legion/extensions/governance/helpers/council.rb
21
23
  - lib/legion/extensions/governance/runners/governance.rb
22
24
  - lib/legion/extensions/governance/version.rb
23
25
  homepage: https://github.com/LegionIO