rspec-pgp_matchers 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rubocop.yml ADDED
@@ -0,0 +1,40 @@
1
+ # This project follows the Ribose OSS style guide.
2
+ # https://github.com/riboseinc/oss-guides
3
+ # All project-specific additions and overrides should be specified in this file.
4
+
5
+ inherit_from:
6
+ # Thoughtbot's style guide from: https://github.com/thoughtbot/guides
7
+ - ".rubocop.tb.yml"
8
+ # Overrides from Ribose
9
+ - ".rubocop.ribose.yml"
10
+ AllCops:
11
+ DisplayCopNames: false
12
+ StyleGuideCopsOnly: false
13
+ TargetRubyVersion: 2.3
14
+ Exclude:
15
+ - bin/bundle
16
+ - bin/rake
17
+ - bin/rspec
18
+ Rails:
19
+ Enabled: false
20
+
21
+ Style/EmptyCaseCondition:
22
+ Enabled: false
23
+
24
+ Style/TrailingCommaInArguments:
25
+ Exclude:
26
+ # RSpec expectations can easily go multiline. And sometimes, it's all not
27
+ # about multiple arguments, but more about & or | operators. Comma placed
28
+ # after a single method argument which spans across many lines is confusing,
29
+ # not helpful. Hence, I'm disabling this cop for all specs.
30
+ - "spec/**/*"
31
+
32
+ Metrics/BlockLength:
33
+ Exclude:
34
+ - "spec/**/*"
35
+ - "**/*.rake"
36
+ - "Rakefile"
37
+
38
+ Style/HashSyntax:
39
+ Exclude:
40
+ - "Rakefile"
data/.travis.yml ADDED
@@ -0,0 +1,77 @@
1
+ dist: trusty
2
+ language: ruby
3
+ sudo: true
4
+
5
+ rvm:
6
+ - "2.3"
7
+ - "2.4"
8
+ - "2.5"
9
+ - "ruby-head"
10
+
11
+ env:
12
+ matrix:
13
+ - GPG_VERSION="2.2"
14
+
15
+ global:
16
+ - DEPS_BUILD_DIR="${TRAVIS_BUILD_DIR}/build"
17
+ - DEPS_PREFIX="${TRAVIS_BUILD_DIR}/opt"
18
+ - GPG_PREFIX="${DEPS_PREFIX}/gpg"
19
+
20
+ - LD_RUN_PATH="${GPG_PREFIX}/lib"
21
+
22
+ - PATH="${GPG_PREFIX}/bin:${PATH}"
23
+
24
+ # Many of these are supported only in few GPG components, hence bunch of
25
+ # harmless warnings typically shows up.
26
+ - >
27
+ GPG_CONFIGURE_OPTS="--disable-doc --enable-pinentry-curses
28
+ --disable-pinentry-emacs --disable-pinentry-gtk2 --disable-pinentry-gnome3
29
+ --disable-pinentry-qt --disable-pinentry-qt4 --disable-pinentry-qt5
30
+ --disable-pinentry-tqt --disable-pinentry-fltk
31
+ --prefix=${GPG_PREFIX}
32
+ --with-libgpg-error-prefix=${GPG_PREFIX}
33
+ --with-libassuan-prefix=${GPG_PREFIX}
34
+ --with-libgpg-error-prefix=${GPG_PREFIX}
35
+ --with-libgcrypt-prefix=${GPG_PREFIX}
36
+ --with-libassuan-prefix=${GPG_PREFIX}
37
+ --with-ksba-prefix=${GPG_PREFIX}
38
+ --with-npth-prefix=${GPG_PREFIX}"
39
+
40
+ cache:
41
+ bundler: true
42
+ directories:
43
+ - opt
44
+
45
+ before_install:
46
+ - mkdir -p ${DEPS_PREFIX}
47
+ - pushd ci
48
+ - >
49
+ [ -d "${GPG_PREFIX}" ] ||
50
+ ./install_gpg_all.sh "${GPG_VERSION}"
51
+ --build-dir "${DEPS_BUILD_DIR}/gpg"
52
+ --configure-opts "${GPG_CONFIGURE_OPTS}"
53
+ --folding-style travis
54
+ - popd
55
+ - gem install bundler -v "~> 1.16"
56
+
57
+ install:
58
+ - bundle install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
59
+ - bundle update --jobs=3 --retry=3
60
+
61
+ before_script:
62
+ - gpg --version
63
+ - bundle exec rake pgp_keys:generate
64
+ - bundle exec rake pgp_keys:list
65
+
66
+ matrix:
67
+ include:
68
+ - gemfile: ci/gemfiles/rspec-3.7.gemfile
69
+ rvm: 2.5
70
+ - gemfile: ci/gemfiles/rspec-3.6.gemfile
71
+ rvm: 2.5
72
+ - gemfile: ci/gemfiles/rspec-3.5.gemfile
73
+ rvm: 2.5
74
+ - gemfile: ci/gemfiles/rspec-3.4.gemfile
75
+ rvm: 2.5
76
+ allow_failures:
77
+ - rvm: ruby-head
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # (c) Copyright 2018 Ribose Inc.
2
+ #
3
+
4
+ source "https://rubygems.org"
5
+
6
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
7
+
8
+ # Specify your gem's dependencies in rspec-pgp_matchers.gemspec
9
+ gemspec
10
+
11
+ gem "codecov", require: false, group: :test
12
+ gem "simplecov", require: false, group: :test
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Ribose Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.adoc ADDED
@@ -0,0 +1,114 @@
1
+ = RSpec::PGPMatchers
2
+
3
+ image:https://img.shields.io/gem/v/rspec-pgp_matchers.svg[
4
+ Gem Version, link="https://rubygems.org/gems/rspec-pgp_matchers"]
5
+ image:https://img.shields.io/travis/riboseinc/rspec-pgp_matchers/master.svg[
6
+ Build Status, link="https://travis-ci.org/riboseinc/rspec-pgp_matchers/branches"]
7
+ image:https://img.shields.io/codecov/c/github/riboseinc/rspec-pgp_matchers.svg[
8
+ Test Coverage, link="https://codecov.io/gh/riboseinc/rspec-pgp_matchers"]
9
+ image:https://img.shields.io/codeclimate/maintainability/riboseinc/rspec-pgp_matchers.svg[
10
+ "Code Climate", link="https://codeclimate.com/github/riboseinc/rspec-pgp_matchers"]
11
+
12
+ RSpec matchers for testing PGP-encrypted messages, and signatures.
13
+
14
+ IMPORTANT: This gem calls GnuPG executables internally. However, it does not
15
+ rely on machine-readable interface yet, and may easily break when they change
16
+ something in GnuPG's human-readable output. As long as it is not resolved in
17
+ a better way, we are going to maintain compatibility with the most recent
18
+ versions of GnuPG. At the moment of writing this statement, it is GnuPG 2.2.9.
19
+
20
+ TIP: In order to check which GnuPG version this gem was tested against,
21
+ check out builds in Travis. One of the build steps in a "before script" phase
22
+ executes `gpg --version` to make things clear.
23
+
24
+ == Usage
25
+
26
+ === Getting started
27
+
28
+ 1. Make sure that you have GnuPG 2.2 installed.
29
+
30
+ 2. Add this line to your application’s Gemfile:
31
+ +
32
+ [source,ruby]
33
+ ----
34
+ gem "rspec-pgp_matchers", github: "riboseinc/rspec-pgp_matchers", require: false, group: :test
35
+ ----
36
+
37
+ 3. And following to your spec helper:
38
+ +
39
+ [source,ruby]
40
+ ----
41
+ require "rspec/pgp_matchers"
42
+ RSpec::PGPMatchers.homedir = "path/to/pgp_home_directory/with/development/keys"
43
+ ----
44
+
45
+ === Matching signatures
46
+
47
+ [source,ruby]
48
+ ----
49
+ text = "Some text"
50
+ signer_uid = "mail@example.com"
51
+ someones_uid = "someone@example.com"
52
+
53
+ # Not defined in this gem, but required for this example
54
+ signature = sign_text(text: text, signer: signer_uid, ascii_armor: true)
55
+
56
+ # Both following do pass
57
+ expect(signature).to be_a_valid_pgp_signature_of(text)
58
+ expect(signature).to be_a_valid_pgp_signature_of(text).signed_by(signer_uid)
59
+
60
+ # This one fails
61
+ expect(signature).to be_a_valid_pgp_signature_of(text).signed_by(someones_uid)
62
+ ----
63
+
64
+ === Matching encrypted messages
65
+
66
+ [source,ruby]
67
+ ----
68
+ text = "Some text"
69
+ recipient1_uid = "mail1@example.com"
70
+ recipient2_uid = "mail2@example.com"
71
+ someones_uid = "someone@example.com"
72
+
73
+ # Not defined in this gem, but required for this example
74
+ encrypted = encrypt_text(
75
+ text: text,
76
+ recipients: [recipient1_uid, recipient2_uid],
77
+ ascii_armor: true
78
+ )
79
+
80
+ # Following do pass
81
+ expect(encrypted).to be_a_pgp_encrypted_message
82
+ expect(encrypted).to be_a_pgp_encrypted_message.containing(text)
83
+ expect(encrypted).to be_a_pgp_encrypted_message.encrypted_for(recipient1_uid, recipient2_uid)
84
+
85
+ # This one fails
86
+ expect(encrypted).to be_a_pgp_encrypted_message.encrypted_for(someones_uid)
87
+ ----
88
+
89
+ == Development
90
+
91
+ After checking out the repo, run `bin/setup` to install dependencies.
92
+ Then, run `rake spec` to run the tests. You can also run `bin/console`
93
+ for an interactive prompt that will allow you to experiment.
94
+
95
+ To install this gem onto your local machine, run
96
+ `bundle exec rake install`. To release a new version, update the version
97
+ number in `version.rb`, and then run `bundle exec rake release`, which
98
+ will create a git tag for the version, push git commits and tags, and
99
+ push the `.gem` file to https://rubygems.org[rubygems.org].
100
+
101
+ == Contributing
102
+
103
+ Bug reports and pull requests are welcome on GitHub at
104
+ https://github.com/riboseinc/rspec-pgp_matchers.
105
+
106
+ == Credits
107
+
108
+ This gem is developed, maintained and funded by
109
+ https://www.ribose.com[Ribose Inc].
110
+
111
+ == License
112
+
113
+ The gem is available as open source under the terms of the
114
+ https://opensource.org/licenses/MIT[MIT License].
data/Rakefile ADDED
@@ -0,0 +1,115 @@
1
+ # (c) Copyright 2018 Ribose Inc.
2
+ #
3
+
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
6
+
7
+ require "tempfile"
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :default => :spec
12
+
13
+ namespace :pgp_keys do
14
+ def init_homedir_if_missing
15
+ FileUtils.mkdir_p(TMP_PGP_HOME)
16
+ end
17
+
18
+ def execute_gpg(*options)
19
+ init_homedir_if_missing
20
+ common_options = ["--no-permission-warning", "--homedir", TMP_PGP_HOME]
21
+ cmd = ["gpg", *common_options, *options]
22
+ system(*cmd)
23
+ end
24
+
25
+ # Available parameters for unattended GPG key generation are described here:
26
+ # https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html
27
+ def generate_pgp_keys(key_params)
28
+ Tempfile.create("gnupg-key-params") do |key_params_file|
29
+ key_params_file.write(key_params)
30
+ key_params_file.close
31
+ execute_gpg("--batch", "--gen-key", in: key_params_file.path)
32
+ end
33
+ end
34
+
35
+ desc "Lists keys in tmp/pgp_home"
36
+ task :list => :prepare do
37
+ execute_gpg "--list-keys"
38
+ end
39
+
40
+ desc "Stops all GPG daemons, and deletes tmp/pgp_home"
41
+ task :clear => :prepare do
42
+ if File.exists?(TMP_PGP_HOME)
43
+ system "gpgconf", "--homedir", TMP_PGP_HOME, "--kill", "all"
44
+ FileUtils.remove_entry_secure TMP_PGP_HOME
45
+ end
46
+ end
47
+
48
+ desc "Clears tmp/pgp_home, and generates new set of keys"
49
+ task :regenerate => %i[clear generate]
50
+
51
+ desc "Generates keys in tmp/pgp_home"
52
+ task :generate => :prepare do
53
+ # Key pairs without password
54
+ generate_pgp_keys(<<~KEY_PARAMS)
55
+ %no-protection
56
+ Key-Type: RSA
57
+ Key-Usage: sign, cert
58
+ Key-Length: 2048
59
+ Subkey-Type: RSA
60
+ Subkey-Length: 2048
61
+ Subkey-Usage: encrypt
62
+ Name-Real: Some Arbitrary Key
63
+ Name-Email: whatever@example.test
64
+ Name-Comment: Without passphrase
65
+ Expire-Date: 0
66
+ KEY_PARAMS
67
+
68
+ generate_pgp_keys(<<~KEY_PARAMS)
69
+ %no-protection
70
+ Key-Type: RSA
71
+ Key-Usage: sign, cert
72
+ Key-Length: 2048
73
+ Subkey-Type: RSA
74
+ Subkey-Length: 2048
75
+ Subkey-Usage: encrypt
76
+ Name-Real: Cato Elder
77
+ Name-Email: cato.elder@example.test
78
+ Name-Comment: Without passphrase
79
+ Expire-Date: 0
80
+ KEY_PARAMS
81
+
82
+ generate_pgp_keys(<<~KEY_PARAMS)
83
+ %no-protection
84
+ Key-Type: RSA
85
+ Key-Usage: sign, cert
86
+ Key-Length: 2048
87
+ Subkey-Type: RSA
88
+ Subkey-Length: 2048
89
+ Subkey-Usage: encrypt
90
+ Name-Real: Roman Senate
91
+ Name-Email: senate@example.test
92
+ Name-Comment: Without passphrase
93
+ Expire-Date: 0
94
+ KEY_PARAMS
95
+
96
+ # Password-protected key pairs
97
+ generate_pgp_keys(<<~KEY_PARAMS)
98
+ Key-Type: RSA
99
+ Key-Usage: sign, cert
100
+ Key-Length: 2048
101
+ Subkey-Type: RSA
102
+ Subkey-Length: 2048
103
+ Subkey-Usage: encrypt
104
+ Name-Real: Cato Elder
105
+ Name-Email: cato.elder+pwd@example.test
106
+ Name-Comment: Password-protected
107
+ Expire-Date: 0
108
+ Passphrase: 1234
109
+ KEY_PARAMS
110
+ end
111
+ end
112
+
113
+ task :prepare do
114
+ require_relative "./spec/support/0_tmp_pgp_home"
115
+ end
data/bin/bundle ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end