Class: Archsight::Analysis::Sandbox

Inherits:
Object
  • Object
show all
Defined in:
lib/archsight/analysis/sandbox.rb

Overview

Sandbox provides a safe execution context for Analysis scripts. Scripts are evaluated via instance_eval with access only to explicitly defined methods.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(database) ⇒ Sandbox

Returns a new instance of Sandbox.



14
15
16
17
18
# File 'lib/archsight/analysis/sandbox.rb', line 14

def initialize(database)
  @database = database
  @sections = []
  @resolver_cache = {}
end

Instance Attribute Details

#sectionsObject (readonly)

Output sections collected during script execution



12
13
14
# File 'lib/archsight/analysis/sandbox.rb', line 12

def sections
  @sections
end

Instance Method Details

#_set_analysis(analysis) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the current analysis being executed (called by Executor)

Parameters:

  • analysis (Object)

    Analysis instance



272
273
274
# File 'lib/archsight/analysis/sandbox.rb', line 272

def _set_analysis(analysis)
  @current_analysis = analysis
end

#annotation(inst, key) ⇒ Object?

Get an annotation value from an instance

Parameters:

  • inst (Object)

    Instance

  • key (String)

    Annotation key

Returns:

  • (Object, nil)

    Annotation value



86
87
88
# File 'lib/archsight/analysis/sandbox.rb', line 86

def annotation(inst, key)
  inst.annotations[key]
end

#annotations(inst) ⇒ Hash

Get all annotations from an instance (frozen copy)

Parameters:

  • inst (Object)

    Instance

Returns:

  • (Hash)

    Frozen hash of annotations



93
94
95
# File 'lib/archsight/analysis/sandbox.rb', line 93

def annotations(inst)
  inst.annotations.dup.freeze
end

#avg(values) ⇒ Float?

Calculate average

Parameters:

  • values (Array<Numeric>)

    Values to average

Returns:

  • (Float, nil)

    Average or nil if empty



139
140
141
142
143
144
# File 'lib/archsight/analysis/sandbox.rb', line 139

def avg(values)
  compact = values.compact
  return nil if compact.empty?

  compact.sum.to_f / compact.size
end

#code(content, lang: "") ⇒ Object

Add a code block

Parameters:

  • content (String)

    Code content

  • lang (String) (defaults to: "")

    Language for syntax highlighting (default: plain)



220
221
222
# File 'lib/archsight/analysis/sandbox.rb', line 220

def code(content, lang: "")
  @sections << { type: :code, content: content, lang: lang }
end

#collect(items, key = nil) {|item| ... } ⇒ Array

Collect values into array

Parameters:

  • items (Array)

    Items

  • key (String, Symbol, nil) (defaults to: nil)

    Optional key to extract

Yields:

  • (item)

    Optional block to transform items

Returns:

  • (Array)

    Collected values



165
166
167
168
169
170
171
172
173
# File 'lib/archsight/analysis/sandbox.rb', line 165

def collect(items, key = nil, &block)
  if block
    items.map(&block).compact
  elsif key
    items.map { |item| item.respond_to?(key) ? item.send(key) : item.annotations[key.to_s] }.compact
  else
    items.compact
  end
end

#config(key) ⇒ Object?

Get a configuration value from the analysis

Parameters:

  • key (String)

    Configuration key (without ‘analysis/config/’ prefix)

Returns:

  • (Object, nil)

    Configuration value



265
266
267
# File 'lib/archsight/analysis/sandbox.rb', line 265

def config(key)
  @current_analysis&.annotations&.[]("analysis/config/#{key}")
end

#count(items) ⇒ Integer

Count items

Parameters:

  • items (Array)

    Items to count

Returns:

  • (Integer)

    Count



132
133
134
# File 'lib/archsight/analysis/sandbox.rb', line 132

def count(items)
  items.compact.count
end

#each_instance(kind) {|instance| ... } ⇒ Object

Iterate over all instances of a kind

Parameters:

  • kind (Symbol, String)

    Resource kind (e.g., :ApplicationService)

Yields:

  • (instance)

    Block called for each instance



25
26
27
# File 'lib/archsight/analysis/sandbox.rb', line 25

def each_instance(kind, &)
  instances(kind).each(&)
end

#error(message) ⇒ Object

Log an error message

Parameters:

  • message (String)

    Error message



250
251
252
# File 'lib/archsight/analysis/sandbox.rb', line 250

def error(message)
  @sections << { type: :message, level: :error, message: message }
end

#group_by(items) {|item| ... } ⇒ Hash

Group items by a key

Parameters:

  • items (Array)

    Items to group

Yields:

  • (item)

    Block that returns the grouping key

Returns:

  • (Hash)

    Grouped items



179
180
181
# File 'lib/archsight/analysis/sandbox.rb', line 179

def group_by(items, &)
  items.group_by(&)
end

#heading(text, level: 0) ⇒ Object

Add a heading

Parameters:

  • text (String)

    Heading text

  • level (Integer) (defaults to: 0)

    Heading level (0-6, default 0) Level 0 creates accordion sections in the web UI Levels 1-6 map to HTML h2-h6 within sections



190
191
192
# File 'lib/archsight/analysis/sandbox.rb', line 190

def heading(text, level: 0)
  @sections << { type: :heading, text: text, level: level.clamp(0, 6) }
end

#incoming(inst, kind = nil) ⇒ Array

Get direct incoming relations (instances that reference this one)

Parameters:

  • inst (Object)

    Target instance

  • kind (Symbol, nil) (defaults to: nil)

    Optional kind filter

Returns:

  • (Array)

    Instances referencing this one



67
68
69
# File 'lib/archsight/analysis/sandbox.rb', line 67

def incoming(inst, kind = nil)
  resolver_for(inst).incoming(kind)
end

#incoming_transitive(inst, kind = nil, max_depth: 10) ⇒ Array

Get transitive incoming relations

Parameters:

  • inst (Object)

    Target instance

  • kind (Symbol, nil) (defaults to: nil)

    Optional kind filter

  • max_depth (Integer) (defaults to: 10)

    Maximum traversal depth

Returns:

  • (Array)

    Instances transitively referencing this one



76
77
78
# File 'lib/archsight/analysis/sandbox.rb', line 76

def incoming_transitive(inst, kind = nil, max_depth: 10)
  resolver_for(inst).incoming_transitive(kind, max_depth: max_depth)
end

#info(message) ⇒ Object

Log an info message

Parameters:

  • message (String)

    Info message



256
257
258
# File 'lib/archsight/analysis/sandbox.rb', line 256

def info(message)
  @sections << { type: :message, level: :info, message: message }
end

#instance(kind, name) ⇒ Object?

Get a specific instance by kind and name

Parameters:

  • kind (Symbol, String)

    Resource kind

  • name (String)

    Instance name

Returns:

  • (Object, nil)

    Instance or nil if not found



40
41
42
# File 'lib/archsight/analysis/sandbox.rb', line 40

def instance(kind, name)
  @database.instance_by_kind(kind.to_s, name)
end

#instances(kind) ⇒ Array

Get all instances of a kind

Parameters:

  • kind (Symbol, String)

    Resource kind

Returns:

  • (Array)

    Array of instances



32
33
34
# File 'lib/archsight/analysis/sandbox.rb', line 32

def instances(kind)
  @database.instances_by_kind(kind.to_s).values
end

#kind(inst) ⇒ String

Get the kind of an instance

Parameters:

  • inst (Object)

    Instance

Returns:

  • (String)

    Instance kind



107
108
109
# File 'lib/archsight/analysis/sandbox.rb', line 107

def kind(inst)
  inst.klass
end

#list(items) ⇒ Object

Add a bullet list

Parameters:

  • items (Array<String, Hash>)

    List items (strings or hashes with :text key)



211
212
213
214
215
# File 'lib/archsight/analysis/sandbox.rb', line 211

def list(items)
  return if items.empty?

  @sections << { type: :list, items: items }
end

#max(values) ⇒ Numeric?

Find maximum value

Parameters:

  • values (Array<Numeric>)

    Values

Returns:

  • (Numeric, nil)

    Maximum



156
157
158
# File 'lib/archsight/analysis/sandbox.rb', line 156

def max(values)
  values.compact.max
end

#min(values) ⇒ Numeric?

Find minimum value

Parameters:

  • values (Array<Numeric>)

    Values

Returns:

  • (Numeric, nil)

    Minimum



149
150
151
# File 'lib/archsight/analysis/sandbox.rb', line 149

def min(values)
  values.compact.min
end

#name(inst) ⇒ String

Get the name of an instance

Parameters:

  • inst (Object)

    Instance

Returns:

  • (String)

    Instance name



100
101
102
# File 'lib/archsight/analysis/sandbox.rb', line 100

def name(inst)
  inst.name
end

#outgoing(inst, kind = nil) ⇒ Array

Get direct outgoing relations

Parameters:

  • inst (Object)

    Source instance

  • kind (Symbol, nil) (defaults to: nil)

    Optional kind filter

Returns:

  • (Array)

    Related instances



50
51
52
# File 'lib/archsight/analysis/sandbox.rb', line 50

def outgoing(inst, kind = nil)
  resolver_for(inst).outgoing(kind)
end

#outgoing_transitive(inst, kind = nil, max_depth: 10) ⇒ Array

Get transitive outgoing relations

Parameters:

  • inst (Object)

    Source instance

  • kind (Symbol, nil) (defaults to: nil)

    Optional kind filter

  • max_depth (Integer) (defaults to: 10)

    Maximum traversal depth

Returns:

  • (Array)

    Transitively related instances



59
60
61
# File 'lib/archsight/analysis/sandbox.rb', line 59

def outgoing_transitive(inst, kind = nil, max_depth: 10)
  resolver_for(inst).outgoing_transitive(kind, max_depth: max_depth)
end

#query(query_string) ⇒ Array

Execute a query string

Parameters:

  • query_string (String)

    Query string

Returns:

  • (Array)

    Matching instances



116
117
118
# File 'lib/archsight/analysis/sandbox.rb', line 116

def query(query_string)
  @database.query(query_string)
end

#report(data, title: nil) ⇒ Object

Report findings (legacy method - creates appropriate section based on data type)

Parameters:

  • data (Object)

    Report data (usually Array or Hash)

  • title (String, nil) (defaults to: nil)

    Optional report title



229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/archsight/analysis/sandbox.rb', line 229

def report(data, title: nil)
  heading(title, level: 1) if title

  case data
  when Array
    report_array(data)
  when Hash
    report_hash(data)
  else
    text(data.to_s)
  end
end

#sum(values) ⇒ Numeric

Sum numeric values

Parameters:

  • values (Array<Numeric>)

    Values to sum

Returns:

  • (Numeric)

    Sum



125
126
127
# File 'lib/archsight/analysis/sandbox.rb', line 125

def sum(values)
  values.compact.sum
end

#table(headers:, rows:) ⇒ Object

Add a table

Parameters:

  • headers (Array<String>)

    Column headers

  • rows (Array<Array>)

    Table rows (each row is an array of values)



203
204
205
206
207
# File 'lib/archsight/analysis/sandbox.rb', line 203

def table(headers:, rows:)
  return if rows.empty?

  @sections << { type: :table, headers: headers, rows: rows }
end

#text(content) ⇒ Object

Add a text paragraph

Parameters:

  • content (String)

    Text content (supports markdown)



196
197
198
# File 'lib/archsight/analysis/sandbox.rb', line 196

def text(content)
  @sections << { type: :text, content: content }
end

#warning(message) ⇒ Object

Log a warning message

Parameters:

  • message (String)

    Warning message



244
245
246
# File 'lib/archsight/analysis/sandbox.rb', line 244

def warning(message)
  @sections << { type: :message, level: :warning, message: message }
end