Class: Contrast::Agent::Assess::Policy::PolicyNode

Inherits:
Patching::Policy::PolicyNode show all
Defined in:
lib/contrast/agent/assess/policy/policy_node.rb

Overview

This class functions to translate our policy.json into an actionable Ruby object, allowing for dynamic patching over hardcoded patching.

Direct Known Subclasses

PropagationNode, SourceNode, TriggerNode

Constant Summary collapse

ALL_TYPE =
'A'
TO_MARKER =
'2'
JSON_SOURCE =

The keys used to read from policy.json to create the individual policy nodes. These are common across node types

'source'
JSON_TARGET =
'target'
JSON_TAGS =
'tags'
JSON_DATAFLOW =
'dataflow'

Instance Attribute Summary collapse

Attributes inherited from Patching::Policy::PolicyNode

#class_name, #instance_method, #method_name, #method_scope, #method_visibility, #properties

Instance Method Summary collapse

Methods inherited from Patching::Policy::PolicyNode

#id, #instance_method?

Methods included from Components::Interface

included

Constructor Details

#initialize(policy_hash = {}) ⇒ PolicyNode



17
18
19
20
21
22
23
24
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 17

def initialize policy_hash = {}
  super(policy_hash)
  @source_string = policy_hash[JSON_SOURCE]
  @target_string = policy_hash[JSON_TARGET]
  @tags = Set.new(policy_hash[JSON_TAGS])
  generate_sources
  generate_targets
end

Instance Attribute Details

#source_stringObject (readonly)

Returns the value of attribute source_string.



15
16
17
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 15

def source_string
  @source_string
end

#sourcesObject (readonly)

Returns the value of attribute sources.



15
16
17
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 15

def sources
  @sources
end

#tagsObject

Returns the value of attribute tags.



14
15
16
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 14

def tags
  @tags
end

#target_stringObject

Returns the value of attribute target_string.



15
16
17
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 15

def target_string
  @target_string
end

#targetsObject (readonly)

Returns the value of attribute targets.



15
16
17
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 15

def targets
  @targets
end

#typeObject

Returns the value of attribute type.



14
15
16
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 14

def type
  @type
end

Instance Method Details

#add_property(name, value) ⇒ Object

Sometimes we need to tie information to an event. We’ll add a properties section to the patch node, which can pass them along to the pre-dtm event



56
57
58
59
60
61
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 56

def add_property name, value
  return unless name && value

  @properties ||= {}
  @properties[name] = value
end

#build_actionObject

Convert our action, built from our source and target, into the TS appropriate action. That’s a single source to single target marker (A,O,P,R)

Creation (source nodes) don’t have sources (they are the source) Trigger (trigger nodes) don’t have targets (they are the target) Everything else (propagation nodes) are Source2Target



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 158

def build_action
  @event_action ||= begin
    case node_class
    when Contrast::Agent::Assess::Policy::SourceNode::SOURCE
      :CREATION
    when Contrast::Agent::Assess::Policy::TriggerNode::TRIGGER
      :TRIGGER
    else
      if source_string.nil?
        :CREATION
      elsif target_string.nil?
        :TRIGGER
      else
        # TeamServer can't handle the multi-source or multi-target
        # values. Give it some help by changing them to 'A'
        source = source_string.include?(Contrast::Utils::ObjectShare::COMMA) ? ALL_TYPE : source_string
        target = target_string.include?(Contrast::Utils::ObjectShare::COMMA) ? ALL_TYPE : target_string
        str = source[0] + TO_MARKER + target[0]
        str.to_sym
      end
    end
  end
  @event_action
end

#featureObject



26
27
28
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 26

def feature
  'Assess'
end

#generate_sourcesObject

Given a source in the format A,B,C, populate the sources of this node 1) Split on ‘,’ 2) If ‘O’, add the source, else it’s P (we don’t have R sources) and

needs to be converted. P type will either be P:name or P# where #
is the index of the parameter. Drop the P and store the int as int
or name as symbol


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 75

def generate_sources
  if source_string
    @sources = []
    source_string.split(Contrast::Utils::ObjectShare::COMMA).each do |s|
      is_object = (s == Contrast::Utils::ObjectShare::OBJECT_KEY)
      if is_object
        @sources << s
      else
        parameter_source = s[1..-1]
        @sources << if parameter_source.start_with?(Contrast::Utils::ObjectShare::COLON)
                      parameter_source[1..-1].to_sym
                    else
                      parameter_source.to_i
                    end
      end
    end
  else
    @sources = Contrast::Utils::ObjectShare::EMPTY_ARRAY
  end
end

#generate_targetsObject

Given a target in the format A,B,C, populate the targets of this node 1) Split on ‘,’ 2) If ‘O’ or ‘R’, add the target, else it’s P and needs to be

converted. P type will either be P:name or P# where # is the index
of the paramter. Drop the P and store the int as int or name as
symbol


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 102

def generate_targets
  if target_string
    @targets = []
    target_string.split(Contrast::Utils::ObjectShare::COMMA).each do |t|
      case t
      when Contrast::Utils::ObjectShare::OBJECT_KEY
        @targets << t
      when Contrast::Utils::ObjectShare::RETURN_KEY
        @targets << t
      else
        parameter_target = t[1..-1]
        @targets << if parameter_target.start_with?(Contrast::Utils::ObjectShare::COLON)
                      parameter_target[1..-1].to_sym
                    else
                      parameter_target.to_i
                    end
      end
    end
  else
    @targets = Contrast::Utils::ObjectShare::EMPTY_ARRAY
  end
end

#get_property(name) ⇒ Object



63
64
65
66
67
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 63

def get_property name
  return unless @properties

  @properties[name]
end

#node_classObject



30
31
32
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 30

def node_class
  'Node'
end

#node_typeObject



34
35
36
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 34

def node_type
  :TYPE_METHOD
end

#targetObject



38
39
40
41
42
43
44
45
46
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 38

def target
  @_target ||= begin
    if targets&.any?
      targets[0]
    elsif sources&.any?
      sources[0]
    end
  end
end

#validateObject

Don’t let nodes be created that will be missing things we need later on. Really, if they don’t have these things, they couldn’t have done their jobs anyway.



128
129
130
131
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 128

def validate
  super
  validate_tags
end

#validate_tagsObject

TeamServer is picky. The tags here match to ENUMs there. If there isn’t a matching ENUM in TS land, the database gets got. We really don’t want to get them, so we’re going to prevent the node from being made.



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/contrast/agent/assess/policy/policy_node.rb', line 137

def validate_tags
  return unless tags

  tags.each do |tag|
    next if Contrast::Api::Decorators::TraceTaintRangeTags::VALID_TAGS.include?(tag) ||
        Contrast::Api::Decorators::TraceTaintRangeTags::VALID_SOURCE_TAGS.include?(tag)

    raise(ArgumentError,
          "#{ node_class } #{ id } had an invalid tag. #{ tag } is not a known value.")
  end
end