# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Agent module Patching module Policy # This class functions to translate our policy.json into an actionable # Ruby object, allowing for dynamic patching over hardcoded patching. # # @abstract class PolicyNode attr_accessor :class_name, :instance_method, :method_name, :method_visibility attr_reader :properties def node_class raise NotImplementedError, 'specify the type of the feature for which this node patches' end def feature raise NotImplementedError, 'specify the name of the feature for which this node patches' end def initialize policy_hash = {} @class_name = policy_hash[JSON_CLASS_NAME] @instance_method = policy_hash[JSON_INSTANCE_METHOD] @method_name = policy_hash[JSON_METHOD_NAME] @method_visibility = policy_hash[JSON_METHOD_VISIBILITY] @properties = policy_hash[JSON_PROPERTIES] symbolize end def id @_id ||= "#{ feature }:#{ node_class }:#{ class_name }#{ instance_method? ? '#' : '.' }#{ method_name }" end # 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. def validate raise(ArgumentError, "#{ node_class } #{ id } did not have a proper class name. Unable to create.") unless class_name raise(ArgumentError, "#{ node_class } #{ id } did not have a proper method name. Unable to create.") unless method_name raise(ArgumentError, "#{ node_class } #{ id } has a non symbol @method_name value. Unable to create.") unless method_name.is_a?(Symbol) raise(ArgumentError, "#{ node_class } #{ id } has a non symbol @method_visibility value. Unable to create.") unless method_visibility.is_a?(Symbol) end # just turns this into a ruby-ism def instance_method? instance_method end def private? @method_visibility == :private end def public? @method_visibility == :public end private # Convert strings to symbols here, once, to avoid doing so on every # comparison at runtime def symbolize @method_name = @method_name.to_sym if @method_name @method_visibility = @method_visibility.to_sym if @method_visibility end # The keys used to read from policy.json to create the individual # policy nodes. These are common across node types JSON_CLASS_NAME = 'class_name' JSON_INSTANCE_METHOD = 'instance_method' JSON_METHOD_NAME = 'method_name' JSON_METHOD_VISIBILITY = 'method_visibility' JSON_PROPERTIES = 'properties' end end end end end