arr-pm 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/arr-pm.gemspec +4 -2
- data/lib/arr-pm/file/header.rb +0 -2
- data/lib/arr-pm/file/lead.rb +0 -2
- data/lib/arr-pm/file/tag.rb +0 -2
- data/lib/arr-pm/file.rb +22 -44
- data/spec/fixtures/pagure-mirror-5.13.2-5.fc35.noarch.rpm +0 -0
- data/spec/rpm/file_spec.rb +57 -0
- metadata +39 -10
- data/.batcave/manifest +0 -5
- data/Guardfile +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b18d6ce9e276f133f3456d3f680c9727936e0be921d1f2492f9541aeefcbca9
|
4
|
+
data.tar.gz: d5bca7b579c4ff1f28b411a0d5195a83d34c023a749d563cbc95b9cb0bb5716b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58e476d730ac09d22ea1ee60cf463f3cc26b4cb3cc99f1f8b44d7cd323084d3ca1208a550b069f56afb2414759b9f3e5475716dfee0f2363ae5a10dc0235ae38
|
7
|
+
data.tar.gz: 361d8dfca458258a617e71153ff8e757c4f8963abe5d07d9020a120407f52059a2f3b8bd0a3e2495f9764a2cc02f18d4755d2ba532f670d16c1adfc3eb85a3cb
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# v0.0.12
|
4
|
+
|
5
|
+
* Security: Fixed a safety problem which would allow for arbitrary shell execution when invoking `RPM::File#extract` or `RPM::File#files`. (Jordan Sissel, @joernchen; #14, #15)
|
6
|
+
* This library now has no external dependencies. (Jordan Sissel, #18)
|
7
|
+
* `RPM::File#extract` now correctly works when the target directory contains spaces or other special characters. (@joernchen, #19)
|
8
|
+
* Listing files (`RPM::File#files`) no longer requires external tools like `cpio` (Jordan Sissel, #17)
|
9
|
+
|
10
|
+
|
11
|
+
# v0.0.11
|
12
|
+
|
13
|
+
* Support Ruby 3.0 (Alexey Morozov, #12)
|
14
|
+
* Fix bug caused when listing config_files on an rpm with no config files. (Daniel Jay Haskin, #7)
|
15
|
+
|
16
|
+
# Older versions
|
17
|
+
|
18
|
+
Changelog not tracked for older versions.
|
data/arr-pm.gemspec
CHANGED
@@ -2,14 +2,13 @@ Gem::Specification.new do |spec|
|
|
2
2
|
files = %x{git ls-files}.split("\n")
|
3
3
|
|
4
4
|
spec.name = "arr-pm"
|
5
|
-
spec.version = "0.0.
|
5
|
+
spec.version = "0.0.12"
|
6
6
|
spec.summary = "RPM reader and writer library"
|
7
7
|
spec.description = "This library allows to you to read and write rpm " \
|
8
8
|
"packages. Written in pure ruby because librpm is not available " \
|
9
9
|
"on all systems"
|
10
10
|
spec.license = "Apache 2"
|
11
11
|
|
12
|
-
spec.add_dependency "cabin", ">0" # for logging. apache 2 license
|
13
12
|
spec.files = files
|
14
13
|
spec.require_paths << "lib"
|
15
14
|
spec.bindir = "bin"
|
@@ -18,6 +17,9 @@ Gem::Specification.new do |spec|
|
|
18
17
|
spec.email = ["jls@semicomplete.com"]
|
19
18
|
|
20
19
|
spec.add_development_dependency "flores", ">0"
|
20
|
+
spec.add_development_dependency "rspec", ">3.0.0"
|
21
|
+
spec.add_development_dependency "stud", ">=0.0.23"
|
22
|
+
spec.add_development_dependency "insist", ">=1.0.0"
|
21
23
|
#spec.homepage = "..."
|
22
24
|
end
|
23
25
|
|
data/lib/arr-pm/file/header.rb
CHANGED
data/lib/arr-pm/file/lead.rb
CHANGED
data/lib/arr-pm/file/tag.rb
CHANGED
data/lib/arr-pm/file.rb
CHANGED
@@ -3,6 +3,7 @@ require File.join(File.dirname(__FILE__), "file", "header")
|
|
3
3
|
require File.join(File.dirname(__FILE__), "file", "lead")
|
4
4
|
require File.join(File.dirname(__FILE__), "file", "tag")
|
5
5
|
require "fcntl"
|
6
|
+
require "shellwords"
|
6
7
|
|
7
8
|
# Much of the code here is derived from knowledge gained by reading the rpm
|
8
9
|
# source code, but mostly it started making more sense after reading this site:
|
@@ -88,6 +89,14 @@ class RPM::File
|
|
88
89
|
return @payload
|
89
90
|
end # def payload
|
90
91
|
|
92
|
+
def valid_compressor?(name)
|
93
|
+
# I scanned rpm's rpmio.c for payload implementation names and found the following.
|
94
|
+
# sed -rne '/struct FDIO_s \w+ *= *\{/{ n; s/^.*"(\w+)",$/\1/p }' rpmio/rpmio.c
|
95
|
+
# It's possible this misses some supported rpm payload compressors.
|
96
|
+
|
97
|
+
[ "gzip", "bzip2", "xz", "lzma", "zstd" ].include?(name)
|
98
|
+
end
|
99
|
+
|
91
100
|
# Extract this RPM to a target directory.
|
92
101
|
#
|
93
102
|
# This should have roughly the same effect as:
|
@@ -97,8 +106,13 @@ class RPM::File
|
|
97
106
|
if !File.directory?(target)
|
98
107
|
raise Errno::ENOENT.new(target)
|
99
108
|
end
|
109
|
+
|
110
|
+
compressor = tags[:payloadcompressor]
|
111
|
+
if !valid_compressor?(compressor)
|
112
|
+
raise "Cannot decompress. This RPM uses an invalid compressor '#{compressor}'"
|
113
|
+
end
|
100
114
|
|
101
|
-
extractor = IO.popen("#{
|
115
|
+
extractor = IO.popen("#{compressor} -d | (cd #{Shellwords.escape(target)}; cpio -i --quiet --make-directories)", "w")
|
102
116
|
buffer = ""
|
103
117
|
begin
|
104
118
|
buffer.force_encoding("BINARY")
|
@@ -195,49 +209,13 @@ class RPM::File
|
|
195
209
|
#
|
196
210
|
# % rpm2cpio blah.rpm | cpio -it
|
197
211
|
def files
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
# Do Nothing
|
206
|
-
end
|
207
|
-
payload_fd = payload.clone
|
208
|
-
output = ""
|
209
|
-
loop do
|
210
|
-
data = payload_fd.read(16384, buffer)
|
211
|
-
break if data.nil? # listerextractor.write(data)
|
212
|
-
lister.write(data)
|
213
|
-
|
214
|
-
# Read output from the pipe.
|
215
|
-
begin
|
216
|
-
output << lister.read_nonblock(16384)
|
217
|
-
rescue Errno::EAGAIN
|
218
|
-
# Nothing to read, move on!
|
219
|
-
end
|
220
|
-
end
|
221
|
-
lister.close_write
|
222
|
-
|
223
|
-
# Read remaining output
|
224
|
-
begin
|
225
|
-
output << lister.read
|
226
|
-
rescue Errno::EAGAIN
|
227
|
-
# Because read_nonblock enables NONBLOCK the 'lister' fd,
|
228
|
-
# and we may have invoked a read *before* cpio has started
|
229
|
-
# writing, let's keep retrying this read until we get an EOF
|
230
|
-
retry
|
231
|
-
rescue EOFError
|
232
|
-
# At EOF, hurray! We're done reading.
|
233
|
-
end
|
234
|
-
|
235
|
-
# Split output by newline and strip leading "."
|
236
|
-
@files = output.split("\n").collect { |s| s.gsub(/^\./, "") }
|
237
|
-
return @files
|
238
|
-
ensure
|
239
|
-
lister.close unless lister.nil?
|
240
|
-
payload_fd.close unless payload_fd.nil?
|
212
|
+
# RPM stores the file metadata split across multiple tags.
|
213
|
+
# A single path's filename (with no directories) is stored in the "basename" tag.
|
214
|
+
# The directory a file lives in is stored in the "dirnames" tag
|
215
|
+
# We can find out what directory a file is in using the "dirindexes" tag.
|
216
|
+
#
|
217
|
+
# We can join each entry of dirnames and basenames to make the full filename.
|
218
|
+
return tags[:basenames].zip(tags[:dirindexes]).map { |name, i| File.join(tags[:dirnames][i], name) }
|
241
219
|
end # def files
|
242
220
|
|
243
221
|
def mask?(value, mask)
|
Binary file
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/file"
|
4
|
+
require "stud/temporary"
|
5
|
+
require "insist"
|
6
|
+
|
7
|
+
describe ::RPM::File do
|
8
|
+
subject { described_class.new(path) }
|
9
|
+
|
10
|
+
context "with a known good rpm" do
|
11
|
+
let(:path) { File.join(File.dirname(__FILE__), "../fixtures/pagure-mirror-5.13.2-5.fc35.noarch.rpm") }
|
12
|
+
|
13
|
+
context "#files" do
|
14
|
+
let(:files) { [
|
15
|
+
"/usr/lib/systemd/system/pagure_mirror.service",
|
16
|
+
"/usr/share/licenses/pagure-mirror",
|
17
|
+
"/usr/share/licenses/pagure-mirror/LICENSE"
|
18
|
+
]}
|
19
|
+
|
20
|
+
it "should have the correct list of files" do
|
21
|
+
expect(subject.files).to eq(files)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "#extract" do
|
27
|
+
# This RPM should be correctly built, but we will modify the tags at runtime to force an error.
|
28
|
+
let(:path) { File.join(File.dirname(__FILE__), "../fixtures/example-1.0-1.x86_64.rpm") }
|
29
|
+
let(:dir) { dir = Stud::Temporary.directory }
|
30
|
+
|
31
|
+
after do
|
32
|
+
FileUtils.rm_rf(dir)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with an invalid payloadcompressor" do
|
36
|
+
before do
|
37
|
+
subject.tags[:payloadcompressor] = "some invalid | string"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should raise an error" do
|
41
|
+
insist { subject.extract(dir) }.raises(RuntimeError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
[ "gzip", "bzip2", "xz", "lzma", "zstd" ].each do |name|
|
46
|
+
context "with a '#{name}' payloadcompressor" do
|
47
|
+
before do
|
48
|
+
subject.tags[:payloadcompressor] = name
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should succeed" do
|
52
|
+
reject { subject.extract(dir) }.raises(RuntimeError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arr-pm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sissel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: flores
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
|
-
type: :
|
20
|
+
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
@@ -25,19 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 3.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 3.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: stud
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.0.23
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.0.23
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: insist
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.0
|
41
69
|
description: This library allows to you to read and write rpm packages. Written in
|
42
70
|
pure ruby because librpm is not available on all systems
|
43
71
|
email:
|
@@ -46,11 +74,10 @@ executables: []
|
|
46
74
|
extensions: []
|
47
75
|
extra_rdoc_files: []
|
48
76
|
files:
|
49
|
-
- ".batcave/manifest"
|
50
77
|
- ".gitignore"
|
51
78
|
- ".rubocop.yml"
|
79
|
+
- CHANGELOG.md
|
52
80
|
- Gemfile
|
53
|
-
- Guardfile
|
54
81
|
- LICENSE
|
55
82
|
- Makefile
|
56
83
|
- README.md
|
@@ -77,6 +104,8 @@ files:
|
|
77
104
|
- spec/arr-pm/v2/lead_spec.rb
|
78
105
|
- spec/fixtures/example-1.0-1.x86_64.rpm
|
79
106
|
- spec/fixtures/example.json
|
107
|
+
- spec/fixtures/pagure-mirror-5.13.2-5.fc35.noarch.rpm
|
108
|
+
- spec/rpm/file_spec.rb
|
80
109
|
homepage:
|
81
110
|
licenses:
|
82
111
|
- Apache 2
|
@@ -97,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
126
|
- !ruby/object:Gem::Version
|
98
127
|
version: '0'
|
99
128
|
requirements: []
|
100
|
-
rubygems_version: 3.
|
129
|
+
rubygems_version: 3.3.3
|
101
130
|
signing_key:
|
102
131
|
specification_version: 4
|
103
132
|
summary: RPM reader and writer library
|
data/Guardfile
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
# A sample Guardfile
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
3
|
-
|
4
|
-
## Uncomment and set this to only include directories you want to watch
|
5
|
-
# directories %w(app lib config test spec features)
|
6
|
-
|
7
|
-
## Uncomment to clear the screen before every task
|
8
|
-
# clearing :on
|
9
|
-
|
10
|
-
## Guard internally checks for changes in the Guardfile and exits.
|
11
|
-
## If you want Guard to automatically start up again, run guard in a
|
12
|
-
## shell loop, e.g.:
|
13
|
-
##
|
14
|
-
## $ while bundle exec guard; do echo "Restarting Guard..."; done
|
15
|
-
##
|
16
|
-
## Note: if you are using the `directories` clause above and you are not
|
17
|
-
## watching the project directory ('.'), then you will want to move
|
18
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
19
|
-
#
|
20
|
-
# $ mkdir config
|
21
|
-
# $ mv Guardfile config/
|
22
|
-
# $ ln -s config/Guardfile .
|
23
|
-
#
|
24
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
25
|
-
|
26
|
-
# Note: The cmd option is now required due to the increasing number of ways
|
27
|
-
# rspec may be run, below are examples of the most common uses.
|
28
|
-
# * bundler: 'bundle exec rspec'
|
29
|
-
# * bundler binstubs: 'bin/rspec'
|
30
|
-
# * spring: 'bin/rspec' (This will use spring if running and you have
|
31
|
-
# installed the spring binstubs per the docs)
|
32
|
-
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
33
|
-
# * 'just' rspec: 'rspec'
|
34
|
-
|
35
|
-
guard :rspec, cmd: "bundle exec rspec" do
|
36
|
-
require "guard/rspec/dsl"
|
37
|
-
dsl = Guard::RSpec::Dsl.new(self)
|
38
|
-
|
39
|
-
# Feel free to open issues for suggestions and improvements
|
40
|
-
|
41
|
-
# RSpec files
|
42
|
-
rspec = dsl.rspec
|
43
|
-
watch(rspec.spec_helper) { rspec.spec_dir }
|
44
|
-
watch(rspec.spec_support) { rspec.spec_dir }
|
45
|
-
watch(rspec.spec_files)
|
46
|
-
|
47
|
-
# Ruby files
|
48
|
-
ruby = dsl.ruby
|
49
|
-
dsl.watch_spec_files_for(ruby.lib_files)
|
50
|
-
|
51
|
-
# Rails files
|
52
|
-
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
53
|
-
dsl.watch_spec_files_for(rails.app_files)
|
54
|
-
dsl.watch_spec_files_for(rails.views)
|
55
|
-
|
56
|
-
watch(rails.controllers) do |m|
|
57
|
-
[
|
58
|
-
rspec.spec.("routing/#{m[1]}_routing"),
|
59
|
-
rspec.spec.("controllers/#{m[1]}_controller"),
|
60
|
-
rspec.spec.("acceptance/#{m[1]}")
|
61
|
-
]
|
62
|
-
end
|
63
|
-
|
64
|
-
# Rails config changes
|
65
|
-
watch(rails.spec_helper) { rspec.spec_dir }
|
66
|
-
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
67
|
-
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
68
|
-
|
69
|
-
# Capybara features specs
|
70
|
-
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
71
|
-
|
72
|
-
# Turnip features and steps
|
73
|
-
watch(%r{^spec/acceptance/(.+)\.feature$})
|
74
|
-
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
75
|
-
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
76
|
-
end
|
77
|
-
end
|