Commit 11c8ca07 authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Etienne Baqué

Use allowlist of allowed attributes for imported models (part 2)

parent 74732bee
...@@ -132,4 +132,23 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do ...@@ -132,4 +132,23 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
expect(project.push_rule.deny_delete_tag).to be_truthy expect(project.push_rule.deny_delete_tag).to be_truthy
end end
end end
describe 'boards' do
let_it_be(:project) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
let(:user) { create(:user) }
before do
setup_import_export_config('complex')
restored_project_json
end
it 'has milestone associated with the issue board' do
expect(Project.find_by_path('project').boards.find_by_name('TestBoardABC').milestone.name).to eq('test milestone')
end
it 'has milestone associated with the issue board list' do
expect(Project.find_by_path('project').boards.find_by_name('TestBoardABC').lists.first.milestone.name).to eq('test milestone')
end
end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::AttributesPermitter do
describe '#permitted_attributes_defined?' do
using RSpec::Parameterized::TableSyntax
let(:attributes_permitter) { described_class.new }
where(:relation_name, :permitted_attributes_defined) do
:push_rule | true
:issuable_sla | false
end
with_them do
it { expect(attributes_permitter.permitted_attributes_defined?(relation_name)).to eq(permitted_attributes_defined) }
end
end
describe 'included_attributes for Project' do
let(:prohibited_attributes) { %i[remote_url my_attributes my_ids token my_id test] }
subject { described_class.new }
Gitlab::ImportExport::Config.new.to_h[:included_attributes].each do |relation_sym, permitted_attributes|
context "for #{relation_sym}" do
it_behaves_like 'a permitted attribute', relation_sym, permitted_attributes
end
end
end
end
...@@ -44,7 +44,7 @@ module Gitlab ...@@ -44,7 +44,7 @@ module Gitlab
# We want to use AttributesCleaner for these relations instead, in the future this should be removed to make sure # We want to use AttributesCleaner for these relations instead, in the future this should be removed to make sure
# we are using AttributesPermitter for every imported relation. # we are using AttributesPermitter for every imported relation.
DISABLED_RELATION_NAMES = %i[user author ci_cd_settings issuable_sla push_rule].freeze DISABLED_RELATION_NAMES = %i[user author issuable_sla].freeze
def initialize(config: ImportExport::Config.new.to_h) def initialize(config: ImportExport::Config.new.to_h)
@config = config @config = config
......
...@@ -183,7 +183,7 @@ module Gitlab ...@@ -183,7 +183,7 @@ module Gitlab
def parsed_relation_hash def parsed_relation_hash
strong_memoize(:parsed_relation_hash) do strong_memoize(:parsed_relation_hash) do
if Feature.enabled?(:permitted_attributes_for_import_export, default_enabled: :yaml) && attributes_permitter.permitted_attributes_defined?(@relation_sym) if use_attributes_permitter? && attributes_permitter.permitted_attributes_defined?(@relation_sym)
attributes_permitter.permit(@relation_sym, @relation_hash) attributes_permitter.permit(@relation_sym, @relation_hash)
else else
Gitlab::ImportExport::AttributeCleaner.clean(relation_hash: @relation_hash, relation_class: relation_class) Gitlab::ImportExport::AttributeCleaner.clean(relation_hash: @relation_hash, relation_class: relation_class)
...@@ -195,6 +195,10 @@ module Gitlab ...@@ -195,6 +195,10 @@ module Gitlab
@attributes_permitter ||= Gitlab::ImportExport::AttributesPermitter.new @attributes_permitter ||= Gitlab::ImportExport::AttributesPermitter.new
end end
def use_attributes_permitter?
Feature.enabled?(:permitted_attributes_for_import_export, default_enabled: :yaml)
end
def existing_or_new_object def existing_or_new_object
# Only find existing records to avoid mapping tables such as milestones # Only find existing records to avoid mapping tables such as milestones
# Otherwise always create the record, skipping the extra SELECT clause. # Otherwise always create the record, skipping the extra SELECT clause.
......
...@@ -10,6 +10,7 @@ tree: ...@@ -10,6 +10,7 @@ tree:
- labels: - labels:
- :priorities - :priorities
- boards: - boards:
- :milestone
- lists: - lists:
- label: - label:
- :priorities - :priorities
......
...@@ -36,6 +36,10 @@ module Gitlab ...@@ -36,6 +36,10 @@ module Gitlab
@relation_hash['group_id'] = @importable.id @relation_hash['group_id'] = @importable.id
end end
def use_attributes_permitter?
false
end
end end
end end
end end
......
...@@ -131,7 +131,6 @@ included_attributes: ...@@ -131,7 +131,6 @@ included_attributes:
- :link_url - :link_url
- :name - :name
- :project_id - :project_id
- :type
- :updated_at - :updated_at
pipeline_schedules: pipeline_schedules:
- :active - :active
...@@ -155,6 +154,77 @@ included_attributes: ...@@ -155,6 +154,77 @@ included_attributes:
- :enabled - :enabled
- :project_id - :project_id
- :updated_at - :updated_at
boards:
- :project_id
- :created_at
- :updated_at
- :group_id
- :weight
- :name
- :hide_backlog_list
- :hide_closed_list
lists:
- :list_type
- :position
- :created_at
- :updated_at
- :user_id
- :max_issue_count
- :max_issue_weight
- :limit_metric
custom_attributes:
- :created_at
- :updated_at
- :project_id
- :key
- :value
label:
- :title
- :color
- :project_id
- :group_id
- :created_at
- :updated_at
- :template
- :description
- :priority
labels:
- :title
- :color
- :project_id
- :group_id
- :created_at
- :updated_at
- :template
- :description
- :priority
priorities:
- :project_id
- :priority
- :created_at
- :updated_at
milestone:
- :iid
- :title
- :project_id
- :group_id
- :description
- :due_date
- :created_at
- :updated_at
- :start_date
- :state
milestones:
- :iid
- :title
- :project_id
- :group_id
- :description
- :due_date
- :created_at
- :updated_at
- :start_date
- :state
# Do not include the following attributes for the models specified. # Do not include the following attributes for the models specified.
excluded_attributes: excluded_attributes:
...@@ -498,6 +568,10 @@ ee: ...@@ -498,6 +568,10 @@ ee:
- :deploy_access_levels - :deploy_access_levels
- :security_setting - :security_setting
- :push_rule - :push_rule
- boards:
- :milestone
- lists:
- :milestone
included_attributes: included_attributes:
issuable_sla: issuable_sla:
......
...@@ -7759,7 +7759,29 @@ ...@@ -7759,7 +7759,29 @@
"created_at": "2019-06-06T14:01:06.204Z", "created_at": "2019-06-06T14:01:06.204Z",
"updated_at": "2019-06-06T14:22:37.045Z", "updated_at": "2019-06-06T14:22:37.045Z",
"name": "TestBoardABC", "name": "TestBoardABC",
"milestone_id": null, "milestone": {
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
},
"group_id": null, "group_id": null,
"weight": null, "weight": null,
"lists": [ "lists": [
...@@ -7772,7 +7794,29 @@ ...@@ -7772,7 +7794,29 @@
"created_at": "2019-06-06T14:01:06.214Z", "created_at": "2019-06-06T14:01:06.214Z",
"updated_at": "2019-06-06T14:01:06.214Z", "updated_at": "2019-06-06T14:01:06.214Z",
"user_id": null, "user_id": null,
"milestone_id": null "milestone": {
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
}
}, },
{ {
"id": 61, "id": 61,
...@@ -7783,7 +7827,29 @@ ...@@ -7783,7 +7827,29 @@
"created_at": "2019-06-06T14:01:43.197Z", "created_at": "2019-06-06T14:01:43.197Z",
"updated_at": "2019-06-06T14:01:43.197Z", "updated_at": "2019-06-06T14:01:43.197Z",
"user_id": null, "user_id": null,
"milestone_id": null, "milestone": {
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
},
"label": { "label": {
"id": 20, "id": 20,
"title": "testlabel", "title": "testlabel",
...@@ -7807,7 +7873,29 @@ ...@@ -7807,7 +7873,29 @@
"created_at": "2019-06-06T14:01:06.221Z", "created_at": "2019-06-06T14:01:06.221Z",
"updated_at": "2019-06-06T14:01:06.221Z", "updated_at": "2019-06-06T14:01:06.221Z",
"user_id": null, "user_id": null,
"milestone_id": null "milestone": {
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
}
} }
] ]
} }
......
{"id":29,"project_id":49,"created_at":"2019-06-06T14:01:06.204Z","updated_at":"2019-06-06T14:22:37.045Z","name":"TestBoardABC","milestone_id":null,"group_id":null,"weight":null,"lists":[{"id":59,"board_id":29,"label_id":null,"list_type":"backlog","position":null,"created_at":"2019-06-06T14:01:06.214Z","updated_at":"2019-06-06T14:01:06.214Z","user_id":null,"milestone_id":null},{"id":61,"board_id":29,"label_id":20,"list_type":"label","position":0,"created_at":"2019-06-06T14:01:43.197Z","updated_at":"2019-06-06T14:01:43.197Z","user_id":null,"milestone_id":null,"label":{"id":20,"title":"testlabel","color":"#0033CC","project_id":49,"created_at":"2019-06-06T14:01:19.698Z","updated_at":"2019-06-06T14:01:19.698Z","template":false,"description":null,"group_id":null,"type":"ProjectLabel","priorities":[]}},{"id":60,"board_id":29,"label_id":null,"list_type":"closed","position":null,"created_at":"2019-06-06T14:01:06.221Z","updated_at":"2019-06-06T14:01:06.221Z","user_id":null,"milestone_id":null}]} {"id":29,"project_id":49,"created_at":"2019-06-06T14:01:06.204Z","updated_at":"2019-06-06T14:22:37.045Z","name":"TestBoardABC","group_id":null,"weight":null,"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]},"lists":[{"id":59,"board_id":29,"label_id":null,"list_type":"backlog","position":null,"created_at":"2019-06-06T14:01:06.214Z","updated_at":"2019-06-06T14:01:06.214Z","user_id":null,"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]}},{"id":61,"board_id":29,"label_id":20,"list_type":"label","position":0,"created_at":"2019-06-06T14:01:43.197Z","updated_at":"2019-06-06T14:01:43.197Z","user_id":null,"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]},"label":{"id":20,"title":"testlabel","color":"#0033CC","project_id":49,"created_at":"2019-06-06T14:01:19.698Z","updated_at":"2019-06-06T14:01:19.698Z","template":false,"description":null,"group_id":null,"type":"ProjectLabel","priorities":[]}},{"id":60,"board_id":29,"label_id":null,"list_type":"closed","position":null,"created_at":"2019-06-06T14:01:06.221Z","updated_at":"2019-06-06T14:01:06.221Z","user_id":null,"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]}}]}
...@@ -83,14 +83,15 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do ...@@ -83,14 +83,15 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
where(:relation_name, :permitted_attributes_defined) do where(:relation_name, :permitted_attributes_defined) do
:user | false :user | false
:author | false :author | false
:ci_cd_settings | false :ci_cd_settings | true
:issuable_sla | false
:push_rule | false
:metrics_setting | true :metrics_setting | true
:project_badges | true :project_badges | true
:pipeline_schedules | true :pipeline_schedules | true
:error_tracking_setting | true :error_tracking_setting | true
:auto_devops | true :auto_devops | true
:boards | true
:custom_attributes | true
:labels | true
end end
with_them do with_them do
...@@ -99,47 +100,11 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do ...@@ -99,47 +100,11 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
end end
describe 'included_attributes for Project' do describe 'included_attributes for Project' do
let(:prohibited_attributes) { %i[remote_url my_attributes my_ids token my_id test] }
subject { described_class.new } subject { described_class.new }
Gitlab::ImportExport::Config.new.to_h[:included_attributes].each do |relation_sym, permitted_attributes| Gitlab::ImportExport::Config.new.to_h[:included_attributes].each do |relation_sym, permitted_attributes|
context "for #{relation_sym}" do context "for #{relation_sym}" do
let(:import_export_config) { Gitlab::ImportExport::Config.new.to_h } it_behaves_like 'a permitted attribute', relation_sym, permitted_attributes
let(:project_relation_factory) { Gitlab::ImportExport::Project::RelationFactory }
let(:relation_hash) { (permitted_attributes + prohibited_attributes).map(&:to_s).zip([]).to_h }
let(:relation_name) { project_relation_factory.overrides[relation_sym]&.to_sym || relation_sym }
let(:relation_class) { project_relation_factory.relation_class(relation_name) }
let(:excluded_keys) { import_export_config.dig(:excluded_keys, relation_sym) || [] }
let(:cleaned_hash) do
Gitlab::ImportExport::AttributeCleaner.new(
relation_hash: relation_hash,
relation_class: relation_class,
excluded_keys: excluded_keys
).clean
end
let(:permitted_hash) { subject.permit(relation_sym, relation_hash) }
if described_class.new.permitted_attributes_defined?(relation_sym)
it 'contains only attributes that are defined as permitted in the import/export config' do
expect(permitted_hash.keys).to contain_exactly(*permitted_attributes.map(&:to_s))
end
it 'does not contain attributes that would be cleaned with AttributeCleaner' do
expect(cleaned_hash.keys).to include(*permitted_hash.keys)
end
it 'does not contain prohibited attributes that are not related to given relation' do
expect(permitted_hash.keys).not_to include(*prohibited_attributes.map(&:to_s))
end
else
it 'is disabled' do
expect(subject).not_to be_permitted_attributes_defined(relation_sym)
end
end
end end
end end
end end
......
# frozen_string_literal: true
RSpec.shared_examples 'a permitted attribute' do |relation_sym, permitted_attributes|
let(:prohibited_attributes) { %i[remote_url my_attributes my_ids token my_id test] }
let(:import_export_config) { Gitlab::ImportExport::Config.new.to_h }
let(:project_relation_factory) { Gitlab::ImportExport::Project::RelationFactory }
let(:relation_hash) { (permitted_attributes + prohibited_attributes).map(&:to_s).zip([]).to_h }
let(:relation_name) { project_relation_factory.overrides[relation_sym]&.to_sym || relation_sym }
let(:relation_class) { project_relation_factory.relation_class(relation_name) }
let(:excluded_keys) { import_export_config.dig(:excluded_keys, relation_sym) || [] }
let(:cleaned_hash) do
Gitlab::ImportExport::AttributeCleaner.new(
relation_hash: relation_hash,
relation_class: relation_class,
excluded_keys: excluded_keys
).clean
end
let(:permitted_hash) { subject.permit(relation_sym, relation_hash) }
if described_class.new.permitted_attributes_defined?(relation_sym)
it 'contains only attributes that are defined as permitted in the import/export config' do
expect(permitted_hash.keys).to contain_exactly(*permitted_attributes.map(&:to_s))
end
it 'does not contain attributes that would be cleaned with AttributeCleaner' do
expect(cleaned_hash.keys).to include(*permitted_hash.keys)
end
it 'does not contain prohibited attributes that are not related to given relation' do
expect(permitted_hash.keys).not_to include(*prohibited_attributes.map(&:to_s))
end
else
it 'is disabled' do
expect(subject).not_to be_permitted_attributes_defined(relation_sym)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment