Commit de3e1661 authored by David Fernandez's avatar David Fernandez

Merge branch 'debian_distribution_keys' into 'master'

Debian Group and Project Distribution Keys (schema and model)

See merge request gitlab-org/gitlab!60993
parents c1cc4d45 e915de2c
......@@ -18,6 +18,10 @@ module Packages
belongs_to container_type
belongs_to :creator, class_name: 'User'
has_one :key,
class_name: "Packages::Debian::#{container_type.capitalize}DistributionKey",
foreign_key: :distribution_id,
inverse_of: :distribution
# component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
has_many :components,
class_name: "Packages::Debian::#{container_type.capitalize}Component",
......
# frozen_string_literal: true
module Packages
module Debian
module DistributionKey
extend ActiveSupport::Concern
included do
belongs_to :distribution, class_name: "Packages::Debian::#{container_type.capitalize}Distribution", inverse_of: :key
validates :distribution,
presence: true
validates :private_key, presence: true, length: { maximum: 512.kilobytes }
validates :passphrase, presence: true, length: { maximum: 255 }
validates :public_key, presence: true, length: { maximum: 512.kilobytes }
validates :fingerprint, presence: true, length: { maximum: 255 }
validate :private_key_armored, :public_key_armored
attr_encrypted :private_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm'
attr_encrypted :passphrase,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm'
private
def private_key_armored
if private_key.present? && !private_key.start_with?('-----BEGIN PGP PRIVATE KEY BLOCK-----')
errors.add(:private_key, 'must be ASCII armored')
end
end
def public_key_armored
if public_key.present? && !public_key.start_with?('-----BEGIN PGP PUBLIC KEY BLOCK-----')
errors.add(:public_key, 'must be ASCII armored')
end
end
end
end
end
end
# frozen_string_literal: true
class Packages::Debian::GroupDistributionKey < ApplicationRecord
def self.container_type
:group
end
include Packages::Debian::DistributionKey
end
# frozen_string_literal: true
class Packages::Debian::ProjectDistributionKey < ApplicationRecord
def self.container_type
:project
end
include Packages::Debian::DistributionKey
end
---
title: Debian Group and Project Distribution Keys schema
merge_request: 60993
author: Mathieu Parent
type: added
# frozen_string_literal: true
class CreatePackagesDebianGroupDistributionKeys < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_DISTRIBUTION = 'idx_pkgs_debian_group_distribution_keys_on_distribution_id'
disable_ddl_transaction!
def up
create_table_with_constraints :packages_debian_group_distribution_keys do |t|
t.timestamps_with_timezone
t.references :distribution,
foreign_key: { to_table: :packages_debian_group_distributions, on_delete: :cascade },
index: { name: INDEX_DISTRIBUTION },
null: false
t.text :encrypted_private_key, null: false
t.text :encrypted_private_key_iv, null: false
t.text :encrypted_passphrase, null: false
t.text :encrypted_passphrase_iv, null: false
t.text :public_key, null: false
t.text :fingerprint, null: false
t.text_limit :public_key, 512.kilobytes
t.text_limit :fingerprint, 255
end
end
def down
with_lock_retries do
drop_table :packages_debian_group_distribution_keys
end
end
end
# frozen_string_literal: true
class CreatePackagesDebianProjectDistributionKeys < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_DISTRIBUTION = 'idx_pkgs_debian_project_distribution_keys_on_distribution_id'
disable_ddl_transaction!
def up
create_table_with_constraints :packages_debian_project_distribution_keys do |t|
t.timestamps_with_timezone
t.references :distribution,
foreign_key: { to_table: :packages_debian_project_distributions, on_delete: :cascade },
index: { name: INDEX_DISTRIBUTION },
null: false
t.text :encrypted_private_key, null: false
t.text :encrypted_private_key_iv, null: false
t.text :encrypted_passphrase, null: false
t.text :encrypted_passphrase_iv, null: false
t.text :public_key, null: false
t.text :fingerprint, null: false
t.text_limit :public_key, 512.kilobytes
t.text_limit :fingerprint, 255
end
end
def down
with_lock_retries do
drop_table :packages_debian_project_distribution_keys
end
end
end
52cc795e577a6de524cc55ce8d11f140e5d919f1164bb9983f7dd2c1ef2f0859
\ No newline at end of file
7d57e1fea3652c0c04d29261d3c21b314ed443c9e61b882d22ca7f59807c312b
\ No newline at end of file
......@@ -15537,6 +15537,30 @@ CREATE SEQUENCE packages_debian_group_components_id_seq
ALTER SEQUENCE packages_debian_group_components_id_seq OWNED BY packages_debian_group_components.id;
CREATE TABLE packages_debian_group_distribution_keys (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
distribution_id bigint NOT NULL,
encrypted_private_key text NOT NULL,
encrypted_private_key_iv text NOT NULL,
encrypted_passphrase text NOT NULL,
encrypted_passphrase_iv text NOT NULL,
public_key text NOT NULL,
fingerprint text NOT NULL,
CONSTRAINT check_bc95dc3fbe CHECK ((char_length(fingerprint) <= 255)),
CONSTRAINT check_f708183491 CHECK ((char_length(public_key) <= 524288))
);
CREATE SEQUENCE packages_debian_group_distribution_keys_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE packages_debian_group_distribution_keys_id_seq OWNED BY packages_debian_group_distribution_keys.id;
CREATE TABLE packages_debian_group_distributions (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
......@@ -15639,6 +15663,30 @@ CREATE SEQUENCE packages_debian_project_components_id_seq
ALTER SEQUENCE packages_debian_project_components_id_seq OWNED BY packages_debian_project_components.id;
CREATE TABLE packages_debian_project_distribution_keys (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
distribution_id bigint NOT NULL,
encrypted_private_key text NOT NULL,
encrypted_private_key_iv text NOT NULL,
encrypted_passphrase text NOT NULL,
encrypted_passphrase_iv text NOT NULL,
public_key text NOT NULL,
fingerprint text NOT NULL,
CONSTRAINT check_9e8a5eef0a CHECK ((char_length(fingerprint) <= 255)),
CONSTRAINT check_d188f6547f CHECK ((char_length(public_key) <= 524288))
);
CREATE SEQUENCE packages_debian_project_distribution_keys_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE packages_debian_project_distribution_keys_id_seq OWNED BY packages_debian_project_distribution_keys.id;
CREATE TABLE packages_debian_project_distributions (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
......@@ -19950,6 +19998,8 @@ ALTER TABLE ONLY packages_debian_group_component_files ALTER COLUMN id SET DEFAU
ALTER TABLE ONLY packages_debian_group_components ALTER COLUMN id SET DEFAULT nextval('packages_debian_group_components_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_group_distribution_keys ALTER COLUMN id SET DEFAULT nextval('packages_debian_group_distribution_keys_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_group_distributions ALTER COLUMN id SET DEFAULT nextval('packages_debian_group_distributions_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_project_architectures ALTER COLUMN id SET DEFAULT nextval('packages_debian_project_architectures_id_seq'::regclass);
......@@ -19958,6 +20008,8 @@ ALTER TABLE ONLY packages_debian_project_component_files ALTER COLUMN id SET DEF
ALTER TABLE ONLY packages_debian_project_components ALTER COLUMN id SET DEFAULT nextval('packages_debian_project_components_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_project_distribution_keys ALTER COLUMN id SET DEFAULT nextval('packages_debian_project_distribution_keys_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_project_distributions ALTER COLUMN id SET DEFAULT nextval('packages_debian_project_distributions_id_seq'::regclass);
ALTER TABLE ONLY packages_debian_publications ALTER COLUMN id SET DEFAULT nextval('packages_debian_publications_id_seq'::regclass);
......@@ -21422,6 +21474,9 @@ ALTER TABLE ONLY packages_debian_group_component_files
ALTER TABLE ONLY packages_debian_group_components
ADD CONSTRAINT packages_debian_group_components_pkey PRIMARY KEY (id);
ALTER TABLE ONLY packages_debian_group_distribution_keys
ADD CONSTRAINT packages_debian_group_distribution_keys_pkey PRIMARY KEY (id);
ALTER TABLE ONLY packages_debian_group_distributions
ADD CONSTRAINT packages_debian_group_distributions_pkey PRIMARY KEY (id);
......@@ -21434,6 +21489,9 @@ ALTER TABLE ONLY packages_debian_project_component_files
ALTER TABLE ONLY packages_debian_project_components
ADD CONSTRAINT packages_debian_project_components_pkey PRIMARY KEY (id);
ALTER TABLE ONLY packages_debian_project_distribution_keys
ADD CONSTRAINT packages_debian_project_distribution_keys_pkey PRIMARY KEY (id);
ALTER TABLE ONLY packages_debian_project_distributions
ADD CONSTRAINT packages_debian_project_distributions_pkey PRIMARY KEY (id);
......@@ -22211,6 +22269,10 @@ CREATE INDEX idx_packages_debian_project_component_files_on_architecture_id ON p
CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON packages_packages USING btree (project_id, name, version, package_type);
CREATE INDEX idx_pkgs_debian_group_distribution_keys_on_distribution_id ON packages_debian_group_distribution_keys USING btree (distribution_id);
CREATE INDEX idx_pkgs_debian_project_distribution_keys_on_distribution_id ON packages_debian_project_distribution_keys USING btree (distribution_id);
CREATE UNIQUE INDEX idx_pkgs_dep_links_on_pkg_id_dependency_id_dependency_type ON packages_dependency_links USING btree (package_id, dependency_id, dependency_type);
CREATE INDEX idx_proj_feat_usg_on_jira_dvcs_cloud_last_sync_at_and_proj_id ON project_feature_usages USING btree (jira_dvcs_cloud_last_sync_at, project_id) WHERE (jira_dvcs_cloud_last_sync_at IS NOT NULL);
......@@ -26271,6 +26333,9 @@ ALTER TABLE ONLY group_merge_request_approval_settings
ALTER TABLE ONLY analytics_cycle_analytics_project_stages
ADD CONSTRAINT fk_rails_3829e49b66 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY packages_debian_project_distribution_keys
ADD CONSTRAINT fk_rails_3834a11264 FOREIGN KEY (distribution_id) REFERENCES packages_debian_project_distributions(id) ON DELETE CASCADE;
ALTER TABLE ONLY issue_user_mentions
ADD CONSTRAINT fk_rails_3861d9fefa FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
......@@ -26679,6 +26744,9 @@ ALTER TABLE ONLY packages_debian_publications
ALTER TABLE ONLY boards_epic_user_preferences
ADD CONSTRAINT fk_rails_76c4e9732d FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE;
ALTER TABLE ONLY packages_debian_group_distribution_keys
ADD CONSTRAINT fk_rails_779438f163 FOREIGN KEY (distribution_id) REFERENCES packages_debian_group_distributions(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_subscriptions_projects
ADD CONSTRAINT fk_rails_7871f9a97b FOREIGN KEY (upstream_project_id) REFERENCES projects(id) ON DELETE CASCADE;
# frozen_string_literal: true
FactoryBot.define do
factory :debian_project_distribution_key, class: 'Packages::Debian::ProjectDistributionKey' do
distribution { association(:debian_project_distribution) }
private_key { '-----BEGIN PGP PRIVATE KEY BLOCK-----' }
passphrase { '12345' }
public_key { '-----BEGIN PGP PUBLIC KEY BLOCK-----' }
fingerprint { '12345' }
factory :debian_group_distribution_key, class: 'Packages::Debian::GroupDistributionKey' do
distribution { association(:debian_group_distribution) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Debian::GroupDistributionKey do
it_behaves_like 'Debian Distribution Key', :group
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Debian::ProjectDistributionKey do
it_behaves_like 'Debian Distribution Key', :project
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.shared_examples 'Debian Distribution Key' do |container|
let_it_be_with_refind(:distribution_key) { create("debian_#{container}_distribution_key") } # rubocop:disable Rails/SaveBang
subject { distribution_key }
describe 'relationships' do
it { is_expected.to belong_to(:distribution).class_name("Packages::Debian::#{container.capitalize}Distribution").inverse_of(:key) }
end
describe 'validations' do
describe "#distribution" do
it { is_expected.to validate_presence_of(:distribution) }
end
describe '#private_key' do
it { is_expected.to validate_presence_of(:private_key) }
it { is_expected.to allow_value("-----BEGIN PGP PRIVATE KEY BLOCK-----\n...").for(:private_key) }
it { is_expected.not_to allow_value('A').for(:private_key).with_message('must be ASCII armored') }
end
describe '#passphrase' do
it { is_expected.to validate_presence_of(:passphrase) }
it { is_expected.to allow_value('P@$$w0rd').for(:passphrase) }
it { is_expected.to allow_value('A' * 255).for(:passphrase) }
it { is_expected.not_to allow_value('A' * 256).for(:passphrase) }
end
describe '#public_key' do
it { is_expected.to validate_presence_of(:public_key) }
it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\n...").for(:public_key) }
it { is_expected.not_to allow_value('A').for(:public_key).with_message('must be ASCII armored') }
end
describe '#fingerprint' do
it { is_expected.to validate_presence_of(:passphrase) }
it { is_expected.to allow_value('abc').for(:passphrase) }
it { is_expected.to allow_value('A' * 255).for(:passphrase) }
it { is_expected.not_to allow_value('A' * 256).for(:passphrase) }
end
end
end
......@@ -17,6 +17,7 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
it { is_expected.to belong_to(container) }
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to have_one(:key).class_name("Packages::Debian::#{container.capitalize}DistributionKey").with_foreign_key(:distribution_id).inverse_of(:distribution) }
it { is_expected.to have_many(:components).class_name("Packages::Debian::#{container.capitalize}Component").inverse_of(:distribution) }
it { is_expected.to have_many(:architectures).class_name("Packages::Debian::#{container.capitalize}Architecture").inverse_of(:distribution) }
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