# frozen_string_literal: true # AttributesPermitter builds a hash of permitted attributes for # every model defined in import_export.yml that is used to validate and # filter out any attributes that are not permitted when doing Project/Group Import # # Each model's list includes: # - attributes defined under included_attributes section # - associations defined under project/group tree # - methods defined under methods section # # Given the following import_export.yml example: # ``` # tree: # project: # - labels: # - :priorities # included_attributes: # labels: # - :title # - :description # methods: # labels: # - :type # ``` # # Produces a list of permitted attributes: # ``` # Gitlab::ImportExport::AttributesPermitter.new.permitted_attributes # # => { labels: [:priorities, :title, :description, :type] } # ``` # # Filters out any other attributes from specific relation hash: # ``` # Gitlab::ImportExport::AttributesPermitter.new.permit(:labels, {id: 5, type: 'opened', description: 'test', sensitive_attribute: 'my_sensitive_attribute'}) # # => {:type=>"opened", :description=>"test"} # ``` module Gitlab module ImportExport class AttributesPermitter attr_reader :permitted_attributes def initialize(config: ImportExport::Config.new.to_h) @config = config @attributes_finder = Gitlab::ImportExport::AttributesFinder.new(config: @config) @permitted_attributes = {} build_permitted_attributes end def permit(relation_name, relation_hash) permitted_attributes = permitted_attributes_for(relation_name) relation_hash.select do |key, _| permitted_attributes.include?(key) end end def permitted_attributes_for(relation_name) @permitted_attributes[relation_name] || [] end private def build_permitted_attributes build_associations build_attributes build_methods end # Deep traverse relations tree to build a list of allowed model relations def build_associations stack = @attributes_finder.tree.to_a while stack.any? model_name, relations = stack.pop if relations.is_a?(Hash) add_permitted_attributes(model_name, relations.keys) stack.concat(relations.to_a) end end @permitted_attributes end def build_attributes @attributes_finder.included_attributes.each(&method(:add_permitted_attributes)) end def build_methods @attributes_finder.methods.each(&method(:add_permitted_attributes)) end def add_permitted_attributes(model_name, attributes) @permitted_attributes[model_name] ||= [] @permitted_attributes[model_name].concat(attributes) if attributes.any? end end end end