Class: GlobiGuard::GovernedActions

Inherits:
Object
  • Object
show all
Defined in:
lib/globiguard.rb

Instance Method Summary collapse

Constructor Details

#initialize(transport, read_only:) ⇒ GovernedActions

Returns a new instance of GovernedActions.



165
166
167
168
# File 'lib/globiguard.rb', line 165

def initialize(transport, read_only:)
  @transport = transport
  @read_only = read_only
end

Instance Method Details

#approval_status(approval_id) ⇒ Object



217
218
219
# File 'lib/globiguard.rb', line 217

def approval_status(approval_id)
  @transport.request("get", "/v1/actions/approvals/#{path_segment(approval_id)}")
end

#authorize_action(body) ⇒ Object



170
171
172
173
# File 'lib/globiguard.rb', line 170

def authorize_action(body)
  require_write!("Action authorization")
  @transport.request("post", "/v1/actions/authorize", body: body)
end

#authorize_action_or_throw(body) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/globiguard.rb', line 175

def authorize_action_or_throw(body)
  result = authorize_action(body)
  decision = result["decision"]
  if decision == "ALLOW"
    raise "A dry-run decision is not an execution permit." if body[:dryRun] == true || body["dryRun"] == true
    unless result["executable"] == true && result["nextAction"] == "EXECUTE_EXACT_ACTION_ONCE"
      raise "The control plane marked this response as non-executable."
    end
    unless %w[NOT_REQUIRED APPROVED].include?(result["approvalState"])
      raise "Resolve review and reauthorize before execution."
    end
    expires_at = begin
      Time.iso8601(result["expiresAt"])
    rescue ArgumentError, TypeError
      nil
    end
    if expires_at.nil? || expires_at <= Time.now || expires_at - Time.now > 300
      raise "Execution authority must have a current, bounded expiry."
    end
    if result["obligations"].is_a?(Array) && !result["obligations"].empty?
      raise "Enforce all obligations and reauthorize before execution."
    end
    if result["modifications"].is_a?(Hash) && !result["modifications"].empty?
      raise "Apply all modifications and reauthorize before execution."
    end
    return result
  end
  if decision == "MODIFY"
    raise "Apply modifications and reauthorize the exact resulting action before execution."
  end
  raise "GlobiGuard blocked the governed action." if decision == "BLOCK"
  if decision == "QUEUE"
    raise "GlobiGuard queued the governed action for review; do not perform the downstream business action yet."
  end
  raise "GlobiGuard returned an unsupported decision; do not perform the downstream business action."
end

#evidence_package_summary(evidence_package_id) ⇒ Object



238
239
240
241
242
243
# File 'lib/globiguard.rb', line 238

def evidence_package_summary(evidence_package_id)
  @transport.request(
    "get",
    "/v1/audit/evidence-packages/#{path_segment(evidence_package_id)}/summary"
  )
end

#evidence_references(authorization_id: nil, approval_id: nil, workflow_run_id: nil) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
# File 'lib/globiguard.rb', line 221

def evidence_references(authorization_id: nil, approval_id: nil, workflow_run_id: nil)
  @transport.request(
    "get",
    "/v1/actions/evidence",
    query: {
      authorizationId: authorization_id,
      approvalId: approval_id,
      workflowRunId: workflow_run_id
    }
  )
end

#export_evidence_package(body = {}) ⇒ Object



233
234
235
236
# File 'lib/globiguard.rb', line 233

def export_evidence_package(body = {})
  require_write!("Evidence export")
  @transport.request("post", "/v1/audit/export", body: body)
end

#incident_replay(lookup_kind, lookup_id) ⇒ Object

Raises:

  • (ArgumentError)


245
246
247
248
249
250
251
252
253
254
# File 'lib/globiguard.rb', line 245

def incident_replay(lookup_kind, lookup_id)
  allowed = %w[workflowRunId correlationId queueEntryId auditEventId authorizationId]
  raise ArgumentError, "Unsupported incident replay lookup kind." unless allowed.include?(lookup_kind)

  @transport.request(
    "get",
    "/v1/audit/incident-replay",
    query: { lookup_kind => lookup_id }
  )
end

#request_approval(body) ⇒ Object



212
213
214
215
# File 'lib/globiguard.rb', line 212

def request_approval(body)
  require_write!("Approval creation")
  @transport.request("post", "/v1/actions/approvals", body: body)
end

#review_queue(queue_entry_id, action, body = {}) ⇒ Object

Raises:

  • (ArgumentError)


256
257
258
259
260
261
262
263
264
265
266
# File 'lib/globiguard.rb', line 256

def review_queue(queue_entry_id, action, body = {})
  require_write!("Queue review")
  allowed = %w[approve reject modify escalate resume]
  raise ArgumentError, "Unsupported queue review action." unless allowed.include?(action)

  @transport.request(
    "post",
    "/v1/queue/#{path_segment(queue_entry_id)}/#{action}",
    body: body
  )
end

#wait_for_approval(queue_entry_id, max_attempts: 60, interval_seconds: 1.0) ⇒ Object

Raises:

  • (ArgumentError)


268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/globiguard.rb', line 268

def wait_for_approval(queue_entry_id, max_attempts: 60, interval_seconds: 1.0)
  raise ArgumentError, "max_attempts must be at least 1." if max_attempts < 1

  max_attempts.times do |index|
    entry = @transport.request("get", "/v1/queue/#{path_segment(queue_entry_id)}")
    status = entry["status"]
    return entry if %w[APPROVED AUTO_APPROVED RESUMED].include?(status)
    if %w[REJECTED EXPIRED FAILED].include?(status)
      raise "Queued action resolved as #{status}; do not perform the downstream business action."
    end
    if status == "MODIFIED"
      raise "The reviewer approved a modified action summary. Rebuild the real payload and request a new authorization before executing it."
    end
    unless %w[PENDING ESCALATED].include?(status)
      raise "GlobiGuard returned an unsupported approval state; the downstream business action remains stopped."
    end
    sleep(interval_seconds) if index + 1 < max_attempts
  end
  raise "Queued action is still pending; do not perform the downstream business action yet."
end