repo-mgr 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 977383f34636b8ba22a0e7a936869ccf69060691787f9ebb2ed4bad5826af13b
4
- data.tar.gz: fb53030359f59ecad95adcf2a304e304fdd5c6ebed32c0c3c4e74f2e214d877d
3
+ metadata.gz: a977e25ed86d9763543cd445087e3d4e94e6ecf830e707ffb8c9dfb9c5d19541
4
+ data.tar.gz: a7d2ea6036a1d3a4fc3fc2c6f575e7dda9eaa7bc2db1d7bc0b2fe7dcdb459891
5
5
  SHA512:
6
- metadata.gz: e78a4a1dafca417fa59fe93d458ee6cf8b4fa22ad48ef0bd60ae95258e02adc9c9a3c6d91c4516224576fe0ba6c9f8eebed1bed8f82777b85836cde089b6133e
7
- data.tar.gz: 2a3c93c1f6768d6296682c17e5eacc4cf416f46d58e2c232962ca1b86bc7fff4fddff2e5c6441bb9392f823d1e9fcbe1bcb0e4d8f64b108307adbfbce71ff07e
6
+ metadata.gz: 8044c481083ac23582a3d3133dbd225ab874188217766e71d0e82e3a76bf325776ef6241064347ee5fb39df5e63d89acfe7c086f592314062fe1c3a391645ae8
7
+ data.tar.gz: d58d378485e4a41741360d308652e56b4dc9a3abd4be396840d1131c6daf187fdce3bde7de00eb2242ac0207dfacd912c591783e6fe38eaf91e266f4e77892d0
data/README.md CHANGED
@@ -16,6 +16,8 @@ To simplify things:
16
16
  * aptly (which, kind of obviously, manages deb repositories) uses "stable" as distribution and "main" as component.
17
17
  * The git publisher uses the `main` branch for `sync` only.
18
18
 
19
+ The requred aptly version is 1.4.0+ which may be installed from [aptly's deb repository](https://www.aptly.info/download/). The version available in Ubuntu 20.04 (1.3.0) doesn't support gpg2.
20
+
19
21
  ## Install
20
22
 
21
23
  ```bash
@@ -26,21 +28,21 @@ gem install repo-mgr
26
28
  rake install
27
29
  ```
28
30
 
29
- As repo-mgr is a frontend for other tools, there's dependencies which must be installed separately.
31
+ As repo-mgr is a frontend for other tools, there are dependencies which must be installed separately. It is not compulsory to install all dependencies, only those needed for a particular use case. The purpose for each tool is explained by `check-depends`.
30
32
 
31
- To check which dependencies are required and their status:
33
+ To check which dependencies are required based on use case and their status:
32
34
 
33
35
  ```bash
34
36
  repo-mgr check-depends
35
- +------------+--------+
36
- | Binary | Status |
37
- +------------+--------+
38
- | aptly | ✔ |
39
- | dpkg-sig | ✔ |
40
- | createrepo | ✔ |
41
- | rpm | ✔ |
42
- | git | ✔ |
43
- +------------+--------+
37
+ +------------+--------+-----------------------+
38
+ | Binary | Status | Purpose |
39
+ +------------+--------+-----------------------+
40
+ | aptly | ✔ | Manage apt repository |
41
+ | dpkg-sig | ✔ | Sign deb packages |
42
+ | createrepo | ✔ | Manage rpm repository |
43
+ | rpm | ✔ | Sign rpm packages |
44
+ | git | ✔ | Use git publisher |
45
+ +------------+--------+-----------------------+
44
46
  ```
45
47
 
46
48
  For managing deb repositories:
@@ -67,6 +69,12 @@ sudo apt install git
67
69
 
68
70
  You can get our build of createrepo from our [deb repository](https://deb.staker.ltd/).
69
71
 
72
+ Pro tip: if the pkg signing fails because gpg can't open the output device, add this to your shell config:
73
+
74
+ ```bash
75
+ export GPG_TTY=$(tty)
76
+ ```
77
+
70
78
  ## How to use
71
79
 
72
80
  ```bash
@@ -87,6 +95,20 @@ repo-mgr add-pkg --repo foo --path path/to/bar_0.0.1_amd64.deb
87
95
 
88
96
  # publish the repository to a remote - for git publisher this means doing git push
89
97
  repo-mgr sync --repo foo
98
+
99
+ # download repo from remote e.g when changing development machines
100
+ # repo-mgr upsert-repo (...) # needed only once if the machine is brand new
101
+ ## --url must point to the root of the remote repository
102
+ ## i.e where the pool and dists directories can be found for deb repos
103
+ ## --keyring is required for deb repositories; it is a file from
104
+ ## /usr/share/keyrings - the base path is automatically prepended
105
+ ## WARNING: the packages are not signed when imported via this method!
106
+ repo-mgr dl-repo --repo foo --type deb --url https://apt.example.com --keyring foo-keyring.gpg
107
+
108
+ ## --arch must be specified as each rpm repo arch is self-contained
109
+ ## the remote repository gpg key must be imported into the user's keyring and trusted
110
+ ## prior to starting the import process from remote rpm repo
111
+ repo-mgr dl-repo --repo foo --type rpm --url https://rpm.example.com --arch x86_64
90
112
  ```
91
113
 
92
114
  ## Migrating from v0.1
@@ -14,14 +14,7 @@ module RepoMgr
14
14
  end
15
15
 
16
16
  def add_repo(name)
17
- return if aptly_repos.include? name
18
-
19
- cmd = "aptly -config=#{@aptly_config_file} repo create #{name}"
20
- out, status = Open3.capture2e cmd
21
-
22
- unless status.exitstatus.zero?
23
- Tools.error "aptly repo create failed with:\n#{out}"
24
- end
17
+ aptly "repo create #{name}" unless aptly_repos.include? name
25
18
 
26
19
  repo_config = @config.cfg[:repos][name]
27
20
 
@@ -34,6 +27,24 @@ module RepoMgr
34
27
  save_aptly_config
35
28
  end
36
29
 
30
+ def dl_repo(options)
31
+ name = options[:repo]
32
+ url = options[:url]
33
+ keyring = options[:keyring]
34
+
35
+ if keyring.nil?
36
+ Tools.error 'you must specify a keyring file for deb repo'
37
+ end
38
+
39
+ keyring = "/usr/share/keyrings/#{keyring}"
40
+
41
+ aptly "-keyring=#{keyring} mirror create #{name} #{url} stable main"
42
+ aptly "-keyring=#{keyring} mirror update #{name}", :output
43
+ aptly "repo import #{name} #{name} Name"
44
+ aptly "mirror drop #{name}"
45
+ aptly("repo search #{name}", :return).split.map { |e| "#{e}.deb" }
46
+ end
47
+
37
48
  def add_pkg(repo, pkg)
38
49
  sign_pkg repo, pkg
39
50
  repo_add repo, pkg
@@ -51,14 +62,14 @@ module RepoMgr
51
62
  return out if status.exitstatus.zero? || allow_fail
52
63
 
53
64
  Tools.error "unable to check package signature for #{pkg} - "\
54
- "dpkg-sig returned:\n#{out}"
65
+ "dpkg-sig returned:\n#{out}"
55
66
  end
56
67
 
57
68
  def sign_pkg(repo, pkg)
58
69
  signature = check_sig pkg, allow_fail: true
59
70
 
60
71
  unless signature[-6, 5] == 'NOSIG'
61
- return puts "-- dpkg-sig returned:\n#{signature.first}"
72
+ return puts "-- dpkg-sig returned:\n#{signature.split.first}"
62
73
  end
63
74
 
64
75
  if @config.cfg[:repos][repo].nil?
@@ -74,18 +85,9 @@ module RepoMgr
74
85
  end
75
86
 
76
87
  def rebuild_pkg_list(repo)
77
- out, status = Open3.capture2e "aptly -config=#{@aptly_config_file} "\
78
- "-with-packages repo show #{repo}"
79
-
80
- unless status.exitstatus.zero?
81
- Tools.error "aptly repo show failed with with:\n#{out}"
88
+ aptly("-with-packages repo search #{repo}", :return).split.map do |e|
89
+ "#{e}.deb"
82
90
  end
83
-
84
- pkgs = out.split
85
- mark = pkgs.find_index 'Packages:'
86
- pkgs = pkgs.drop(mark + 1)
87
-
88
- pkgs.map { |e| "#{e}.deb" }
89
91
  end
90
92
 
91
93
  def export(repo)
@@ -121,8 +123,6 @@ module RepoMgr
121
123
  dependencyVerboseResolve: false,
122
124
  gpgDisableSign: false,
123
125
  gpgDisableVerify: false,
124
- # despite the binary being gpg, this must spell gpg2, otherwise aptly
125
- # defaults to gpg1 with less than impressive results
126
126
  gpgProvider: 'gpg2',
127
127
  downloadSourcePackages: false,
128
128
  skipLegacyPool: true,
@@ -136,36 +136,30 @@ module RepoMgr
136
136
  end
137
137
  # rubocop:enable Metrics/MethodLength
138
138
 
139
- def aptly_repos
140
- cmd = "aptly -raw -config=#{@aptly_config_file} repo list"
139
+ def aptly(cmd, output = nil)
140
+ cmd = "aptly -config=#{@aptly_config_file} #{cmd}"
141
141
  out, status = Open3.capture2e cmd
142
142
 
143
- unless status.exitstatus.zero?
144
- Tools.error "aptly repo list failed with:\n#{out}"
143
+ Tools.error "#{cmd} failed with:\n#{out}" unless status.exitstatus.zero?
144
+
145
+ case output
146
+ when :output
147
+ puts out
148
+ when :return
149
+ out
145
150
  end
151
+ end
146
152
 
147
- out.split("\n")
153
+ def aptly_repos
154
+ aptly('-raw repo list', :return).split
148
155
  end
149
156
 
150
157
  def aptly_published_repos
151
- cmd = "aptly -raw -config=#{@aptly_config_file} publish list"
152
- out, status = Open3.capture2e cmd
153
-
154
- unless status.exitstatus.zero?
155
- Tools.error "aptly publish list failed with:\n#{out}"
156
- end
157
-
158
- out.split("\n")
158
+ aptly('-raw publish list', :return).split("\n")
159
159
  end
160
160
 
161
161
  def aptly_publish_drop(repo)
162
- cmd = "aptly -config=#{@aptly_config_file} publish drop stable "\
163
- "filesystem:#{repo}:"
164
- out, status = Open3.capture2e cmd
165
-
166
- return if status.exitstatus.zero?
167
-
168
- Tools.error "aptly publish drop failed with:\n#{out}"
162
+ aptly "publish drop stable filesystem:#{repo}:"
169
163
  end
170
164
 
171
165
  def save_aptly_config
@@ -173,23 +167,12 @@ module RepoMgr
173
167
  end
174
168
 
175
169
  def repo_add(repo, pkg)
176
- cmd = "aptly -config=#{@aptly_config_file} repo add #{repo} #{pkg}"
177
- out, status = Open3.capture2e cmd
178
-
179
- return if status.exitstatus.zero?
180
-
181
- Tools.error "aptly repo add failed with:\n#{out}"
170
+ aptly "repo add #{repo} #{pkg}"
182
171
  end
183
172
 
184
173
  def repo_rm(repo, pkg)
185
174
  package = File.basename pkg, File.extname(pkg)
186
- cmd = "aptly -config=#{@aptly_config_file} repo remove "\
187
- "#{repo} #{package}"
188
- out, status = Open3.capture2e cmd
189
-
190
- return if status.exitstatus.zero?
191
-
192
- Tools.error "aptly repo remove failed with:\n#{out}"
175
+ aptly "repo remove #{repo} #{package}"
193
176
  end
194
177
 
195
178
  def repo_publish(repo)
@@ -198,14 +181,8 @@ module RepoMgr
198
181
  end
199
182
 
200
183
  keyid = @config.cfg[:repos][repo][:keyid]
201
- cmd = "aptly -config=#{@aptly_config_file} -distribution=stable "\
202
- "-gpg-key=#{keyid} publish repo #{repo} filesystem:#{repo}:"
203
-
204
- out, status = Open3.capture2e cmd
205
-
206
- return if status.exitstatus.zero?
207
-
208
- Tools.error "aptly publish repo failed with:\n#{out}"
184
+ aptly "-distribution=stable -gpg-key=#{keyid} publish repo #{repo} "\
185
+ "filesystem:#{repo}:"
209
186
  end
210
187
  end
211
188
  end
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: false
2
2
 
3
+ require 'zlib'
3
4
  require 'open3'
4
5
  require 'gpgme'
6
+ require 'digest'
7
+ require 'faraday'
8
+ require 'nokogiri'
9
+ require 'stringio'
5
10
  require 'fileutils'
6
11
 
7
12
  module RepoMgr
@@ -27,6 +32,30 @@ module RepoMgr
27
32
  sync_repo repo
28
33
  end
29
34
 
35
+ def dl_repo(options)
36
+ name = options[:repo]
37
+ url = options[:url]
38
+ arch = options[:arch]
39
+
40
+ Tools.error 'you must specify an arch name for rpm repo' if arch.nil?
41
+
42
+ tmpdir = "/tmp/#{name}/#{arch}"
43
+ dest_dir = "#{@config.cfg_dir}/rpms/#{name}/#{arch}"
44
+ make_dirs tmpdir, dest_dir
45
+
46
+ repomd = dl_repomd url, arch, tmpdir
47
+ pkgs = dl_primary url, arch, tmpdir, repomd
48
+
49
+ pkgs.each do |hash, file|
50
+ dl_pkg hash, url, arch, file, tmpdir
51
+ copy_pkg "#{tmpdir}/#{file}", dest_dir
52
+ end
53
+
54
+ sync_repo name
55
+
56
+ pkgs.values
57
+ end
58
+
30
59
  def remove_pkg(repo, pkg)
31
60
  name = File.basename pkg
32
61
  arch = extract_arch pkg
@@ -43,7 +72,7 @@ module RepoMgr
43
72
  return out if status.exitstatus.zero?
44
73
 
45
74
  Tools.error "unable to check package signature for #{pkg} - "\
46
- "rpm -K returned:\n#{out}"
75
+ "rpm -K returned:\n#{out}"
47
76
  end
48
77
 
49
78
  def sign_pkg(repo, pkg)
@@ -114,7 +143,7 @@ module RepoMgr
114
143
  return if status.exitstatus.zero?
115
144
 
116
145
  Tools.error "unable to create repo for #{arch} - createrepo "\
117
- "returned:\n#{out}"
146
+ "returned:\n#{out}"
118
147
  end
119
148
 
120
149
  def sign_repo(repo)
@@ -131,6 +160,83 @@ module RepoMgr
131
160
 
132
161
  File.write 'repomd.xml.asc', signature
133
162
  end
163
+
164
+ def faraday_dl(url, tmpdir, file = File.basename(url))
165
+ puts "-- Download #{file}"
166
+ File.write "#{tmpdir}/#{file}", Faraday.get(url).body
167
+ end
168
+
169
+ def dl_repomd(url, arch, tmpdir)
170
+ faraday_dl "#{url}/#{arch}/repodata/repomd.xml", tmpdir
171
+ faraday_dl "#{url}/#{arch}/repodata/repomd.xml.asc", tmpdir
172
+
173
+ valid = false
174
+ crypto = GPGME::Crypto.new armor: true
175
+ sig = GPGME::Data.new File.read "#{tmpdir}/repomd.xml.asc"
176
+ data = File.read "#{tmpdir}/repomd.xml"
177
+ crypto.verify(sig, signed_text: data) do |sign|
178
+ valid = sign.valid?
179
+ end
180
+
181
+ unless valid == true
182
+ Tools.error "unable to check signature for #{tmpdir}/repomd.xml"
183
+ end
184
+
185
+ Nokogiri::XML data
186
+ end
187
+
188
+ def extract_pkgs(primary)
189
+ pkgs = {}
190
+
191
+ primary.css('package').each do |pkg|
192
+ pkg_hash = pkg.at('checksum[type=sha256]').text
193
+ pkgs[pkg_hash] = pkg.at('location')['href']
194
+ end
195
+
196
+ pkgs
197
+ end
198
+
199
+ def dl_primary(url, arch, tmpdir, repomd)
200
+ hash = repomd.at('data[type=primary]').at('checksum').text
201
+ primary = "#{url}/#{arch}/repodata/#{hash}-primary.xml.gz"
202
+
203
+ faraday_dl primary, tmpdir, 'primary.xml.gz'
204
+
205
+ primary_xml_gz = "#{tmpdir}/primary.xml.gz"
206
+ fl_hash = Digest::SHA256.hexdigest(File.read(primary_xml_gz))
207
+
208
+ unless fl_hash == hash
209
+ Tools.error "failed hash check for #{tmpdir}/primary.xml.gz"
210
+ end
211
+
212
+ primary_xml_gz = File.read("#{tmpdir}/primary.xml.gz")
213
+ primary = Zlib::GzipReader.new(StringIO.new(primary_xml_gz)).read
214
+ File.write("#{tmpdir}/primary.xml", primary)
215
+
216
+ extract_pkgs Nokogiri::XML(primary)
217
+ end
218
+
219
+ def dl_pkg(hash, url, arch, file, tmpdir)
220
+ unless File.exist? "#{tmpdir}/#{file}"
221
+ faraday_dl "#{url}/#{arch}/#{file}", tmpdir
222
+ end
223
+
224
+ fl_hash = Digest::SHA256.hexdigest(File.read("#{tmpdir}/#{file}"))
225
+
226
+ return if fl_hash == hash
227
+
228
+ Tools.error "failed hash check for #{tmpdir}/#{file}"
229
+ end
230
+
231
+ def copy_pkg(file, destdir)
232
+ puts "-- Copy to repo-mgr #{File.basename(file)}"
233
+ FileUtils.cp file, destdir
234
+ end
235
+
236
+ def make_dirs(tmpdir, dest_dir)
237
+ FileUtils.mkdir_p tmpdir
238
+ FileUtils.mkdir_p dest_dir
239
+ end
134
240
  end
135
241
  end
136
242
  end
data/lib/repo_mgr/cli.rb CHANGED
@@ -29,16 +29,19 @@ module RepoMgr
29
29
 
30
30
  def check_depends
31
31
  rows = []
32
-
33
- %w[aptly dpkg-sig createrepo rpm git].each do |bin_dep|
34
- rows << if Tools.which bin_dep
35
- [bin_dep, ''.green]
36
- else
37
- [bin_dep, ''.red]
38
- end
32
+ deps = {
33
+ 'aptly' => 'Manage apt repository',
34
+ 'dpkg-sig' => 'Sign deb packages',
35
+ 'createrepo' => 'Manage rpm repository',
36
+ 'rpm' => 'Sign rpm packages',
37
+ 'git' => 'Use git publisher'
38
+ }
39
+
40
+ deps.each do |bin_dep, purpose|
41
+ rows << which_depends(bin_dep, purpose)
39
42
  end
40
43
 
41
- puts Terminal::Table.new headings: %w[Binary Status], rows: rows
44
+ puts Terminal::Table.new headings: %w[Binary Status Purpose], rows: rows
42
45
  end
43
46
 
44
47
  desc 'upsert-repo', 'Create/Update new repository'
@@ -82,6 +85,28 @@ module RepoMgr
82
85
  )
83
86
  end
84
87
 
88
+ desc 'dl-repo', 'Download repository from remote endpoint'
89
+ option :repo, type: :string, required: true, aliases: %w[-r],
90
+ desc: 'The repository to download packages into'
91
+ option :type, type: :string, required: true, aliases: %w[-t],
92
+ enum: types, desc: 'Repository type'
93
+ option :url, type: :string, required: true, aliases: %w[-u],
94
+ desc: 'The URL for the remote repository'
95
+ option :keyring, type: :string, aliases: %w[-k],
96
+ desc: 'Name of keyring file if required to auth repository'
97
+ option :arch, type: :string, aliases: %w[-a],
98
+ desc: 'Pkg arch if multiple arch are supported by repo'
99
+
100
+ def dl_repo
101
+ backend, config = load_backend options[:type]
102
+
103
+ pkgs = backend.dl_repo options
104
+
105
+ pkgs.each do |pkg|
106
+ config.add_pkg options[:repo], pkg
107
+ end
108
+ end
109
+
85
110
  desc 'add-pkg', 'Add package to repository'
86
111
  option :repo, type: :string, required: true, aliases: %w[-r],
87
112
  desc: 'The repository to add the package to'
@@ -100,7 +125,7 @@ module RepoMgr
100
125
  end
101
126
 
102
127
  puts "-- Added #{File.basename(options[:path])} to "\
103
- "#{options[:repo]} repository"
128
+ "#{options[:repo]} repository"
104
129
  end
105
130
 
106
131
  desc 'list-pkgs', 'List repository packages'
@@ -132,7 +157,7 @@ module RepoMgr
132
157
  config.remove_pkg options[:repo], options[:path]
133
158
 
134
159
  puts "-- Removed #{File.basename(options[:path])} from "\
135
- "#{options[:repo]} repository"
160
+ "#{options[:repo]} repository"
136
161
  end
137
162
 
138
163
  desc 'check-sig', 'Check package signature'
@@ -190,8 +215,15 @@ module RepoMgr
190
215
 
191
216
  private
192
217
 
218
+ def which_depends(bin_dep, purpose)
219
+ return [bin_dep, '✔'.green, purpose] if Tools.which bin_dep
220
+
221
+ [bin_dep, '✘'.red, purpose]
222
+ end
223
+
193
224
  def load_backend(path)
194
225
  type = File.extname(path).strip.downcase[1..-1]
226
+ type = path if type.nil?
195
227
 
196
228
  unless CLI.types.include? type
197
229
  Tools.error "unsupported package type #{type}"
@@ -68,7 +68,7 @@ module RepoMgr
68
68
  def remove_pkg(repo, path)
69
69
  if @cfg[:repos][repo].nil?
70
70
  Tools.error "unable to remove packages from #{repo} "\
71
- '- repo does not exist'
71
+ '- repo does not exist'
72
72
  end
73
73
 
74
74
  @cfg[:packages] ||= {}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repo-mgr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ștefan Rusu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-17 00:00:00.000000000 Z
11
+ date: 2022-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.9.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.9.3
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: git
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.13.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.13.3
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: terminal-table
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +109,7 @@ dependencies:
81
109
  - !ruby/object:Gem::Version
82
110
  version: '1.1'
83
111
  - !ruby/object:Gem::Dependency
84
- name: jeweler
112
+ name: juwelier
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - ">="
@@ -176,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
204
  - !ruby/object:Gem::Version
177
205
  version: '0'
178
206
  requirements: []
179
- rubygems_version: 3.1.4
207
+ rubygems_version: 3.2.32
180
208
  signing_key:
181
209
  specification_version: 4
182
210
  summary: deb and rpm repository manager