boxen 2.7.1 → 2.7.2
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.
- data/boxen.gemspec +2 -2
- data/lib/boxen/preflight/creds.rb +47 -6
- data/test/boxen_preflight_creds_test.rb +97 -0
- metadata +7 -6
data/boxen.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "boxen"
|
5
|
-
gem.version = "2.7.
|
5
|
+
gem.version = "2.7.2"
|
6
6
|
gem.authors = ["John Barnette", "Will Farrington", "David Goodlad"]
|
7
7
|
gem.email = ["jbarnette@github.com", "wfarr@github.com", "dgoodlad@github.com"]
|
8
8
|
gem.description = "Manage Mac development boxes with love (and Puppet)."
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
|
17
17
|
gem.add_dependency "ansi", "~> 1.4"
|
18
18
|
gem.add_dependency "hiera", "~> 1.0"
|
19
|
-
gem.add_dependency "highline", "~> 1.6"
|
19
|
+
gem.add_dependency "highline", "~> 1.6.0"
|
20
20
|
gem.add_dependency "json_pure", [">= 1.7.7", "< 2.0"]
|
21
21
|
gem.add_dependency "librarian-puppet", "~> 1.0.0"
|
22
22
|
gem.add_dependency "octokit", "~> 2.7", ">= 2.7.1"
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "boxen/preflight"
|
2
2
|
require "highline"
|
3
3
|
require "octokit"
|
4
|
+
require "digest"
|
5
|
+
require "socket"
|
4
6
|
|
5
7
|
# HACK: Unless this is `false`, HighLine has some really bizarre
|
6
8
|
# problems with empty/expended streams at bizarre intervals.
|
@@ -68,12 +70,27 @@ class Boxen::Preflight::Creds < Boxen::Preflight
|
|
68
70
|
fetch_login_and_password
|
69
71
|
tokens = get_tokens
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
# Boxen now supports the updated GitHub Authorizations API by using a unique
|
74
|
+
# `fingerprint` for each Boxen installation for a user. We delete any older
|
75
|
+
# authorization that does not make use of `fingerprint` so that the "legacy"
|
76
|
+
# authorization doesn't persist in the user's list of personal access
|
77
|
+
# tokens.
|
78
|
+
legacy_auth = tokens.detect { |a| a.note == "Boxen" && a.fingerprint == nil }
|
79
|
+
tmp_api.delete_authorization(legacy_auth.id, :headers => headers) if legacy_auth
|
80
|
+
|
81
|
+
# The updated GitHub authorizations API, in order to improve security, no
|
82
|
+
# longer returns a plaintext `token` for existing authorizations. So, if an
|
83
|
+
# authorization already exists for this machine we need to first delete it
|
84
|
+
# so that we can create a new one.
|
85
|
+
auth = tokens.detect { |a| a.note == note && a.fingerprint == fingerprint }
|
86
|
+
tmp_api.delete_authorization(auth.id, :headers => headers) if auth
|
87
|
+
|
88
|
+
auth = tmp_api.create_authorization(
|
89
|
+
:note => note,
|
90
|
+
:scopes => %w(repo user),
|
91
|
+
:fingerprint => fingerprint,
|
92
|
+
:headers => headers
|
93
|
+
)
|
77
94
|
|
78
95
|
config.token = auth.token
|
79
96
|
|
@@ -105,4 +122,28 @@ class Boxen::Preflight::Creds < Boxen::Preflight
|
|
105
122
|
warn "Oh, looks like you've provided your #{thing} as environmental variable..."
|
106
123
|
found
|
107
124
|
end
|
125
|
+
|
126
|
+
def fingerprint
|
127
|
+
@fingerprint ||= begin
|
128
|
+
# See Apple technical note TN1103, "Uniquely Identifying a Macintosh
|
129
|
+
# Computer."
|
130
|
+
serial_number_match_data = IO.popen(
|
131
|
+
["ioreg", "-c", "IOPlatformExpertDevice", "-d", "2"]
|
132
|
+
).read.match(/"IOPlatformSerialNumber" = "([[:alnum:]]+)"/)
|
133
|
+
if serial_number_match_data
|
134
|
+
# The fingerprint must be unique across all personal access tokens for a
|
135
|
+
# given user. We prefix the serial number with the application name to
|
136
|
+
# differentiate between any other personal access token that uses the
|
137
|
+
# Mac serial number for the fingerprint.
|
138
|
+
Digest::SHA256.hexdigest("Boxen: #{serial_number_match_data[1]}")
|
139
|
+
else
|
140
|
+
abort "Sorry, I was unable to obtain your Mac's serial number.",
|
141
|
+
"Boxen requires access to your Mac's serial number in order to generate a unique GitHub personal access token."
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def note
|
147
|
+
@note ||= "Boxen: #{Socket.gethostname}"
|
148
|
+
end
|
108
149
|
end
|
@@ -3,6 +3,9 @@ require 'boxen/config'
|
|
3
3
|
require 'boxen/preflight/creds'
|
4
4
|
|
5
5
|
class BoxenPreflightCredsTest < Boxen::Test
|
6
|
+
# Make a struct to use for stubbing out authorization objects.
|
7
|
+
Struct.new("Authorization", :id, :note, :fingerprint, :token)
|
8
|
+
|
6
9
|
def setup
|
7
10
|
@config = Boxen::Config.new do |c|
|
8
11
|
c.user = 'mojombo'
|
@@ -77,4 +80,98 @@ class BoxenPreflightCredsTest < Boxen::Test
|
|
77
80
|
assert_equal "l", @config.login
|
78
81
|
assert_equal "p", preflight.instance_variable_get(:@password)
|
79
82
|
end
|
83
|
+
|
84
|
+
def test_run_with_existing_token
|
85
|
+
preflight = Boxen::Preflight::Creds.new @config
|
86
|
+
note = "App1"
|
87
|
+
fingerprint = "Fingerprint1"
|
88
|
+
existing_token = Struct::Authorization.new(1, note, fingerprint, "Token1")
|
89
|
+
|
90
|
+
preflight.stubs(:fetch_login_and_password).returns("")
|
91
|
+
preflight.stubs(:get_tokens).returns([existing_token])
|
92
|
+
preflight.stubs(:note).returns(note)
|
93
|
+
preflight.stubs(:fingerprint).returns(fingerprint)
|
94
|
+
preflight.stubs(:ok?).returns(true)
|
95
|
+
preflight.tmp_api.expects(:delete_authorization).with(existing_token.id, :headers => {})
|
96
|
+
preflight.tmp_api.expects(:create_authorization).with(
|
97
|
+
:note => note,
|
98
|
+
:fingerprint => fingerprint,
|
99
|
+
:scopes => %w(repo user),
|
100
|
+
:headers => {}
|
101
|
+
).returns(existing_token)
|
102
|
+
|
103
|
+
preflight.run
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_run_with_no_existing_token
|
107
|
+
preflight = Boxen::Preflight::Creds.new @config
|
108
|
+
note = "App1"
|
109
|
+
fingerprint = "Fingerprint1"
|
110
|
+
new_token = Struct::Authorization.new(1, note, fingerprint, "Token1")
|
111
|
+
|
112
|
+
preflight.stubs(:fetch_login_and_password).returns("")
|
113
|
+
preflight.stubs(:get_tokens).returns([])
|
114
|
+
preflight.stubs(:note).returns(note)
|
115
|
+
preflight.stubs(:fingerprint).returns(fingerprint)
|
116
|
+
preflight.stubs(:ok?).returns(true)
|
117
|
+
preflight.tmp_api.expects(:delete_authorization).never
|
118
|
+
preflight.tmp_api.expects(:create_authorization).with(
|
119
|
+
:note => note,
|
120
|
+
:fingerprint => fingerprint,
|
121
|
+
:scopes => %w(repo user),
|
122
|
+
:headers => {}
|
123
|
+
).returns(new_token)
|
124
|
+
|
125
|
+
preflight.run
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_run_does_not_delete_unrelated_tokens
|
129
|
+
preflight = Boxen::Preflight::Creds.new @config
|
130
|
+
note = "App1"
|
131
|
+
fingerprint = "Fingerprint1"
|
132
|
+
new_token = Struct::Authorization.new(1, note, fingerprint, "Token1")
|
133
|
+
unrelated_token = Struct::Authorization.new(2, "App2", fingerprint, "Token2")
|
134
|
+
unrelated_token_with_fingerprint = Struct::Authorization.new(3, "App3", "Fingerprint3", "Token3")
|
135
|
+
|
136
|
+
preflight.stubs(:fetch_login_and_password).returns("")
|
137
|
+
preflight.stubs(:get_tokens).returns(
|
138
|
+
[unrelated_token, unrelated_token_with_fingerprint]
|
139
|
+
)
|
140
|
+
preflight.stubs(:note).returns(note)
|
141
|
+
preflight.stubs(:fingerprint).returns(fingerprint)
|
142
|
+
preflight.stubs(:ok?).returns(true)
|
143
|
+
preflight.tmp_api.expects(:delete_authorization).never
|
144
|
+
preflight.tmp_api.expects(:create_authorization).with(
|
145
|
+
:note => note,
|
146
|
+
:fingerprint => fingerprint,
|
147
|
+
:scopes => %w(repo user),
|
148
|
+
:headers => {}
|
149
|
+
).returns(new_token)
|
150
|
+
|
151
|
+
preflight.run
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_run_does_delete_legacy_token
|
155
|
+
preflight = Boxen::Preflight::Creds.new @config
|
156
|
+
note = "App1"
|
157
|
+
fingerprint = "Fingerprint1"
|
158
|
+
existing_token = Struct::Authorization.new(1, note, fingerprint, "Token1")
|
159
|
+
legacy_token = Struct::Authorization.new(2, "Boxen", nil, "Token2")
|
160
|
+
|
161
|
+
preflight.stubs(:fetch_login_and_password).returns("")
|
162
|
+
preflight.stubs(:get_tokens).returns([existing_token, legacy_token])
|
163
|
+
preflight.stubs(:note).returns(note)
|
164
|
+
preflight.stubs(:fingerprint).returns(fingerprint)
|
165
|
+
preflight.stubs(:ok?).returns(true)
|
166
|
+
preflight.tmp_api.expects(:delete_authorization).with(2, :headers => {})
|
167
|
+
preflight.tmp_api.expects(:delete_authorization).with(1, :headers => {})
|
168
|
+
preflight.tmp_api.expects(:create_authorization).with(
|
169
|
+
:note => note,
|
170
|
+
:fingerprint => fingerprint,
|
171
|
+
:scopes => %w(repo user),
|
172
|
+
:headers => {}
|
173
|
+
).returns(existing_token)
|
174
|
+
|
175
|
+
preflight.run
|
176
|
+
end
|
80
177
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boxen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 7
|
9
|
-
-
|
10
|
-
version: 2.7.
|
9
|
+
- 2
|
10
|
+
version: 2.7.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- John Barnette
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2015-
|
20
|
+
date: 2015-05-18 00:00:00 +01:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
@@ -58,11 +58,12 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
hash:
|
61
|
+
hash: 15
|
62
62
|
segments:
|
63
63
|
- 1
|
64
64
|
- 6
|
65
|
-
|
65
|
+
- 0
|
66
|
+
version: 1.6.0
|
66
67
|
type: :runtime
|
67
68
|
version_requirements: *id003
|
68
69
|
- !ruby/object:Gem::Dependency
|