mellon 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +5 -5
- data/Rakefile +3 -0
- data/lib/mellon.rb +0 -1
- data/lib/mellon/keychain.rb +8 -7
- data/lib/mellon/store.rb +5 -0
- data/lib/mellon/utils.rb +45 -0
- data/lib/mellon/version.rb +1 -1
- data/mellon.gemspec +1 -0
- data/spec/mellon/keychain_spec.rb +109 -37
- data/spec/mellon/store_spec.rb +31 -21
- data/spec/mellon_spec.rb +1 -1
- data/spec/spec_helper.rb +12 -8
- metadata +18 -4
- data/lib/mellon/shell_utils.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76d1c2268781b0099e7c924852a17bfbe0f52fa6
|
4
|
+
data.tar.gz: 108c0fa6d05f1f87307fcc52e9c15738b83b9c32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d17a055a2d6f33bb9099bdfca03cee93e0b6ee70ab133b4ae9e749a115319af8f373d72632698c1a500f87d73d701f484d8db4acf9cb9581098ef113d3ed1c59
|
7
|
+
data.tar.gz: b3ec39f219f671ff33ffb60a14f6f73eee5cbb10551e2f3a66c119acacd043da68dd4845c41721ccd36fcd2537c0674633cecd473ba53f6fab2b42a9c58bc42e
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
[HEAD][]
|
2
2
|
--------
|
3
3
|
|
4
|
+
[v1.2.0][]
|
5
|
+
----------
|
6
|
+
|
7
|
+
- Add Mellon::Store#to_h (47523c2f)
|
8
|
+
- Add more verbosity when $DEBUG is set (29b97367)
|
9
|
+
- Match only keychain name in Keychain.find (44693409) [closes #5]
|
10
|
+
|
4
11
|
[v1.1.1][]
|
5
12
|
----------
|
6
13
|
|
@@ -21,7 +28,8 @@
|
|
21
28
|
|
22
29
|
Initial release!
|
23
30
|
|
24
|
-
[HEAD]: https://github.com/elabs/mellon/compare/v1.
|
31
|
+
[HEAD]: https://github.com/elabs/mellon/compare/v1.2.0...HEAD
|
32
|
+
[v1.2.0]: https://github.com/elabs/mellon/compare/v1.1.1...v1.2.0
|
25
33
|
[v1.1.1]: https://github.com/elabs/mellon/compare/v1.1.0...v1.1.1
|
26
34
|
[v1.1.0]: https://github.com/elabs/mellon/compare/v1.0.0...v1.1.0
|
27
35
|
[v1.0.0]: https://github.com/elabs/mellon/compare/24b83977d...v1.0.0
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ See instructions over at [econfig-keychain](https://github.com/elabs/econfig-key
|
|
32
32
|
|
33
33
|
# Documentation
|
34
34
|
|
35
|
-
An API reference can be found at [
|
35
|
+
An API reference can be found at [rubydoc.info/github/elabs/mellon](http://www.rubydoc.info/github/elabs/mellon/).
|
36
36
|
|
37
37
|
## Mellon::Keychain
|
38
38
|
|
@@ -46,7 +46,7 @@ keychain["ruby note"] # => "Hello from Ruby!"
|
|
46
46
|
keychain["ruby note"] = nil # deletes keychain note `ruby note`
|
47
47
|
```
|
48
48
|
|
49
|
-
More documentation can be found at the [API reference for Mellon::Keychain](http://
|
49
|
+
More documentation can be found at the [API reference for Mellon::Keychain](http://www.rubydoc.info/github/elabs/mellon/Mellon/Keychain).
|
50
50
|
|
51
51
|
## Mellon::Store
|
52
52
|
|
@@ -63,7 +63,7 @@ store["some key"] # => "Hello from Ruby!"
|
|
63
63
|
store.keychain[store.project_name] # => "---\nsome key: Hello from Ruby!\n"
|
64
64
|
```
|
65
65
|
|
66
|
-
More documentation can be found at the [API reference for Mellon::Store](http://
|
66
|
+
More documentation can be found at the [API reference for Mellon::Store](http://www.rubydoc.info/github/elabs/mellon/Mellon/Store).
|
67
67
|
|
68
68
|
## Command-line interface
|
69
69
|
|
@@ -75,5 +75,5 @@ When you install the Mellon gem you also get an executable called `mellon`. See
|
|
75
75
|
|
76
76
|
[Elabs]: http://www.elabs.se/
|
77
77
|
[elabs logo]: ./elabs-logo.png?raw=true
|
78
|
-
[Mellon::Keychain]: #
|
79
|
-
[Mellon::Store]: #
|
78
|
+
[Mellon::Keychain]: #mellonkeychain
|
79
|
+
[Mellon::Store]: #mellonstore
|
data/Rakefile
CHANGED
data/lib/mellon.rb
CHANGED
data/lib/mellon/keychain.rb
CHANGED
@@ -11,7 +11,7 @@ module Mellon
|
|
11
11
|
# @param [String] key
|
12
12
|
# @return [Keychain, nil]
|
13
13
|
def search(key)
|
14
|
-
output =
|
14
|
+
output = Utils.security("find-generic-password", "-l", key)
|
15
15
|
new(output[/keychain: "(.+)"/i, 1], ensure_exists: false)
|
16
16
|
rescue CommandError => e
|
17
17
|
raise unless e.message =~ ENTRY_MISSING
|
@@ -26,13 +26,14 @@ module Mellon
|
|
26
26
|
def find(name)
|
27
27
|
quoted = Regexp.quote(name)
|
28
28
|
regexp = Regexp.new(quoted, Regexp::IGNORECASE)
|
29
|
+
keychains = list
|
29
30
|
|
30
|
-
keychain =
|
31
|
-
keychain.
|
31
|
+
keychain = keychains.find do |keychain|
|
32
|
+
keychain.name =~ regexp
|
32
33
|
end
|
33
34
|
|
34
35
|
if keychain.nil?
|
35
|
-
raise KeyError, "Could not find keychain “#{name}” in #{
|
36
|
+
raise KeyError, "Could not find keychain “#{name}” in #{keychains.map(&:name).join(", ")}"
|
36
37
|
end
|
37
38
|
|
38
39
|
keychain
|
@@ -40,13 +41,13 @@ module Mellon
|
|
40
41
|
|
41
42
|
# @return [Keychain] default keychain
|
42
43
|
def default
|
43
|
-
keychain_path =
|
44
|
+
keychain_path = Utils.security("default-keychain")[KEYCHAIN_REGEXP, 1]
|
44
45
|
new(keychain_path, ensure_exists: false)
|
45
46
|
end
|
46
47
|
|
47
48
|
# @return [Array<Keychain>] all available keychains
|
48
49
|
def list
|
49
|
-
|
50
|
+
Utils.security("list-keychains").scan(KEYCHAIN_REGEXP).map do |(keychain_path)|
|
50
51
|
new(keychain_path, ensure_exists: false)
|
51
52
|
end
|
52
53
|
end
|
@@ -197,7 +198,7 @@ module Mellon
|
|
197
198
|
# @param [Array<String>] command
|
198
199
|
def command(*command, &block)
|
199
200
|
command += [path]
|
200
|
-
|
201
|
+
Utils.security *command, &block
|
201
202
|
end
|
202
203
|
end
|
203
204
|
end
|
data/lib/mellon/store.rb
CHANGED
data/lib/mellon/utils.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "shellwords"
|
3
|
+
|
1
4
|
module Mellon
|
5
|
+
# @api private
|
2
6
|
module Utils
|
3
7
|
module_function
|
4
8
|
|
@@ -88,5 +92,46 @@ module Mellon
|
|
88
92
|
password
|
89
93
|
end
|
90
94
|
end
|
95
|
+
|
96
|
+
# @see #sh
|
97
|
+
def security(*command, &block)
|
98
|
+
sh("security", *command, &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @overload sh(*command, &block)
|
102
|
+
# Yields stdout and stderr to the given block.
|
103
|
+
#
|
104
|
+
# @overload sh(*command)
|
105
|
+
# Returns stdout.
|
106
|
+
#
|
107
|
+
# @raise [CommandError] if command exited with a non-zero exit status.
|
108
|
+
def sh(*command)
|
109
|
+
$stderr.puts "$ " + command.join(" ") if $VERBOSE
|
110
|
+
stdout, stderr, status = Open3.capture3(*command)
|
111
|
+
|
112
|
+
stdout.chomp!
|
113
|
+
stderr.chomp!
|
114
|
+
|
115
|
+
if $DEBUG
|
116
|
+
$stderr.puts stdout.gsub(/(?<=\n|\A)/, "--> ") unless stdout.empty?
|
117
|
+
$stderr.puts stderr.gsub(/(?<=\n|\A)/, "--! ") unless stderr.empty?
|
118
|
+
end
|
119
|
+
|
120
|
+
unless status.success?
|
121
|
+
error_string = Shellwords.join(command)
|
122
|
+
error_string << "\n"
|
123
|
+
|
124
|
+
stderr = "<no output>" if stderr.empty?
|
125
|
+
error_string << " " << stderr.chomp
|
126
|
+
|
127
|
+
raise CommandError, "[ERROR] #{error_string}"
|
128
|
+
end
|
129
|
+
|
130
|
+
if block_given?
|
131
|
+
yield [stdout, stderr]
|
132
|
+
else
|
133
|
+
stdout
|
134
|
+
end
|
135
|
+
end
|
91
136
|
end
|
92
137
|
end
|
data/lib/mellon/version.rb
CHANGED
data/mellon.gemspec
CHANGED
@@ -3,27 +3,108 @@ describe Mellon::Keychain do
|
|
3
3
|
Mellon::Keychain.new(keychain_path)
|
4
4
|
end
|
5
5
|
|
6
|
+
describe ".search" do
|
7
|
+
it "returns the first keychain that contains the requested entry" do
|
8
|
+
stub_command "security find-generic-password -l booboom", stdout: <<-STDOUT
|
9
|
+
keychain: "/Users/dev/Library/Keychains/projects.keychain"
|
10
|
+
class: "genp"
|
11
|
+
attributes:
|
12
|
+
0x00000007 <blob>="booboom"
|
13
|
+
0x00000008 <blob>=<NULL>
|
14
|
+
"acct"<blob>=<NULL>
|
15
|
+
"cdat"<timedate>=0x32303135303132333037343035395A00 "20150123074059Z\000"
|
16
|
+
"crtr"<uint32>=<NULL>
|
17
|
+
"cusi"<sint32>=<NULL>
|
18
|
+
"desc"<blob>="secure note"
|
19
|
+
"gena"<blob>=<NULL>
|
20
|
+
"icmt"<blob>=<NULL>
|
21
|
+
"invi"<sint32>=<NULL>
|
22
|
+
"mdat"<timedate>=0x32303135303132333037343035395A00 "20150123074059Z\000"
|
23
|
+
"nega"<sint32>=<NULL>
|
24
|
+
"prot"<blob>=<NULL>
|
25
|
+
"scrp"<sint32>=<NULL>
|
26
|
+
"svce"<blob>="booboom"
|
27
|
+
"type"<uint32>="note"
|
28
|
+
STDOUT
|
29
|
+
|
30
|
+
keychain = Mellon::Keychain.search "booboom"
|
31
|
+
expect(keychain.path).to eq "/Users/dev/Library/Keychains/projects.keychain"
|
32
|
+
expect(keychain.name).to eq "projects"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns nil if the entry is missing" do
|
36
|
+
stub_command "security find-generic-password -l booboom", error: true, stderr: <<-STDERR
|
37
|
+
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.
|
38
|
+
STDERR
|
39
|
+
|
40
|
+
keychain = Mellon::Keychain.search "booboom"
|
41
|
+
expect(keychain).to eq nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".find" do
|
46
|
+
before do
|
47
|
+
stub_command "security list-keychains", stdout: <<-STDOUT
|
48
|
+
"/Users/dev/Library/Keychains/login.keychain"
|
49
|
+
"/Users/dev/Library/Keychains/projects.keychain"
|
50
|
+
"/Users/dev/Library/Keychains/developer.keychain"
|
51
|
+
"/Library/Keychains/System.keychain"
|
52
|
+
STDOUT
|
53
|
+
end
|
54
|
+
|
55
|
+
it "finds a keychain matching the given name" do
|
56
|
+
keychain = Mellon::Keychain.find("dev")
|
57
|
+
expect(keychain.name).to eq "developer"
|
58
|
+
expect(keychain.path).to eq "/Users/dev/Library/Keychains/developer.keychain"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises an error if no keychain was found" do
|
62
|
+
expect { Mellon::Keychain.find("bar") }.to raise_error(KeyError, /Could not find keychain/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
specify ".list" do
|
67
|
+
stub_command "security list-keychains", stdout: <<-STDOUT
|
68
|
+
"/Users/dev/Library/Keychains/login.keychain"
|
69
|
+
"/Users/dev/Library/Keychains/projects.keychain"
|
70
|
+
"/Users/dev/Library/Keychains/developer.keychain"
|
71
|
+
"/Library/Keychains/System.keychain"
|
72
|
+
STDOUT
|
73
|
+
|
74
|
+
expect(Mellon::Keychain.list.map(&:name)).to contain_exactly("login", "projects", "developer", "System")
|
75
|
+
end
|
76
|
+
|
77
|
+
specify ".default" do
|
78
|
+
stub_command "security default-keychain", stdout: <<-STDOUT
|
79
|
+
"/Users/dev/Library/Keychains/login.keychain"
|
80
|
+
STDOUT
|
81
|
+
|
82
|
+
default = Mellon::Keychain.default
|
83
|
+
expect(default.path).to eq "/Users/dev/Library/Keychains/login.keychain"
|
84
|
+
expect(default.name).to eq "login"
|
85
|
+
end
|
86
|
+
|
6
87
|
specify "#name" do
|
7
|
-
keychain.name.
|
88
|
+
expect(keychain.name).to eq "temporary_keychain"
|
8
89
|
end
|
9
90
|
|
10
91
|
specify "#path" do
|
11
|
-
keychain.path.
|
92
|
+
expect(keychain.path).to eq keychain_path
|
12
93
|
end
|
13
94
|
|
14
95
|
specify "keychain can be stored in hash" do
|
15
96
|
hash = {}
|
16
97
|
hash[keychain] = "some value"
|
17
|
-
hash[Mellon::Keychain.new(keychain.path)].
|
98
|
+
expect(hash[Mellon::Keychain.new(keychain.path)]).to eq "some value"
|
18
99
|
end
|
19
100
|
|
20
101
|
describe "#==" do
|
21
102
|
it "is equal to another keychain with same path" do
|
22
|
-
keychain.
|
103
|
+
expect(keychain).to eq Mellon::Keychain.new(keychain.path)
|
23
104
|
end
|
24
105
|
|
25
106
|
it "is not equal to any other object" do
|
26
|
-
keychain.
|
107
|
+
expect(keychain).to_not eq({})
|
27
108
|
end
|
28
109
|
end
|
29
110
|
|
@@ -35,31 +116,31 @@ describe Mellon::Keychain do
|
|
35
116
|
|
36
117
|
describe "#keys" do
|
37
118
|
it "lists all keys available in the keychain" do
|
38
|
-
keychain.keys.
|
119
|
+
expect(keychain.keys).to contain_exactly("simple", "existing", "encoded", "plist", "empty", "doomed", "json store", "yaml store")
|
39
120
|
end
|
40
121
|
end
|
41
122
|
|
42
123
|
describe "#fetch" do
|
43
124
|
it "delegates (and as such, behaves equally) to #[]" do
|
44
|
-
keychain.
|
45
|
-
keychain.fetch("simple").
|
125
|
+
expect(keychain).to receive(:[]).with("simple").and_call_original
|
126
|
+
expect(keychain.fetch("simple")).to eq "Simple note"
|
46
127
|
end
|
47
128
|
|
48
129
|
describe "behaves like Hash#fetch" do
|
49
130
|
specify "when key exists" do
|
50
|
-
keychain.fetch("simple", nil).
|
51
|
-
keychain.fetch("simple", "default value").
|
52
|
-
keychain.fetch("simple", "default value") { "block value" }.
|
53
|
-
keychain.fetch("simple") { "block value" }.
|
131
|
+
expect(keychain.fetch("simple", nil)).to eq "Simple note"
|
132
|
+
expect(keychain.fetch("simple", "default value")).to eq "Simple note"
|
133
|
+
expect(keychain.fetch("simple", "default value") { "block value" }).to eq "Simple note"
|
134
|
+
expect(keychain.fetch("simple") { "block value" }).to eq "Simple note"
|
54
135
|
|
55
|
-
keychain.fetch("simple").
|
136
|
+
expect(keychain.fetch("simple")).to eq "Simple note"
|
56
137
|
end
|
57
138
|
|
58
139
|
specify "when key does not exist" do
|
59
|
-
keychain.fetch("missing", nil).
|
60
|
-
keychain.fetch("missing", "default value").
|
61
|
-
keychain.fetch("missing", "default value") { "block value" }.
|
62
|
-
keychain.fetch("missing") { "block value" }.
|
140
|
+
expect(keychain.fetch("missing", nil)).to eq nil
|
141
|
+
expect(keychain.fetch("missing", "default value")).to eq "default value"
|
142
|
+
expect(keychain.fetch("missing", "default value") { "block value" }).to eq "block value"
|
143
|
+
expect(keychain.fetch("missing") { "block value" }).to eq "block value"
|
63
144
|
|
64
145
|
expect { keychain.fetch("missing") }.to raise_error(KeyError)
|
65
146
|
end
|
@@ -68,52 +149,43 @@ describe Mellon::Keychain do
|
|
68
149
|
|
69
150
|
describe "#[key]" do
|
70
151
|
it "reads simple entries" do
|
71
|
-
keychain["simple"].
|
152
|
+
expect(keychain["simple"]).to eq "Simple note"
|
72
153
|
end
|
73
154
|
|
74
155
|
it "reads encoded entries" do
|
75
|
-
keychain["encoded"].
|
156
|
+
expect(keychain["encoded"]).to eq "Encoded\nnote"
|
76
157
|
end
|
77
158
|
|
78
159
|
it "reads plist entries" do
|
79
|
-
keychain["plist"].
|
160
|
+
expect(keychain["plist"]).to eq "Plist note."
|
80
161
|
end
|
81
162
|
|
82
163
|
it "reads empty entries" do
|
83
|
-
keychain["empty"].
|
164
|
+
expect(keychain["empty"]).to eq ""
|
84
165
|
end
|
85
166
|
|
86
167
|
it "returns nil when there is no entry with the given name" do
|
87
|
-
keychain["nonexisting note"].
|
88
|
-
end
|
89
|
-
|
90
|
-
it "raises an error when command exits for a reason other than key missing" do
|
91
|
-
error = Mellon::CommandError.new(<<-ERROR)
|
92
|
-
security find-generic-password -g -l unreadable /Users/dev/Projects/mellon/spec/temporary_keychain.keychain
|
93
|
-
security: SecKeychainItemCopyAccess: In dark wake, no UI possible
|
94
|
-
ERROR
|
95
|
-
Mellon::ShellUtils.should_receive(:sh).and_raise(error)
|
96
|
-
expect { keychain["simple"] }.to raise_error(Mellon::CommandError, /dark wake/)
|
168
|
+
expect(keychain["nonexisting note"]).to be_nil
|
97
169
|
end
|
98
170
|
end
|
99
171
|
|
100
172
|
describe "#[]=" do
|
101
173
|
it "can create a new note" do
|
102
|
-
keychain["new note"].
|
174
|
+
expect(keychain["new note"]).to be_nil
|
103
175
|
keychain["new note"] = "This is new data"
|
104
|
-
keychain["new note"].
|
176
|
+
expect(keychain["new note"]).to eq "This is new data"
|
105
177
|
end
|
106
178
|
|
107
179
|
it "can write data to an existing note" do
|
108
|
-
keychain["existing"].
|
180
|
+
expect(keychain["existing"]).to eq "Existing note."
|
109
181
|
keychain["existing"] = "This is new"
|
110
|
-
keychain["existing"].
|
182
|
+
expect(keychain["existing"]).to eq "This is new"
|
111
183
|
end
|
112
184
|
|
113
185
|
it "can delete an existing note" do
|
114
|
-
keychain["doomed"].
|
186
|
+
expect(keychain["doomed"]).to_not be_nil
|
115
187
|
keychain["doomed"] = nil
|
116
|
-
keychain["doomed"].
|
188
|
+
expect(keychain["doomed"]).to be_nil
|
117
189
|
end
|
118
190
|
end
|
119
191
|
end
|
data/spec/mellon/store_spec.rb
CHANGED
@@ -9,75 +9,85 @@ describe Mellon::Store do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it "finds and uses the keychain containing the project name by default" do
|
12
|
-
Mellon::Keychain.
|
13
|
-
Mellon::Store.new(project_name).keychain.
|
12
|
+
expect(Mellon::Keychain).to receive(:search).with(project_name).and_return(keychain)
|
13
|
+
expect(Mellon::Store.new(project_name).keychain).to eq keychain
|
14
14
|
end
|
15
15
|
|
16
16
|
it "uses the default keychain is no keychain contains the project name" do
|
17
17
|
keychain = double
|
18
|
-
Mellon::Keychain.
|
19
|
-
Mellon::Keychain.
|
20
|
-
Mellon::Store.new(project_name).keychain.
|
18
|
+
expect(Mellon::Keychain).to receive(:search).with(project_name).and_return(nil)
|
19
|
+
expect(Mellon::Keychain).to receive(:default).and_return(keychain)
|
20
|
+
expect(Mellon::Store.new(project_name).keychain).to eq keychain
|
21
21
|
end
|
22
22
|
|
23
23
|
it "accepts specifying the keychain by name" do
|
24
24
|
keychain = double
|
25
|
-
Mellon::Keychain.
|
25
|
+
expect(Mellon::Keychain).to receive(:find).with("projects").and_return(keychain)
|
26
26
|
store = Mellon::Store.new(project_name, keychain: "projects")
|
27
|
-
store.keychain.
|
27
|
+
expect(store.keychain).to eq keychain
|
28
28
|
end
|
29
29
|
|
30
30
|
it "accepts specifying the keychain object" do
|
31
31
|
store = Mellon::Store.new(project_name, keychain: keychain)
|
32
|
-
store.keychain.
|
32
|
+
expect(store.keychain).to eq keychain
|
33
33
|
end
|
34
34
|
|
35
35
|
it "allows setting the serializer" do
|
36
36
|
require "json"
|
37
37
|
store = Mellon::Store.new("json store", keychain: keychain, serializer: JSON)
|
38
|
-
store["some value"].
|
38
|
+
expect(store["some value"]).to eq "This is some json value"
|
39
39
|
store["some value"] = "New value"
|
40
|
-
store["some value"].
|
40
|
+
expect(store["some value"]).to eq "New value"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
describe "#[]" do
|
45
45
|
it "returns the value for key inside the store" do
|
46
|
-
store["some value"].
|
46
|
+
expect(store["some value"]).to eq "This is some yaml value"
|
47
47
|
end
|
48
48
|
|
49
49
|
it "returns nil if store entry does not exist" do
|
50
50
|
store = Mellon::Store.new("missing project", keychain: keychain)
|
51
|
-
store["some value"].
|
51
|
+
expect(store["some value"]).to be_nil
|
52
52
|
end
|
53
53
|
|
54
54
|
it "returns nil if keychain item is empty" do
|
55
55
|
store = Mellon::Store.new("empty", keychain: keychain)
|
56
|
-
store["some value"].
|
56
|
+
expect(store["some value"]).to be_nil
|
57
57
|
store["some value"] = "New value"
|
58
|
-
store["some value"].
|
58
|
+
expect(store["some value"]).to eq "New value"
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
62
|
describe "#[]=" do
|
63
63
|
it "assigns an existing value for key inside the store" do
|
64
|
-
store["some value"].
|
64
|
+
expect(store["some value"]).to eq "This is some yaml value"
|
65
65
|
store["some value"] = "This is a new value"
|
66
|
-
store["some value"].
|
66
|
+
expect(store["some value"]).to eq "This is a new value"
|
67
67
|
end
|
68
68
|
|
69
69
|
it "creates the store entry if it does not exist" do
|
70
70
|
store = Mellon::Store.new("missing project", keychain: keychain)
|
71
|
-
store["some value"].
|
71
|
+
expect(store["some value"]).to be_nil
|
72
72
|
store["some value"] = "That value"
|
73
|
-
store["some value"].
|
73
|
+
expect(store["some value"]).to eq "That value"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#to_h" do
|
78
|
+
it "returns a hash with all keys contained" do
|
79
|
+
store["new value"] = "This is new value"
|
80
|
+
expect(store.to_h).to eq({
|
81
|
+
"some value" => "This is some yaml value",
|
82
|
+
"new value" => "This is new value"
|
83
|
+
})
|
74
84
|
end
|
75
85
|
end
|
76
86
|
|
77
87
|
specify "#fetch" do
|
78
|
-
store.fetch("some value").
|
79
|
-
store.fetch("missing value", "default").
|
80
|
-
store.fetch("missing value") { "default" }.
|
88
|
+
expect(store.fetch("some value")).to eq "This is some yaml value"
|
89
|
+
expect(store.fetch("missing value", "default")).to eq "default"
|
90
|
+
expect(store.fetch("missing value") { "default" }).to eq "default"
|
81
91
|
|
82
92
|
expect { store.fetch("missing value") }.to raise_error(KeyError)
|
83
93
|
end
|
data/spec/mellon_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -6,14 +6,6 @@ keychain_path = File.expand_path("./temporary_keychain.keychain", __dir__)
|
|
6
6
|
original_keychain_path = File.expand_path("./keychain.keychain", __dir__)
|
7
7
|
|
8
8
|
RSpec.configure do |config|
|
9
|
-
config.expect_with :rspec do |c|
|
10
|
-
c.syntax = [:expect, :should]
|
11
|
-
end
|
12
|
-
|
13
|
-
config.mock_with :rspec do |c|
|
14
|
-
c.syntax = :should
|
15
|
-
end
|
16
|
-
|
17
9
|
config.around do |example|
|
18
10
|
FileUtils.cp(original_keychain_path, keychain_path)
|
19
11
|
example.run
|
@@ -23,4 +15,16 @@ RSpec.configure do |config|
|
|
23
15
|
define_method :keychain_path do
|
24
16
|
keychain_path
|
25
17
|
end
|
18
|
+
|
19
|
+
config.include(Module.new do
|
20
|
+
def stub_command(command, stdout: "", stderr: "", error: false)
|
21
|
+
status = if error
|
22
|
+
double("success?" => false)
|
23
|
+
else
|
24
|
+
double("success?" => true)
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(Open3).to receive(:capture3).with(*command.split(" ")).and_return([stdout, stderr, status])
|
28
|
+
end
|
29
|
+
end)
|
26
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mellon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kim Burgestrand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: plist
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description:
|
98
112
|
email:
|
99
113
|
- kim@burgestrand.se
|
@@ -113,7 +127,6 @@ files:
|
|
113
127
|
- elabs-logo.png
|
114
128
|
- lib/mellon.rb
|
115
129
|
- lib/mellon/keychain.rb
|
116
|
-
- lib/mellon/shell_utils.rb
|
117
130
|
- lib/mellon/store.rb
|
118
131
|
- lib/mellon/utils.rb
|
119
132
|
- lib/mellon/version.rb
|
@@ -143,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
156
|
version: '0'
|
144
157
|
requirements: []
|
145
158
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.
|
159
|
+
rubygems_version: 2.4.5
|
147
160
|
signing_key:
|
148
161
|
specification_version: 4
|
149
162
|
summary: A command-line utility for managing secret application credentials via OSX
|
@@ -154,3 +167,4 @@ test_files:
|
|
154
167
|
- spec/mellon/store_spec.rb
|
155
168
|
- spec/mellon_spec.rb
|
156
169
|
- spec/spec_helper.rb
|
170
|
+
has_rdoc:
|
data/lib/mellon/shell_utils.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require "open3"
|
2
|
-
require "shellwords"
|
3
|
-
|
4
|
-
module Mellon
|
5
|
-
module ShellUtils
|
6
|
-
module_function
|
7
|
-
|
8
|
-
def security(*command, &block)
|
9
|
-
sh("security", *command, &block)
|
10
|
-
end
|
11
|
-
|
12
|
-
def sh(*command)
|
13
|
-
$stderr.puts command.join(" ") if $VERBOSE
|
14
|
-
stdout, stderr, status = Open3.capture3(*command)
|
15
|
-
|
16
|
-
stdout.chomp!
|
17
|
-
stderr.chomp!
|
18
|
-
|
19
|
-
unless status.success?
|
20
|
-
error_string = Shellwords.join(command)
|
21
|
-
error_string << "\n"
|
22
|
-
|
23
|
-
stderr = "<no output>" if stderr.empty?
|
24
|
-
error_string << " " << stderr.chomp
|
25
|
-
|
26
|
-
raise CommandError, "[ERROR] #{error_string}"
|
27
|
-
end
|
28
|
-
|
29
|
-
if block_given?
|
30
|
-
yield [stdout, stderr]
|
31
|
-
else
|
32
|
-
stdout
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|