Commit b45205a0 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '347064-database-changes-for-security-policy-in-namespaces' into 'master'

Add namespace to Security Policy Orchestration Configuration

See merge request gitlab-org/gitlab!82013
parents d959694a b77aefa6
# frozen_string_literal: true
class AddSecurityOrchestrationPolicyConfigurationNamespaceReference < Gitlab::Database::Migration[1.0]
def up
add_column :security_orchestration_policy_configurations, :namespace_id, :bigint
end
def down
remove_column :security_orchestration_policy_configurations, :namespace_id
end
end
# frozen_string_literal: true
class AddSecurityOrchestrationPolicyConfigurationNamespaceIndex < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
INDEX_NAME = 'partial_index_sop_configs_on_namespace_id'
def up
add_concurrent_index :security_orchestration_policy_configurations, :namespace_id, unique: true, name: INDEX_NAME, where: 'namespace_id IS NOT NULL'
add_concurrent_foreign_key :security_orchestration_policy_configurations, :namespaces, column: :namespace_id, on_delete: :cascade, reverse_lock_order: true
add_check_constraint :security_orchestration_policy_configurations,
"((project_id IS NULL) != (namespace_id IS NULL))",
:cop_configs_project_or_namespace_existence
end
def down
exec_query 'DELETE FROM security_orchestration_policy_configurations WHERE namespace_id IS NOT NULL'
remove_check_constraint :security_orchestration_policy_configurations, :cop_configs_project_or_namespace_existence
with_lock_retries do
remove_foreign_key_if_exists :security_orchestration_policy_configurations, column: :namespace_id
end
remove_concurrent_index_by_name :security_orchestration_policy_configurations, INDEX_NAME
end
end
# frozen_string_literal: true
class AddNotNullConstraintToSecurityPolicyConfigurations < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
change_column_null :security_orchestration_policy_configurations, :project_id, true
end
def down
exec_query 'DELETE FROM security_orchestration_policy_configurations WHERE project_id IS NULL'
change_column_null :security_orchestration_policy_configurations, :project_id, false
end
end
# frozen_string_literal: true
class ChangeSecurityOrchestrationPolicyConfigurationProjectIndex < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
OLD_INDEX_NAME = 'index_sop_configs_on_project_id'
NEW_INDEX_NAME = 'partial_index_sop_configs_on_project_id'
def up
add_concurrent_index :security_orchestration_policy_configurations, :project_id, unique: true, name: NEW_INDEX_NAME, where: 'project_id IS NOT NULL'
remove_concurrent_index_by_name :security_orchestration_policy_configurations, OLD_INDEX_NAME
end
def down
add_concurrent_index :security_orchestration_policy_configurations, :project_id, unique: true, name: OLD_INDEX_NAME
remove_concurrent_index_by_name :security_orchestration_policy_configurations, NEW_INDEX_NAME
end
end
a19f7f5026fd91cf6f3fcadccd19808920e64005c207b57b46955a0352a68366
\ No newline at end of file
bbca8df8e60c8d027f672dfdee2b0edef35f4fdc3152ae98450df67633f3998f
\ No newline at end of file
4a05ddbc3d2a52a719c6fda8d834611be6f663fbce97b42655a00583d0e2042a
\ No newline at end of file
52e172b1ca6e21a6864e82597a7aae6e1c4776507a475a88807ec140b8648966
\ No newline at end of file
......@@ -20239,11 +20239,13 @@ ALTER SEQUENCE security_findings_id_seq OWNED BY security_findings.id;
CREATE TABLE security_orchestration_policy_configurations (
id bigint NOT NULL,
project_id bigint NOT NULL,
project_id bigint,
security_policy_management_project_id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
configured_at timestamp with time zone
configured_at timestamp with time zone,
namespace_id bigint,
CONSTRAINT cop_configs_project_or_namespace_existence CHECK (((project_id IS NULL) <> (namespace_id IS NULL)))
);
COMMENT ON TABLE security_orchestration_policy_configurations IS '{"owner":"group::container security","description":"Configuration used to store relationship between project and security policy repository"}';
......@@ -29018,8 +29020,6 @@ CREATE INDEX index_software_licenses_on_spdx_identifier ON software_licenses USI
CREATE UNIQUE INDEX index_software_licenses_on_unique_name ON software_licenses USING btree (name);
CREATE UNIQUE INDEX index_sop_configs_on_project_id ON security_orchestration_policy_configurations USING btree (project_id);
CREATE INDEX index_sop_configurations_project_id_policy_project_id ON security_orchestration_policy_configurations USING btree (security_policy_management_project_id, project_id);
CREATE INDEX index_sop_schedules_on_sop_configuration_id ON security_orchestration_policy_rule_schedules USING btree (security_orchestration_policy_configuration_id);
......@@ -29510,6 +29510,10 @@ CREATE INDEX partial_index_deployments_for_legacy_successful_deployments ON depl
CREATE INDEX partial_index_deployments_for_project_id_and_tag ON deployments USING btree (project_id) WHERE (tag IS TRUE);
CREATE UNIQUE INDEX partial_index_sop_configs_on_namespace_id ON security_orchestration_policy_configurations USING btree (namespace_id) WHERE (namespace_id IS NOT NULL);
CREATE UNIQUE INDEX partial_index_sop_configs_on_project_id ON security_orchestration_policy_configurations USING btree (project_id) WHERE (project_id IS NOT NULL);
CREATE UNIQUE INDEX snippet_user_mentions_on_snippet_id_and_note_id_index ON snippet_user_mentions USING btree (snippet_id, note_id);
CREATE UNIQUE INDEX snippet_user_mentions_on_snippet_id_index ON snippet_user_mentions USING btree (snippet_id) WHERE (note_id IS NULL);
......@@ -31409,6 +31413,9 @@ ALTER TABLE ONLY bulk_import_entities
ALTER TABLE ONLY users
ADD CONSTRAINT fk_a4b8fefe3e FOREIGN KEY (managing_group_id) REFERENCES namespaces(id) ON DELETE SET NULL;
ALTER TABLE ONLY security_orchestration_policy_configurations
ADD CONSTRAINT fk_a50430b375 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY lfs_objects_projects
ADD CONSTRAINT fk_a56e02279c FOREIGN KEY (lfs_object_id) REFERENCES lfs_objects(id) ON DELETE RESTRICT NOT VALID;
......@@ -31,6 +31,11 @@ module EE
has_many :ci_minutes_additional_packs, class_name: "Ci::Minutes::AdditionalPack"
has_one :security_orchestration_policy_configuration,
class_name: 'Security::OrchestrationPolicyConfiguration',
foreign_key: :namespace_id,
inverse_of: :namespace
accepts_nested_attributes_for :gitlab_subscription, update_only: true
accepts_nested_attributes_for :namespace_limit
......
......@@ -14,13 +14,18 @@ module Security
POLICY_SCHEMA = JSONSchemer.schema(Rails.root.join(POLICY_SCHEMA_PATH))
AVAILABLE_POLICY_TYPES = %i{scan_execution_policy scan_result_policy}.freeze
belongs_to :project, inverse_of: :security_orchestration_policy_configuration
belongs_to :project, inverse_of: :security_orchestration_policy_configuration, optional: true
belongs_to :namespace, inverse_of: :security_orchestration_policy_configuration, optional: true
belongs_to :security_policy_management_project, class_name: 'Project', foreign_key: 'security_policy_management_project_id'
validates :project, presence: true, uniqueness: true
validates :project, uniqueness: true, if: :project
validates :project, presence: true, unless: :namespace
validates :namespace, uniqueness: true, if: :namespace
validates :namespace, presence: true, unless: :project
validates :security_policy_management_project, presence: true
scope :for_project, -> (project_id) { where(project_id: project_id) }
scope :for_namespace, -> (namespace_id) { where(namespace_id: namespace_id) }
scope :with_outdated_configuration, -> do
joins(:security_policy_management_project)
.where(arel_table[:configured_at].lt(Project.arel_table[:last_repository_updated_at]).or(arel_table[:configured_at].eq(nil)))
......
......@@ -3,6 +3,12 @@
FactoryBot.define do
factory :security_orchestration_policy_configuration, class: 'Security::OrchestrationPolicyConfiguration' do
project
namespace { nil }
security_policy_management_project { association(:project) }
trait :namespace do
project { nil }
namespace
end
end
end
......@@ -16,6 +16,7 @@ RSpec.describe Namespace do
it { is_expected.to have_one(:namespace_limit) }
it { is_expected.to have_one(:elasticsearch_indexed_namespace) }
it { is_expected.to have_one(:security_orchestration_policy_configuration).class_name('Security::OrchestrationPolicyConfiguration').with_foreign_key(:namespace_id) }
it { is_expected.to have_one :upcoming_reconciliation }
it { is_expected.to have_many(:ci_minutes_additional_packs) }
......
......@@ -20,6 +20,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
describe 'associations' do
it { is_expected.to belong_to(:project).inverse_of(:security_orchestration_policy_configuration) }
it { is_expected.to belong_to(:namespace).inverse_of(:security_orchestration_policy_configuration) }
it { is_expected.to belong_to(:security_policy_management_project).class_name('Project') }
it { is_expected.to have_many(:rule_schedules).class_name('Security::OrchestrationPolicyRuleSchedule').inverse_of(:security_orchestration_policy_configuration) }
end
......@@ -27,10 +28,21 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
describe 'validations' do
subject { create(:security_orchestration_policy_configuration) }
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:security_policy_management_project) }
context 'when created for project' do
it { is_expected.not_to validate_presence_of(:namespace) }
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_uniqueness_of(:project) }
end
context 'when created for namespace' do
subject { create(:security_orchestration_policy_configuration, :namespace) }
it { is_expected.to validate_uniqueness_of(:project) }
it { is_expected.not_to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:namespace) }
it { is_expected.to validate_uniqueness_of(:namespace) }
end
it { is_expected.to validate_presence_of(:security_policy_management_project) }
end
describe '.for_project' do
......@@ -45,6 +57,18 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
end
end
describe '.for_namespace' do
let_it_be(:security_orchestration_policy_configuration_1) { create(:security_orchestration_policy_configuration, :namespace) }
let_it_be(:security_orchestration_policy_configuration_2) { create(:security_orchestration_policy_configuration, :namespace) }
let_it_be(:security_orchestration_policy_configuration_3) { create(:security_orchestration_policy_configuration, :namespace) }
subject { described_class.for_namespace([security_orchestration_policy_configuration_2.namespace, security_orchestration_policy_configuration_3.namespace]) }
it 'returns configuration for given namespaces' do
is_expected.to contain_exactly(security_orchestration_policy_configuration_2, security_orchestration_policy_configuration_3)
end
end
describe '.with_outdated_configuration' do
let!(:security_orchestration_policy_configuration_1) { create(:security_orchestration_policy_configuration, configured_at: nil) }
let!(:security_orchestration_policy_configuration_2) { create(:security_orchestration_policy_configuration, configured_at: Time.zone.now - 1.hour) }
......
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