Class: Contrast::Agent::Patching::Policy::Policy Abstract

Inherits:
Object
  • Object
show all
Includes:
Components::Logger::InstanceMethods, Singleton
Defined in:
lib/contrast/agent/patching/policy/policy.rb

Overview

This class is abstract.

This is just a holder for our policy. Takes the policy JSON and converts it into hashes that we can access nicely.

Constant Summary collapse

SOURCES_KEY =
'sources'
PROPAGATION_KEY =
'propagators'
RULES_KEY =
'rules'
TRIGGERS_KEY =
'triggers'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Components::Logger::InstanceMethods

#cef_logger, #logger

Constructor Details

#initializePolicy

Returns a new instance of Policy.



27
28
29
30
31
32
33
34
35
# File 'lib/contrast/agent/patching/policy/policy.rb', line 27

def initialize
  @sources = []
  @propagators = []
  @triggers = []
  @providers = {}

  json = Contrast::Utils::ResourceLoader.load(cs__class.policy_json)
  from_hash_string(json)
end

Instance Attribute Details

#propagatorsObject (readonly)

Returns the value of attribute propagators.



57
58
59
# File 'lib/contrast/agent/patching/policy/policy.rb', line 57

def propagators
  @propagators
end

#providersObject (readonly)

Returns the value of attribute providers.



57
58
59
# File 'lib/contrast/agent/patching/policy/policy.rb', line 57

def providers
  @providers
end

#sourcesObject (readonly)

Returns the value of attribute sources.



57
58
59
# File 'lib/contrast/agent/patching/policy/policy.rb', line 57

def sources
  @sources
end

#triggersObject (readonly)

Returns the value of attribute triggers.



57
58
59
# File 'lib/contrast/agent/patching/policy/policy.rb', line 57

def triggers
  @triggers
end

Class Method Details

.policy_folderObject

Indicates the folder in ‘resources` where this policy lives.

@raise raises if any of the subclasses, extending this class is not implementing this method

Raises:

  • (NoMethodError)


40
41
42
# File 'lib/contrast/agent/patching/policy/policy.rb', line 40

def self.policy_folder
  raise(NoMethodError, 'specify policy_folder for patching')
end

.policy_jsonObject



59
60
61
# File 'lib/contrast/agent/patching/policy/policy.rb', line 59

def self.policy_json
  File.join(policy_folder, 'policy.json').cs__freeze
end

Instance Method Details

#add_node(node, node_type = :trigger) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/contrast/agent/patching/policy/policy.rb', line 84

def add_node node, node_type = :trigger
  unless node
    logger.error('Node was nil when adding node to policy')
    return
  end

  begin
    node.validate
  rescue ArgumentError => e
    logger.error('Node failed validation', e)
    return
  end

  case node_type
  when :source
    @sources << node
  when :propagator
    @propagators << node
  when :trigger
    @triggers << node
  when :dynamic_source
    module_names << node.class_name
    @sources << node
  else
    logger.error('Invalid node_type provided when adding node to policy', node_type: node_type)
  end
end

#disabled_globally?Boolean

Indicates is this feature has been disabled by the configuration, read at startup, and therefore can never be enabled.

@raise raises if any of the subclasses, extending this class is not implementing this method

Returns:

  • (Boolean)

Raises:

  • (NoMethodError)


48
49
50
# File 'lib/contrast/agent/patching/policy/policy.rb', line 48

def disabled_globally?
  raise(NoMethodError, 'specify disabled_globally? conditions for patching')
end

#find_node(rule_id, class_name, method_name, instance_method) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/contrast/agent/patching/policy/policy.rb', line 136

def find_node rule_id, class_name, method_name, instance_method
  find_triggers_by_rule(rule_id).find do |node|
    node.class_name == class_name &&
        node.method_name == method_name &&
        node.instance_method == instance_method
  end
end

#find_propagator_node(class_name, method_name, instance_method) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/contrast/agent/patching/policy/policy.rb', line 128

def find_propagator_node class_name, method_name, instance_method
  propagators.find do |propagator|
    propagator.class_name == class_name &&
        propagator.method_name == method_name &&
        propagator.instance_method == instance_method
  end
end

#find_source_node(class_name, method_name, instance_method) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/contrast/agent/patching/policy/policy.rb', line 120

def find_source_node class_name, method_name, instance_method
  sources.find do |source|
    source.class_name == class_name &&
        source.method_name == method_name &&
        source.instance_method == instance_method
  end
end

#find_triggers_by_rule(rule_id) ⇒ Object



116
117
118
# File 'lib/contrast/agent/patching/policy/policy.rb', line 116

def find_triggers_by_rule rule_id
  triggers.select { |trigger| trigger.rule_id == rule_id }
end

#from_hash_string(string) ⇒ Object

Our policy for patching rules is a ‘dope ass’ JSON file. Rather than hard code in a bunch of things to monkey patch, we let the JSON file define the conditions in which modifications are applied. This let’s us be flexible and extensible.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/contrast/agent/patching/policy/policy.rb', line 66

def from_hash_string string
  # The default behavior of the agent is to load the policy on startup, as at this point we do not know in
  # which mode we'll be run.
  #
  # If the configuration file explicitly disables a feature, we know that we will not ever be able to enable
  # it, so in that case, we can skip policy loading.
  return if disabled_globally?

  policy_data = Contrast::Utils::Json.parse(string)

  policy_data[RULES_KEY].each do |rule_hash|
    rule_hash[TRIGGERS_KEY].each do |trigger_hash|
      trigger_node = node_type.new(trigger_hash, rule_hash)
      add_node(trigger_node)
    end
  end
end

#module_namesObject



112
113
114
# File 'lib/contrast/agent/patching/policy/policy.rb', line 112

def module_names
  @_module_names ||= Set.new([sources, propagators, triggers].flatten.map!(&:class_name))
end

#node_typeObject

@raise raises if any of the subclasses, extending this class is not implementing this method

Raises:

  • (NoMethodError)


53
54
55
# File 'lib/contrast/agent/patching/policy/policy.rb', line 53

def node_type
  raise(NoMethodError, 'specify the concrete node type for this poilcy')
end