diff options
Diffstat (limited to 'lib/gitlab/import_export/attributes_permitter.rb')
-rw-r--r-- | lib/gitlab/import_export/attributes_permitter.rb | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/gitlab/import_export/attributes_permitter.rb b/lib/gitlab/import_export/attributes_permitter.rb new file mode 100644 index 00000000000..86f51add504 --- /dev/null +++ b/lib/gitlab/import_export/attributes_permitter.rb @@ -0,0 +1,105 @@ +# 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 |