tfa 0.0.14 → 0.0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 165a204703e889ae75bcd6592b7c0461acab1ab105b938d8d0211e50f74b96d8
4
- data.tar.gz: 1af5e8d49c650b8caf622d83ef1693177da89b1df433b24f267c1132d40e869f
3
+ metadata.gz: 4986f1db7a233768d23cc39c31e8c7f7257c5291b99edc2bb62256dee75c75a6
4
+ data.tar.gz: 9b1421af345917ceee7775fb3f74abef84e7e33394af904199c4a1fbe66fbbb0
5
5
  SHA512:
6
- metadata.gz: 252e06668172e271dd76af579c888fe4906dfe57ec0e2c1f02fec0ac82cf1152c847c16e01e77416cdb1e7c5b4562e96df64de7c3765a57a2813904f58b5e47b
7
- data.tar.gz: 21b407384b87ae6cd58f5ad0593c274880231830772c939fc234208d88082cd88edb0fd1907df195e15067a1ddd9f47502da0682ad7447b80c05f5b267d588e8
6
+ metadata.gz: 32a5d58eddc632ed57af8f8701bd65b61fd3fcc1373ea8ad121f9dbdc650a5351bf62217a66e05a41a57fd6936a67f5855d4322e6243390150452c9cc30a8695
7
+ data.tar.gz: 347a0f07c968bb4b295f0c2caac950a71b68baee36b677efd91d2e8fb360ed9a15201acc9ee8fb26cb1e028d89e51b1508314e60f96d7bf5c719ec385ebd2755
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/mokhan/tfa.svg?branch=v0.0.2)](https://travis-ci.org/mokhan/tfa)
4
4
  [![Code Climate](https://codeclimate.com/github/mokhan/tfa.png)](https://codeclimate.com/github/mokhan/tfa)
5
- [![Gitter chat](https://badges.gitter.im/mokhan/tfa.png)](https://gitter.im/mokhan/tfa)
6
5
 
7
6
  This CLI helps to manage your one time passwords for different accounts/environments.
8
7
  The goal of this tool is to help you generate one time passwords quickly
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require 'tfa'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/tfa ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'tfa'
3
+
4
+ begin
5
+ result = TFA::CLI.start(ARGV)
6
+ puts result unless result.is_a?(IO)
7
+ rescue OpenSSL::Cipher::CipherError => error
8
+ puts error.message
9
+ end
data/lib/tfa.rb CHANGED
@@ -1,7 +1,13 @@
1
+ require "base64"
2
+ require "digest"
3
+ require "json"
4
+ require "openssl"
1
5
  require "pstore"
2
6
  require "rotp"
3
- require "openssl"
4
- require "tfa/version"
5
- require "tfa/totp_command"
6
- require "tfa/storage"
7
+ require "yaml/store"
8
+
7
9
  require "tfa/cli"
10
+ require "tfa/secure_storage"
11
+ require "tfa/storage"
12
+ require "tfa/totp_command"
13
+ require "tfa/version"
data/lib/tfa/cli.rb CHANGED
@@ -4,11 +4,12 @@ module TFA
4
4
  class CLI < Thor
5
5
  package_name "TFA"
6
6
  class_option :filename
7
+ class_option :directory
8
+ class_option :passphrase
7
9
 
8
10
  desc "add NAME SECRET", "add a new secret to the database"
9
11
  def add(name, secret)
10
- secret = clean(secret)
11
- storage.save(name, secret)
12
+ storage.save(name, clean(secret))
12
13
  "Added #{name}"
13
14
  end
14
15
 
@@ -32,10 +33,70 @@ module TFA
32
33
  TotpCommand.new(storage).run('', secret)
33
34
  end
34
35
 
36
+ desc "upgrade", "upgrade the database."
37
+ def upgrade
38
+ if !File.exist?(pstore_path)
39
+ say_status :error, "Unable to detect #{pstore_path}", :red
40
+ return
41
+ end
42
+ if File.exist?(secure_path)
43
+ say_status :error, "The new database format was detected.", :red
44
+ return
45
+ end
46
+
47
+ if yes? "Upgrade to #{secure_path}?"
48
+ secure_storage
49
+ pstore_storage.each do |row|
50
+ row.each do |name, secret|
51
+ secure_storage.save(name, secret) if yes?("Migrate `#{name}`?")
52
+ end
53
+ end
54
+ File.delete(pstore_path) if yes?("Delete `#{pstore_path}`?")
55
+ end
56
+ end
57
+
58
+ desc "encrypt", "encrypts the tfa database"
59
+ def encrypt
60
+ return unless ensure_upgraded!
61
+
62
+ secure_storage.encrypt!
63
+ end
64
+
65
+ desc "decrypt", "decrypts the tfa database"
66
+ def decrypt
67
+ return unless ensure_upgraded!
68
+
69
+ secure_storage.decrypt!
70
+ end
71
+
35
72
  private
36
73
 
37
74
  def storage
38
- @storage ||= Storage.new(filename: options[:filename] || 'tfa')
75
+ File.exist?(pstore_path) ? pstore_storage : secure_storage
76
+ end
77
+
78
+ def pstore_storage
79
+ @pstore_storage ||= Storage.new(pstore_path)
80
+ end
81
+
82
+ def secure_storage
83
+ @secure_storage ||= SecureStorage.new(Storage.new(secure_path), ->{ passphrase })
84
+ end
85
+
86
+ def filename
87
+ options[:filename] || '.tfa'
88
+ end
89
+
90
+ def directory
91
+ options[:directory] || Dir.home
92
+ end
93
+
94
+ def pstore_path
95
+ File.join(directory, "#{filename}.pstore")
96
+ end
97
+
98
+ def secure_path
99
+ File.join(directory, filename)
39
100
  end
40
101
 
41
102
  def clean(secret)
@@ -45,5 +106,26 @@ module TFA
45
106
  secret
46
107
  end
47
108
  end
109
+
110
+ def passphrase
111
+ @passphrase ||=
112
+ begin
113
+ result = options[:passphrase] || ask("Enter passphrase:\n", echo: false)
114
+ raise "Invalid Passphrase" if result.nil? || result.strip.empty?
115
+ result
116
+ end
117
+ end
118
+
119
+ def ensure_upgraded!
120
+ return true if upgraded?
121
+
122
+ error = "Use the `upgrade` command to upgrade your database."
123
+ say_status :error, error, :red
124
+ false
125
+ end
126
+
127
+ def upgraded?
128
+ !File.exist?(pstore_path) && File.exist?(secure_path)
129
+ end
48
130
  end
49
131
  end
@@ -0,0 +1,72 @@
1
+ module TFA
2
+ class SecureStorage
3
+ def initialize(original, passphrase_request)
4
+ @original = original
5
+ @passphrase_request = passphrase_request
6
+ end
7
+
8
+ def encrypt!(algorithm = "AES-256-CBC")
9
+ cipher = OpenSSL::Cipher.new(algorithm)
10
+ cipher.encrypt
11
+ cipher.key = digest
12
+ cipher.iv = iv = cipher.random_iv
13
+ plain_text = IO.read(@original.path)
14
+ json = JSON.generate(
15
+ algorithm: algorithm,
16
+ iv: Base64.encode64(iv),
17
+ cipher_text: Base64.encode64(cipher.update(plain_text) + cipher.final),
18
+ )
19
+ IO.write(@original.path, json)
20
+ end
21
+
22
+ def decrypt!
23
+ data = JSON.parse(IO.read(@original.path), symbolize_names: true)
24
+ decipher = OpenSSL::Cipher.new(data[:algorithm])
25
+ decipher.decrypt
26
+ decipher.key = digest
27
+ decipher.iv = Base64.decode64(data[:iv])
28
+ plain_text = decipher.update(Base64.decode64(data[:cipher_text]))
29
+ IO.write(@original.path, plain_text + decipher.final)
30
+ end
31
+
32
+ def encrypted?
33
+ return false unless File.exist?(@original.path)
34
+ JSON.parse(IO.read(@original.path))
35
+ true
36
+ rescue JSON::ParserError
37
+ false
38
+ end
39
+
40
+ private
41
+
42
+ def method_missing(name, *args, &block)
43
+ super unless @original.respond_to?(name)
44
+
45
+ was_encrypted = encrypted?
46
+ if was_encrypted
47
+ encrypted_content = IO.read(@original.path)
48
+ decrypt!
49
+ original_sha256 = Digest::SHA256.file(@original.path)
50
+ end
51
+ result = @original.public_send(name, *args, &block)
52
+ if was_encrypted
53
+ new_sha256 = Digest::SHA256.file(@original.path)
54
+
55
+ if original_sha256 == new_sha256
56
+ IO.write(@original.path, encrypted_content)
57
+ else
58
+ encrypt!
59
+ end
60
+ end
61
+ result
62
+ end
63
+
64
+ def respond_to_missing?(method, *)
65
+ @original.respond_to?(method)
66
+ end
67
+
68
+ def digest
69
+ @digest ||= Digest::SHA256.digest(@passphrase_request.call)
70
+ end
71
+ end
72
+ end
data/lib/tfa/storage.rb CHANGED
@@ -1,9 +1,16 @@
1
1
  module TFA
2
2
  class Storage
3
3
  include Enumerable
4
-
5
- def initialize(options)
6
- @storage = PStore.new(File.join(Dir.home, ".#{options[:filename]}.pstore"))
4
+ attr_reader :path
5
+
6
+ def initialize(path)
7
+ @path = path
8
+ @storage =
9
+ if ".pstore" == File.extname(path)
10
+ PStore.new(path)
11
+ else
12
+ YAML::Store.new(path)
13
+ end
7
14
  end
8
15
 
9
16
  def each
data/lib/tfa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module TFA
2
- VERSION = "0.0.14".freeze
2
+ VERSION = "0.0.15".freeze
3
3
  end
data/tfa.gemspec CHANGED
@@ -13,14 +13,18 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/mokhan/tfa/"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
22
  spec.require_paths = ["lib"]
23
+ spec.required_ruby_version = "~> 2.0"
20
24
 
21
- spec.add_dependency "rotp"
22
- spec.add_dependency "thor"
25
+ spec.add_dependency "rotp", "~> 3.3"
26
+ spec.add_dependency "thor", "~> 0.20"
23
27
  spec.add_development_dependency "bundler", "~> 1.6"
24
- spec.add_development_dependency "rake"
25
- spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "rake", "~> 12.3"
29
+ spec.add_development_dependency "rspec", "~> 3.7"
26
30
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tfa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-09 00:00:00.000000000 Z
11
+ date: 2018-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rotp
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '3.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '3.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '0.20'
34
34
  type: :runtime
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: '0'
40
+ version: '0.20'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,30 +56,30 @@ dependencies:
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '12.3'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '12.3'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '3.7'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '3.7'
83
83
  description: A CLI to manage your time based one time passwords.
84
84
  email:
85
85
  - mo@mokhan.ca
@@ -95,16 +95,15 @@ files:
95
95
  - LICENSE.txt
96
96
  - README.md
97
97
  - Rakefile
98
- - bin/tfa
98
+ - bin/console
99
+ - bin/setup
100
+ - exe/tfa
99
101
  - lib/tfa.rb
100
102
  - lib/tfa/cli.rb
103
+ - lib/tfa/secure_storage.rb
101
104
  - lib/tfa/storage.rb
102
105
  - lib/tfa/totp_command.rb
103
106
  - lib/tfa/version.rb
104
- - spec/lib/cli_spec.rb
105
- - spec/lib/console_spec.rb
106
- - spec/lib/totp_command_spec.rb
107
- - spec/spec_helper.rb
108
107
  - tfa.gemspec
109
108
  homepage: https://github.com/mokhan/tfa/
110
109
  licenses:
@@ -116,9 +115,9 @@ require_paths:
116
115
  - lib
117
116
  required_ruby_version: !ruby/object:Gem::Requirement
118
117
  requirements:
119
- - - ">="
118
+ - - "~>"
120
119
  - !ruby/object:Gem::Version
121
- version: '0'
120
+ version: '2.0'
122
121
  required_rubygems_version: !ruby/object:Gem::Requirement
123
122
  requirements:
124
123
  - - ">="
@@ -126,12 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
125
  version: '0'
127
126
  requirements: []
128
127
  rubyforge_project:
129
- rubygems_version: 2.7.3
128
+ rubygems_version: 2.7.5
130
129
  signing_key:
131
130
  specification_version: 4
132
131
  summary: A CLI to manage your time based one time passwords.
133
- test_files:
134
- - spec/lib/cli_spec.rb
135
- - spec/lib/console_spec.rb
136
- - spec/lib/totp_command_spec.rb
137
- - spec/spec_helper.rb
132
+ test_files: []
data/bin/tfa DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'tfa'
3
-
4
- puts TFA::CLI.start(ARGV)
data/spec/lib/cli_spec.rb DELETED
@@ -1,87 +0,0 @@
1
- module TFA
2
- describe CLI do
3
- subject { CLI.new }
4
-
5
- def code_for(secret)
6
- ::ROTP::TOTP.new(secret).now
7
- end
8
-
9
- let(:dev_secret) { ::ROTP::Base32.random_base32 }
10
- let(:prod_secret) { ::ROTP::Base32.random_base32 }
11
-
12
- describe "#add" do
13
- context "when a secret is added" do
14
- it "adds the secret" do
15
- subject.add("development", dev_secret)
16
- expect(subject.show("development")).to eql(dev_secret)
17
- end
18
- end
19
-
20
- context "when a full otpauth string is added" do
21
- it "strips out the url for just the secret" do
22
- url = "otpauth://totp/email@email.com?secret=#{dev_secret}&issuer="
23
-
24
- subject.add("development", url)
25
- expect(subject.show("development")).to eql(dev_secret)
26
- end
27
- end
28
- end
29
-
30
- describe "#show" do
31
- context "when a single key is given" do
32
- it "returns the secret" do
33
- subject.add("development", dev_secret)
34
- expect(subject.show("development")).to eql(dev_secret)
35
- end
36
- end
37
-
38
- context "when no key is given" do
39
- it "returns the secret for all keys" do
40
- subject.add("development", dev_secret)
41
- subject.add("production", prod_secret)
42
-
43
- result = subject.show.to_s
44
- expect(result).to include(dev_secret)
45
- expect(result).to include(prod_secret)
46
- end
47
- end
48
- end
49
-
50
- describe "#totp" do
51
- context "when a single key is given" do
52
- it "returns a time based one time password" do
53
- subject.add("development", dev_secret)
54
- expect(subject.totp("development")).to eql(code_for(dev_secret))
55
- end
56
- end
57
-
58
- context "when no key is given" do
59
- it "returns a time based one time password for all keys" do
60
- subject.add("development", dev_secret)
61
- subject.add("production", prod_secret)
62
-
63
- result = subject.totp.to_s
64
- expect(result).to include(code_for(dev_secret))
65
- expect(result).to include(code_for(prod_secret))
66
- end
67
- end
68
- end
69
-
70
- describe "#destroy" do
71
- let(:name) { "development" }
72
-
73
- it "removes the secret with the given name" do
74
- subject.add(name, dev_secret)
75
- subject.destroy(name)
76
-
77
- expect(subject.show(name)).to be_nil
78
- end
79
- end
80
-
81
- describe "#now" do
82
- it "returns a time based one time password for the given secret" do
83
- expect(subject.now(dev_secret)).to eql(code_for(dev_secret))
84
- end
85
- end
86
- end
87
- end
@@ -1,22 +0,0 @@
1
- module TFA
2
- describe CLI do
3
- subject { CLI.new }
4
- let(:secret) { ::ROTP::Base32.random_base32 }
5
-
6
- describe "#run" do
7
- context "when adding a key" do
8
- it "saves a new secret" do
9
- subject.add("development", secret)
10
- expect(subject.show("development")).to eql(secret)
11
- end
12
- end
13
-
14
- context "when getting a one time password" do
15
- it "creates a totp for a certain key" do
16
- subject.add("development", secret)
17
- expect(subject.totp("development")).to_not be_nil
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,55 +0,0 @@
1
- module TFA
2
- describe TotpCommand do
3
- subject { TotpCommand.new(storage) }
4
- let(:storage) { Storage.new(filename: SecureRandom.uuid) }
5
-
6
- def code_for(secret)
7
- ::ROTP::TOTP.new(secret).now
8
- end
9
-
10
- describe "#run" do
11
- context "when a single key is given" do
12
- let(:secret) { ::ROTP::Base32.random_base32 }
13
-
14
- it "returns a time based one time password for the authentication secret given" do
15
- storage.save("development", secret)
16
- expect(subject.run("development")).to eql(code_for(secret))
17
- end
18
- end
19
-
20
- context "when no arguments are given" do
21
- let(:development_secret) { ::ROTP::Base32.random_base32 }
22
- let(:staging_secret) { ::ROTP::Base32.random_base32 }
23
-
24
- it "returns the one time password for all keys" do
25
- storage.save("development", development_secret)
26
- storage.save("staging", staging_secret)
27
-
28
- expect(subject.run(nil)).to match_array([
29
- { "development" => code_for(development_secret) },
30
- { "staging" => code_for(staging_secret) }
31
- ])
32
- end
33
- end
34
-
35
- context "when the key is not known" do
36
- it "returns with nothing" do
37
- expect(subject.run(["blah"])).to be_empty
38
- end
39
- end
40
-
41
- context "when the secret is invalid" do
42
- let(:invalid_secret) { "hello world" }
43
-
44
- before :each do
45
- storage.save("development", invalid_secret)
46
- end
47
-
48
- it "returns an error message" do
49
- expected = { "development" => "INVALID SECRET" }
50
- expect(subject.run(["development"])).to match_array([expected])
51
- end
52
- end
53
- end
54
- end
55
- end
data/spec/spec_helper.rb DELETED
@@ -1,81 +0,0 @@
1
- # This file was generated by the `rspec --init` command. Conventionally, all
2
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
- # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
- # file to always be loaded, without a need to explicitly require it in any files.
5
- #
6
- # Given that it is always loaded, you are encouraged to keep this file as
7
- # light-weight as possible. Requiring heavyweight dependencies from this file
8
- # will add to the boot time of your test suite on EVERY test run, even for an
9
- # individual file that may not need all of that loaded. Instead, make a
10
- # separate helper file that requires this one and then use it only in the specs
11
- # that actually need it.
12
- #
13
- # The `.rspec` file also contains a few flags that are not defaults but that
14
- # users commonly want.
15
- #
16
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
- require 'tfa'
18
- require 'securerandom'
19
- require 'tempfile'
20
- RSpec.configure do |config|
21
- # The settings below are suggested to provide a good initial experience
22
- # with RSpec, but feel free to customize to your heart's content.
23
- =begin
24
- # These two settings work together to allow you to limit a spec run
25
- # to individual examples or groups you care about by tagging them with
26
- # `:focus` metadata. When nothing is tagged with `:focus`, all examples
27
- # get run.
28
- config.filter_run :focus
29
- config.run_all_when_everything_filtered = true
30
-
31
- # Many RSpec users commonly either run the entire suite or an individual
32
- # file, and it's useful to allow more verbose output when running an
33
- # individual spec file.
34
- if config.files_to_run.one?
35
- # Use the documentation formatter for detailed output,
36
- # unless a formatter has already been configured
37
- # (e.g. via a command-line flag).
38
- config.default_formatter = 'doc'
39
- end
40
-
41
- # Print the 10 slowest examples and example groups at the
42
- # end of the spec run, to help surface which specs are running
43
- # particularly slow.
44
- config.profile_examples = 10
45
-
46
- # Run specs in random order to surface order dependencies. If you find an
47
- # order dependency and want to debug it, you can fix the order by providing
48
- # the seed, which is printed after each run.
49
- # --seed 1234
50
- config.order = :random
51
-
52
- # Seed global randomization in this process using the `--seed` CLI option.
53
- # Setting this allows you to use `--seed` to deterministically reproduce
54
- # test failures related to randomization by passing the same `--seed` value
55
- # as the one that triggered the failure.
56
- Kernel.srand config.seed
57
-
58
- # rspec-expectations config goes here. You can use an alternate
59
- # assertion/expectation library such as wrong or the stdlib/minitest
60
- # assertions if you prefer.
61
- config.expect_with :rspec do |expectations|
62
- # Enable only the newer, non-monkey-patching expect syntax.
63
- # For more details, see:
64
- # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
65
- expectations.syntax = :expect
66
- end
67
-
68
- # rspec-mocks config goes here. You can use an alternate test double
69
- # library (such as bogus or mocha) by changing the `mock_with` option here.
70
- config.mock_with :rspec do |mocks|
71
- # Enable only the newer, non-monkey-patching expect syntax.
72
- # For more details, see:
73
- # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
74
- mocks.syntax = :expect
75
-
76
- # Prevents you from mocking or stubbing a method that does not exist on
77
- # a real object. This is generally recommended.
78
- mocks.verify_partial_doubles = true
79
- end
80
- =end
81
- end