Commit e3807801 authored by Ryan Hass's avatar Ryan Hass Committed by GitHub
Browse files

Merge pull request #799 from WarheadsSE/add-deb-package-signing

Add Debian (.deb) package signing (implementing debsig)
parents 52393d7c a02a2c95
...@@ -39,6 +39,7 @@ package :deb do ...@@ -39,6 +39,7 @@ package :deb do
license 'Apache 2.0' license 'Apache 2.0'
priority 'extra' priority 'extra'
section 'databases' section 'databases'
signing_passphrase 'acbd1234'
end end
``` ```
...@@ -46,6 +47,7 @@ Some DSL methods available include: ...@@ -46,6 +47,7 @@ Some DSL methods available include:
| DSL Method | Description | | DSL Method | Description |
| :------------------: | --------------------------------------------| | :------------------: | --------------------------------------------|
| `signing_passphrase` | The passphrase to sign the RPM with |
| `vendor` | The name of the package producer | | `vendor` | The name of the package producer |
| `license` | The default license for the package | | `license` | The default license for the package |
| `priority` | The priority for the package | | `priority` | The priority for the package |
...@@ -56,4 +58,4 @@ If you are unfamiliar with any of these terms, you should just accept the defaul ...@@ -56,4 +58,4 @@ If you are unfamiliar with any of these terms, you should just accept the defaul
For more information, please see the [`Packager::DEB` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Packager/DEB). For more information, please see the [`Packager::DEB` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Packager/DEB).
### Notes on DEB-signing ### Notes on DEB-signing
At this time, signing Debian packages is not supported. To sign an DEB, you will need a GPG keypair. You can [create your own signing key](http://www.madboa.com/geek/gpg-quickstart/) or [import an existing one](http://irtfweb.ifa.hawaii.edu/~lockhart/gpg/gpg-cs.html). Omnibus will automatically call `gpg` with arguments that assume the real name associated to the GPG key is the same as the name of the project maintainer as specified in your Omnibus config.
...@@ -60,12 +60,37 @@ module Omnibus ...@@ -60,12 +60,37 @@ module Omnibus
# Create the deb # Create the deb
create_deb_file create_deb_file
# Sign the deb
sign_deb_file
end end
# #
# @!group DSL methods # @!group DSL methods
# -------------------------------------------------- # --------------------------------------------------
#
# Set or return the signing passphrase. If this value is provided,
# Omnibus will attempt to sign the DEB.
#
# @example
# signing_passphrase "foo"
#
# @param [String] val
# the passphrase to use when signing the DEB
#
# @return [String]
# the DEB-signing passphrase
#
def signing_passphrase(val = NULL)
if null?(val)
@signing_passphrase
else
@signing_passphrase = val
end
end
expose :signing_passphrase
# #
# Set or return the vendor who made this package. # Set or return the vendor who made this package.
# #
...@@ -389,6 +414,62 @@ module Omnibus ...@@ -389,6 +414,62 @@ module Omnibus
end end
end end
#
# Sign the +.deb+ file with gpg. This has to be done as separate steps
# from creating the +.deb+ file. See +debsigs+ source for behavior
# replicated here. +https://gitlab.com/debsigs/debsigs/blob/master/debsigs.txt#L103-124+
#
# @return [void]
def sign_deb_file
if !signing_passphrase
log.info(log_key) { "Signing not enabled for .deb file" }
return
end
log.info(log_key) { "Signing enabled for .deb file" }
# Check our dependencies and determine command for GnuPG. +Omnibus.which+ returns the path, or nil.
gpg = nil
if Omnibus.which("gpg2")
gpg = "gpg2"
elsif Omnibus.which("gpg")
gpg = "gpg"
end
if gpg && Omnibus.which("ar")
# Create a directory that will be cleaned when we leave the block
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir) do
# Extract the deb file contents
shellout!("ar x #{Config.package_dir}/#{package_name}")
# Concatenate contents, in order per +debsigs+ documentation.
shellout!("cat debian-binary control.tar.* data.tar.* > complete")
# Create signature (as +root+)
gpg_command = "#{gpg} --armor --sign --detach-sign"
gpg_command << " --local-user '#{project.maintainer}'"
gpg_command << " --homedir #{ENV['HOME']}/.gnupg" # TODO: Make this configurable
## pass the +signing_passphrase+ via +STDIN+
gpg_command << " --batch --no-tty"
## Check `gpg` for the compatibility/need of pinentry-mode
# - We're calling gpg with the +--pinentry-mode+ argument, and +STDIN+ of +/dev/null+
# - This _will_ fail with exit code 2 no matter what. We want to check the +STDERR+
# for the error message about the parameter. If it is _not present_ in the
# output, then we _do_ want to add it. (If +grep -q+ is +1+, add parameter)
if shellout("#{gpg} --pinentry-mode loopback </dev/null 2>&1 | grep -q pinentry-mode").exitstatus == 1
gpg_command << " --pinentry-mode loopback"
end
gpg_command << " --passphrase-fd 0"
gpg_command << " -o _gpgorigin complete"
shellout!("fakeroot #{gpg_command}", input: signing_passphrase)
# Append +_gpgorigin+ to the +.deb+ file (as +root+)
shellout!("fakeroot ar rc #{Config.package_dir}/#{package_name} _gpgorigin")
end
end
else
log.info(log_key) { "Signing not possible. Ensure that GnuPG and GNU AR are available" }
end
end
# #
# The size of this Debian package. This is dynamically calculated. # The size of this Debian package. This is dynamically calculated.
# #
......
...@@ -337,6 +337,46 @@ module Omnibus ...@@ -337,6 +337,46 @@ module Omnibus
end end
end end
describe "#sign_deb_file", :not_supported_on_windows do
context "when DEB signing is not enabled" do
before do
subject.signing_passphrase(nil)
end
it "logs a message" do
output = capture_logging { subject.sign_deb_file }
expect(output).to include("Signing not enabled for .deb file")
end
end
context "when DEB signing is enabled" do
before do
allow(subject).to receive(:shellout!)
allow(subject).to receive(:package_name).and_return("safe")
subject.signing_passphrase("foobar")
end
it "logs a message" do
output = capture_logging { subject.sign_deb_file }
expect(output).to include("Signing enabled for .deb file")
end
it "finds gpg and ar commands" do
output = capture_logging { subject.sign_deb_file }
expect(output).not_to include("Signing not possible.")
end
it "runs correct commands" do
expect(subject).to receive(:shellout!)
.at_least(:once).with(/ar x/)
.at_least(:once).with(/cat debian-binary control\.tar/)
.at_least(:once).with(/fakeroot gpg/)
.at_least(:once).with(/fakeroot ar rc/)
subject.sign_deb_file
end
end
end
describe "#package_size" do describe "#package_size" do
before do before do
project.install_dir(staging_dir) project.install_dir(staging_dir)
......
Supports Markdown
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