1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# frozen_string_literal: true
module Packages
module Debian
module Distribution
extend ActiveSupport::Concern
included do
include FileStoreMounter
def self.container_foreign_key
"#{container_type}_id".to_sym
end
alias_attribute :container, container_type
alias_attribute :container_id, "#{container_type}_id"
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",
foreign_key: :distribution_id,
inverse_of: :distribution,
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :component_files,
through: :components,
source: :files,
class_name: "Packages::Debian::#{container_type.capitalize}ComponentFile"
has_many :architectures,
class_name: "Packages::Debian::#{container_type.capitalize}Architecture",
foreign_key: :distribution_id,
inverse_of: :distribution
validates :codename,
presence: true,
uniqueness: { scope: [container_foreign_key] },
format: { with: Gitlab::Regex.debian_distribution_regex }
validates :suite,
allow_nil: true,
format: { with: Gitlab::Regex.debian_distribution_regex }
validates :suite,
uniqueness: { scope: [container_foreign_key] },
if: :suite
validate :unique_codename_and_suite
validates :origin,
allow_nil: true,
format: { with: Gitlab::Regex.debian_distribution_regex }
validates :label,
allow_nil: true,
format: { with: Gitlab::Regex.debian_distribution_regex }
validates :version,
allow_nil: true,
format: { with: Gitlab::Regex.debian_version_regex }
# The Valid-Until field is a security measure to prevent malicious attackers to
# serve an outdated repository, with vulnerable packages
# (keeping in mind that most Debian repository are not using TLS but use GPG
# signatures instead).
# A minimum of 24 hours is simply to avoid generating indices too often
# (which generates load).
# Official Debian repositories are generated 4 times a day, and valid for 7 days.
# Full ref: https://wiki.debian.org/DebianRepository/Format#Date.2C_Valid-Until
validates :valid_time_duration_seconds,
allow_nil: true,
numericality: { greater_than_or_equal_to: 24.hours.to_i }
validates container_type, presence: true
validates :file_store, presence: true
validates :signed_file_store, presence: true
scope :with_container, ->(subject) { where(container_type => subject) }
scope :with_codename, ->(codename) { where(codename: codename) }
scope :with_suite, ->(suite) { where(suite: suite) }
scope :with_codename_or_suite, ->(codename_or_suite) { with_codename(codename_or_suite).or(with_suite(codename_or_suite)) }
mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader
mount_uploader :signed_file, Packages::Debian::DistributionReleaseFileUploader
after_save :update_signed_file_store, if: :saved_change_to_signed_file?
def component_names
components.pluck(:name).sort
end
def architecture_names
architectures.pluck(:name).sort
end
def package_files
if Feature.enabled?(:packages_installable_package_files, default_enabled: :yaml)
::Packages::PackageFile.installable
.for_package_ids(packages.select(:id))
else
::Packages::PackageFile.for_package_ids(packages.select(:id))
end
end
private
def unique_codename_and_suite
errors.add(:codename, _('has already been taken as Suite')) if codename_exists_as_suite?
errors.add(:suite, _('has already been taken as Codename')) if suite_exists_as_codename?
end
def codename_exists_as_suite?
return false unless codename.present?
self.class.with_container(container).with_suite(codename).exists?
end
def suite_exists_as_codename?
return false unless suite.present?
self.class.with_container(container).with_codename(suite).exists?
end
def update_signed_file_store
# The signed_file.object_store is set during `uploader.store!`
# which happens after object is inserted/updated
self.update_column(:signed_file_store, signed_file.object_store)
end
end
end
end
end
|