artifactory 2.1.3 → 2.2.0
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -2
- data/lib/artifactory.rb +14 -13
- data/lib/artifactory/client.rb +2 -1
- data/lib/artifactory/resources/artifact.rb +82 -0
- data/lib/artifactory/resources/permission_target.rb +206 -0
- data/lib/artifactory/resources/repository.rb +1 -1
- data/lib/artifactory/version.rb +1 -1
- data/spec/integration/resources/artifact_spec.rb +8 -0
- data/spec/integration/resources/permission_target_spec.rb +75 -0
- data/spec/support/api_server.rb +2 -0
- data/spec/support/api_server/artifact_endpoints.rb +14 -0
- data/spec/support/api_server/permission_target_endpoints.rb +53 -0
- data/spec/unit/resources/artifact_spec.rb +50 -0
- data/spec/unit/resources/permission_target_spec.rb +186 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b89a0d205ba82632c1f9b538a50b84f69b67ac0f
|
|
4
|
+
data.tar.gz: 1484191f4caf8502ca9ec7519d97c67fe5cc51f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d374065d88be5dc94f46fa9c4cf90694e8eb270ef1c92c6036a1e7941274735ca89e9ecc326d3d2d25d4a9170dd89217b0d6ee39cb2b616810817d756734249
|
|
7
|
+
data.tar.gz: dbe9986454583e5977d555d466a9163a535ae1a623b1d7916f258c1016315db1c32e09355f8e48303793a2c3189a3c9f5044b168217ecac6ca02d031aecbd042
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@ Artifactory Client CHANGELOG
|
|
|
3
3
|
This file is used to document the changes between releases of the Artifactory
|
|
4
4
|
Ruby client.
|
|
5
5
|
|
|
6
|
+
v2.2.0 (11-20-2014)
|
|
7
|
+
-------------------
|
|
8
|
+
- Add artifact usage search
|
|
9
|
+
- Add artifact creation search
|
|
10
|
+
- Add support for configuring permission targets
|
|
11
|
+
|
|
6
12
|
v2.1.3 (08-29-2014)
|
|
7
13
|
-------------------
|
|
8
14
|
- CGI escape matrix properties
|
data/README.md
CHANGED
|
@@ -31,14 +31,14 @@ This will given you "Rails-like" access to the top-level Artifactory resources l
|
|
|
31
31
|
|
|
32
32
|
```ruby
|
|
33
33
|
System.info
|
|
34
|
-
|
|
34
|
+
Repository.all
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
If you choose not to include the module (for namespacing reasons), you will need to specify the full module path to access resources:
|
|
38
38
|
|
|
39
39
|
```ruby
|
|
40
40
|
Artifactory::Resource::System.info
|
|
41
|
-
Artifactory::Resource::
|
|
41
|
+
Artifactory::Resource::Repository.all
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
### Create a connection
|
data/lib/artifactory.rb
CHANGED
|
@@ -30,19 +30,20 @@ module Artifactory
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
module Resource
|
|
33
|
-
autoload :Artifact,
|
|
34
|
-
autoload :Backup,
|
|
35
|
-
autoload :Base,
|
|
36
|
-
autoload :Build,
|
|
37
|
-
autoload :Group,
|
|
38
|
-
autoload :Layout,
|
|
39
|
-
autoload :LDAPSetting,
|
|
40
|
-
autoload :MailServer,
|
|
41
|
-
autoload :
|
|
42
|
-
autoload :
|
|
43
|
-
autoload :
|
|
44
|
-
autoload :
|
|
45
|
-
autoload :
|
|
33
|
+
autoload :Artifact, 'artifactory/resources/artifact'
|
|
34
|
+
autoload :Backup, 'artifactory/resources/backup'
|
|
35
|
+
autoload :Base, 'artifactory/resources/base'
|
|
36
|
+
autoload :Build, 'artifactory/resources/build'
|
|
37
|
+
autoload :Group, 'artifactory/resources/group'
|
|
38
|
+
autoload :Layout, 'artifactory/resources/layout'
|
|
39
|
+
autoload :LDAPSetting, 'artifactory/resources/ldap_setting'
|
|
40
|
+
autoload :MailServer, 'artifactory/resources/mail_server'
|
|
41
|
+
autoload :PermissionTarget, 'artifactory/resources/permission_target'
|
|
42
|
+
autoload :Plugin, 'artifactory/resources/plugin'
|
|
43
|
+
autoload :Repository, 'artifactory/resources/repository'
|
|
44
|
+
autoload :System, 'artifactory/resources/system'
|
|
45
|
+
autoload :URLBase, 'artifactory/resources/url_base'
|
|
46
|
+
autoload :User, 'artifactory/resources/user'
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
class << self
|
data/lib/artifactory/client.rb
CHANGED
|
@@ -52,10 +52,11 @@ module Artifactory
|
|
|
52
52
|
proxy Resource::Layout
|
|
53
53
|
proxy Resource::LDAPSetting
|
|
54
54
|
proxy Resource::MailServer
|
|
55
|
+
proxy Resource::PermissionTarget
|
|
55
56
|
proxy Resource::Repository
|
|
57
|
+
proxy Resource::System
|
|
56
58
|
proxy Resource::URLBase
|
|
57
59
|
proxy Resource::User
|
|
58
|
-
proxy Resource::System
|
|
59
60
|
|
|
60
61
|
#
|
|
61
62
|
# Create a new Artifactory Client with the given options. Any options
|
|
@@ -185,6 +185,88 @@ module Artifactory
|
|
|
185
185
|
end
|
|
186
186
|
end
|
|
187
187
|
|
|
188
|
+
#
|
|
189
|
+
# Search for an artifact by its usage
|
|
190
|
+
#
|
|
191
|
+
# @example Search for all repositories with the given usage statistics
|
|
192
|
+
# Artifact.usage_search(
|
|
193
|
+
# notUsedSince: 1388534400000,
|
|
194
|
+
# createdBefore: 1388534400000,
|
|
195
|
+
# )
|
|
196
|
+
#
|
|
197
|
+
# @example Search for all artifacts with the given usage statistics in a repo
|
|
198
|
+
# Artifact.usage_search(
|
|
199
|
+
# notUsedSince: 1388534400000,
|
|
200
|
+
# createdBefore: 1388534400000,
|
|
201
|
+
# repos: 'libs-release-local',
|
|
202
|
+
# )
|
|
203
|
+
#
|
|
204
|
+
# @param [Hash] options
|
|
205
|
+
# the list of options to search with
|
|
206
|
+
#
|
|
207
|
+
# @option options [Artifactory::Client] :client
|
|
208
|
+
# the client object to make the request with
|
|
209
|
+
# @option options [Long] :notUsedSince
|
|
210
|
+
# the last downloaded cutoff date of the artifact to search for (millis since epoch)
|
|
211
|
+
# @option options [Long] :createdBefore
|
|
212
|
+
# the creation cutoff date of the artifact to search for (millis since epoch)
|
|
213
|
+
# @option options [String, Array<String>] :repos
|
|
214
|
+
# the list of repos to search
|
|
215
|
+
#
|
|
216
|
+
# @return [Array<Resource::Artifact>]
|
|
217
|
+
# a list of artifacts that match the query
|
|
218
|
+
#
|
|
219
|
+
def usage_search(options = {})
|
|
220
|
+
client = extract_client!(options)
|
|
221
|
+
params = Util.slice(options, :notUsedSince, :createdBefore, :repos)
|
|
222
|
+
format_repos!(params)
|
|
223
|
+
|
|
224
|
+
client.get('/api/search/usage', params)['results'].map do |artifact|
|
|
225
|
+
from_url(artifact['uri'], client: client)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
#
|
|
230
|
+
# Search for an artifact by its creation date
|
|
231
|
+
#
|
|
232
|
+
# @example Search for all repositories with the given creation date range
|
|
233
|
+
# Artifact.usage_search(
|
|
234
|
+
# from : 1414800000000,
|
|
235
|
+
# to : 1414871200000,
|
|
236
|
+
# )
|
|
237
|
+
#
|
|
238
|
+
# @example Search for all artifacts with the given creation date range in a repo
|
|
239
|
+
# Artifact.usage_search(
|
|
240
|
+
# from : 1414800000000,
|
|
241
|
+
# to : 1414871200000,
|
|
242
|
+
# repos: 'libs-release-local',
|
|
243
|
+
# )
|
|
244
|
+
#
|
|
245
|
+
# @param [Hash] options
|
|
246
|
+
# the list of options to search with
|
|
247
|
+
#
|
|
248
|
+
# @option options [Artifactory::Client] :client
|
|
249
|
+
# the client object to make the request with
|
|
250
|
+
# @option options [Long] :from
|
|
251
|
+
# the creation start date of the artifact to search for (millis since epoch)
|
|
252
|
+
# @option options [Long] :to
|
|
253
|
+
# the creation end date of the artifact to search for (millis since epoch)
|
|
254
|
+
# @option options [String, Array<String>] :repos
|
|
255
|
+
# the list of repos to search
|
|
256
|
+
#
|
|
257
|
+
# @return [Array<Resource::Artifact>]
|
|
258
|
+
# a list of artifacts that match the query
|
|
259
|
+
#
|
|
260
|
+
def creation_search(options = {})
|
|
261
|
+
client = extract_client!(options)
|
|
262
|
+
params = Util.slice(options, :from, :to, :repos)
|
|
263
|
+
format_repos!(params)
|
|
264
|
+
|
|
265
|
+
client.get('/api/search/creation', params)['results'].map do |artifact|
|
|
266
|
+
from_url(artifact['uri'], client: client)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
188
270
|
#
|
|
189
271
|
# Get all versions of an artifact.
|
|
190
272
|
#
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module Artifactory
|
|
2
|
+
class Resource::PermissionTarget < Resource::Base
|
|
3
|
+
VERBOSE_PERMS = {
|
|
4
|
+
'd' => 'delete',
|
|
5
|
+
'm' => 'admin',
|
|
6
|
+
'n' => 'annotate',
|
|
7
|
+
'r' => 'read',
|
|
8
|
+
'w' => 'deploy',
|
|
9
|
+
}
|
|
10
|
+
class << self
|
|
11
|
+
#
|
|
12
|
+
# Get a list of all PermissionTargets in the system.
|
|
13
|
+
#
|
|
14
|
+
# @param [Hash] options
|
|
15
|
+
# the list of options
|
|
16
|
+
#
|
|
17
|
+
# @option options [Artifactory::Client] :client
|
|
18
|
+
# the client object to make the request with
|
|
19
|
+
#
|
|
20
|
+
# @return [Array<Resource::PermissionTarget>]
|
|
21
|
+
# the list of PermissionTargets
|
|
22
|
+
#
|
|
23
|
+
def all(options = {})
|
|
24
|
+
client = extract_client!(options)
|
|
25
|
+
client.get('/api/security/permissions').map do |hash|
|
|
26
|
+
from_url(hash['uri'], client: client)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Find (fetch) a permission target by its name.
|
|
32
|
+
#
|
|
33
|
+
# @example Find a permission target by its name
|
|
34
|
+
# PermissionTarget.find('readers') #=> #<PermissionTarget name: 'readers' ...>
|
|
35
|
+
#
|
|
36
|
+
# @param [String] name
|
|
37
|
+
# the name of the permission target to find
|
|
38
|
+
# @param [Hash] options
|
|
39
|
+
# the list of options
|
|
40
|
+
#
|
|
41
|
+
# @option options [Artifactory::Client] :client
|
|
42
|
+
# the client object to make the request with
|
|
43
|
+
#
|
|
44
|
+
# @return [Resource::PermissionTarget, nil]
|
|
45
|
+
# an instance of the permission target that matches the given name, or +nil+
|
|
46
|
+
# if one does not exist
|
|
47
|
+
#
|
|
48
|
+
def find(name, options = {})
|
|
49
|
+
client = extract_client!(options)
|
|
50
|
+
|
|
51
|
+
response = client.get("/api/security/permissions/#{url_safe(name)}")
|
|
52
|
+
from_hash(response, client: client)
|
|
53
|
+
rescue Error::HTTPError => e
|
|
54
|
+
raise unless e.code == 404
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# @see Resource::Base.from_hash
|
|
60
|
+
# Additionally use verbose names for permissions (e.g. 'read' for 'r')
|
|
61
|
+
#
|
|
62
|
+
def from_hash(hash, options = {})
|
|
63
|
+
super.tap do |instance|
|
|
64
|
+
%w(users groups).each do |key|
|
|
65
|
+
if instance.principals[key] && !instance.principals[key].nil?
|
|
66
|
+
instance.principals[key] = Hash[instance.principals[key].map { |k, v| [k, verbose(v)] } ]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
# Replace an array of permissions with one using verbose permission names
|
|
76
|
+
#
|
|
77
|
+
def verbose(array)
|
|
78
|
+
array.map { |elt| VERBOSE_PERMS[elt] }.sort
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class Principal
|
|
83
|
+
attr_accessor :users, :groups
|
|
84
|
+
|
|
85
|
+
def initialize(users = {}, groups = {})
|
|
86
|
+
@users = users
|
|
87
|
+
@groups = groups
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# Converts the user-friendly form of the principals hash to one suitable
|
|
92
|
+
# for posting to Artifactory.
|
|
93
|
+
# @return [Hash]
|
|
94
|
+
#
|
|
95
|
+
def to_abbreviated
|
|
96
|
+
{ 'users' => abbreviate_principal(@users), 'groups' => abbreviate_principal(@groups) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# Replace an array of verbose permission names with an equivalent array of abbreviated permission names.
|
|
103
|
+
#
|
|
104
|
+
def abbreviate_permissions(array)
|
|
105
|
+
inverse = VERBOSE_PERMS.invert
|
|
106
|
+
if (inverse.keys & array).sort != array.sort then
|
|
107
|
+
raise "One of your principals contains an invalid permission. Valid permissions are #{inverse.keys.join(', ')}"
|
|
108
|
+
end
|
|
109
|
+
array.map { |elt| inverse[elt] }.sort
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
# Replace a principal with verbose permissions with an equivalent one with abbreviated permissions.
|
|
114
|
+
#
|
|
115
|
+
def abbreviate_principal(principal_hash)
|
|
116
|
+
Hash[principal_hash.map { |k, v| [k, abbreviate_permissions(v)] } ]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
attribute :name, ->{ raise 'Name missing!' }
|
|
121
|
+
attribute :includes_pattern, '**'
|
|
122
|
+
attribute :excludes_pattern, ''
|
|
123
|
+
attribute :repositories
|
|
124
|
+
attribute :principals, { 'users' => {}, 'groups' => {} }
|
|
125
|
+
|
|
126
|
+
def client_principal
|
|
127
|
+
@client_principal ||= Principal.new(principals['users'], principals['groups'])
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
#
|
|
131
|
+
# Delete this PermissionTarget from artifactory, suppressing any +ResourceNotFound+
|
|
132
|
+
# exceptions might occur.
|
|
133
|
+
#
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
# true if the object was deleted successfully, false otherwise
|
|
136
|
+
#
|
|
137
|
+
def delete
|
|
138
|
+
client.delete(api_path)
|
|
139
|
+
true
|
|
140
|
+
rescue Error::HTTPError
|
|
141
|
+
false
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# Save the PermissionTarget to the artifactory server.
|
|
146
|
+
# See http://bit.ly/1qMOw0L
|
|
147
|
+
#
|
|
148
|
+
# @return [Boolean]
|
|
149
|
+
#
|
|
150
|
+
def save
|
|
151
|
+
send("#{:principals}=", client_principal.to_abbreviated)
|
|
152
|
+
client.put(api_path, to_json, headers)
|
|
153
|
+
true
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
#
|
|
157
|
+
# Getter for groups
|
|
158
|
+
#
|
|
159
|
+
def groups
|
|
160
|
+
client_principal.groups
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#
|
|
164
|
+
# Setter for groups (groups_hash expected to be friendly)
|
|
165
|
+
#
|
|
166
|
+
def groups=(groups_hash)
|
|
167
|
+
client_principal.groups = Hash[groups_hash.map { |k, v| [k, v.sort] } ]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#
|
|
171
|
+
# Getter for users
|
|
172
|
+
#
|
|
173
|
+
def users
|
|
174
|
+
client_principal.users
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# Setter for users (expecting users_hash to be friendly)
|
|
179
|
+
#
|
|
180
|
+
def users=(users_hash)
|
|
181
|
+
client_principal.users = Hash[users_hash.map { |k, v| [k, v.sort] } ]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
|
|
186
|
+
#
|
|
187
|
+
# The path to this PermissionTarget on the server.
|
|
188
|
+
#
|
|
189
|
+
# @return [String]
|
|
190
|
+
#
|
|
191
|
+
def api_path
|
|
192
|
+
@api_path ||= "/api/security/permissions/#{url_safe(name)}"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
#
|
|
196
|
+
# The default headers for this object. This includes the +Content-Type+.
|
|
197
|
+
#
|
|
198
|
+
# @return [Hash]
|
|
199
|
+
#
|
|
200
|
+
def headers
|
|
201
|
+
@headers ||= {
|
|
202
|
+
'Content-Type' => 'application/vnd.org.jfrog.artifactory.security.PermissionTarget+json'
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -39,7 +39,7 @@ module Artifactory
|
|
|
39
39
|
#
|
|
40
40
|
# Find (fetch) a repository by name.
|
|
41
41
|
#
|
|
42
|
-
# @example Find a
|
|
42
|
+
# @example Find a repository by named key
|
|
43
43
|
# Repository.find(name: 'libs-release-local') #=> #<Resource::Artifact>
|
|
44
44
|
#
|
|
45
45
|
# @param [Hash] options
|
data/lib/artifactory/version.rb
CHANGED
|
@@ -52,6 +52,14 @@ module Artifactory
|
|
|
52
52
|
it_behaves_like 'an artifact search endpoint', :checksum_search, md5: 'abcd1234'
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
describe '.usage_search' do
|
|
56
|
+
it_behaves_like 'an artifact search endpoint', :usage_search, notUsedSince: '1414800000'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe '.creation_search' do
|
|
60
|
+
it_behaves_like 'an artifact search endpoint', :creation_search, from: '1414800000'
|
|
61
|
+
end
|
|
62
|
+
|
|
55
63
|
describe '.versions' do
|
|
56
64
|
it 'returns an array of versions' do
|
|
57
65
|
response = described_class.versions
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Artifactory
|
|
4
|
+
describe Resource::PermissionTarget, :integration do
|
|
5
|
+
describe '.all' do
|
|
6
|
+
it 'returns an array of PermissionTarget objects' do
|
|
7
|
+
results = described_class.all
|
|
8
|
+
expect(results).to be_a(Array)
|
|
9
|
+
expect(results.first).to be_a(described_class)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'includes the information from the server' do
|
|
13
|
+
results = described_class.all
|
|
14
|
+
anything = results[0]
|
|
15
|
+
any_remote = results[1]
|
|
16
|
+
|
|
17
|
+
expect(anything.name).to eq('Anything')
|
|
18
|
+
expect(any_remote.name).to eq('Any Remote')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '.find' do
|
|
23
|
+
it 'finds a permission target by name' do
|
|
24
|
+
readers = described_class.find('Anything')
|
|
25
|
+
|
|
26
|
+
expect(readers).to be_a(described_class)
|
|
27
|
+
expect(readers.name).to eq('Anything')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#delete' do
|
|
32
|
+
it 'deletes the permission target from the server' do
|
|
33
|
+
readers = described_class.find('Anything')
|
|
34
|
+
expect(readers.delete).to be_truthy
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#save' do
|
|
39
|
+
it 'saves the permission target to the server' do
|
|
40
|
+
target = described_class.new(name: 'testing')
|
|
41
|
+
expect(target.save).to be_truthy
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#users' do
|
|
46
|
+
it 'displays the users hash with sorted verbose permissions' do
|
|
47
|
+
target = described_class.find('Any Remote')
|
|
48
|
+
expect(target.users).to eq( { 'anonymous' => ['deploy', 'read'] } )
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#groups' do
|
|
53
|
+
it 'displays the groups hash with sorted verbose permissions' do
|
|
54
|
+
target = described_class.find('Anything')
|
|
55
|
+
expect(target.groups).to eq( { 'readers' => ['admin', 'read'] } )
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe '#users=' do
|
|
60
|
+
it 'sets the users hash' do
|
|
61
|
+
target = described_class.find('Any Remote')
|
|
62
|
+
target.users = { 'admins' => ['admin'] }
|
|
63
|
+
expect(target.users).to eq( { 'admins' => ['admin'] })
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '#groups=' do
|
|
68
|
+
it 'sets the groups hash' do
|
|
69
|
+
target = described_class.find('Anything')
|
|
70
|
+
target.groups = { 'deployers' => ['deploy'] }
|
|
71
|
+
expect(target.groups).to eq( { 'deployers' => ['deploy'] })
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
data/spec/support/api_server.rb
CHANGED
|
@@ -10,6 +10,7 @@ module Artifactory
|
|
|
10
10
|
require_relative 'api_server/build_endpoints'
|
|
11
11
|
require_relative 'api_server/group_endpoints'
|
|
12
12
|
require_relative 'api_server/repository_endpoints'
|
|
13
|
+
require_relative 'api_server/permission_target_endpoints'
|
|
13
14
|
require_relative 'api_server/status_endpoints'
|
|
14
15
|
require_relative 'api_server/system_endpoints'
|
|
15
16
|
require_relative 'api_server/user_endpoints'
|
|
@@ -17,6 +18,7 @@ module Artifactory
|
|
|
17
18
|
register APIServer::ArtifactEndpoints
|
|
18
19
|
register APIServer::BuildEndpoints
|
|
19
20
|
register APIServer::GroupEndpoints
|
|
21
|
+
register APIServer::PermissionTargetEndpoints
|
|
20
22
|
register APIServer::RepositoryEndpoints
|
|
21
23
|
register APIServer::StatusEndpoints
|
|
22
24
|
register APIServer::SystemEndpoints
|
|
@@ -32,6 +32,20 @@ module Artifactory
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
app.get('/api/search/usage') do
|
|
36
|
+
content_type 'application/vnd.org.jfrog.artifactory.search.ArtifactUsageResult+json'
|
|
37
|
+
artifacts_for_conditions do
|
|
38
|
+
params['notUsedSince'] == '1414800000'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
app.get('/api/search/creation') do
|
|
43
|
+
content_type 'application/vnd.org.jfrog.artifactory.search.ArtifactCreationResult+json'
|
|
44
|
+
artifacts_for_conditions do
|
|
45
|
+
params['from'] == '1414800000'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
35
49
|
app.get('/api/search/versions') do
|
|
36
50
|
content_type 'application/vnd.org.jfrog.artifactory.search.ArtifactVersionsResult+json'
|
|
37
51
|
JSON.fast_generate(
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Artifactory
|
|
2
|
+
module APIServer::PermissionTargetEndpoints
|
|
3
|
+
def self.registered(app)
|
|
4
|
+
app.get('/api/security/permissions') do
|
|
5
|
+
content_type 'application/vnd.org.jfrog.artifactory.security.PermissionTargets+json'
|
|
6
|
+
JSON.fast_generate([
|
|
7
|
+
{
|
|
8
|
+
'name' => 'Anything',
|
|
9
|
+
'uri' => server_url.join('/api/security/permissions/Anything'),
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
'name' => 'Any Remote',
|
|
13
|
+
'uri' => server_url.join('/api/security/permissions/Any%20Remote')
|
|
14
|
+
}
|
|
15
|
+
])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
app.get('/api/security/permissions/Any%20Remote') do
|
|
19
|
+
content_type 'application/vnd.org.jfrog.artifactory.security.PermissionTargets+json'
|
|
20
|
+
JSON.fast_generate(
|
|
21
|
+
'name' => 'Any Remote',
|
|
22
|
+
'includes_pattern' => nil,
|
|
23
|
+
'excludes_pattern' => '',
|
|
24
|
+
'repositories' => ["ANY REMOTE"],
|
|
25
|
+
'principals' => { 'users' => { 'anonymous' => ['w', 'r'] }, 'groups' => nil }
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
app.get('/api/security/permissions/Anything') do
|
|
30
|
+
content_type 'application/vnd.org.jfrog.artifactory.security.PermissionTargets+json'
|
|
31
|
+
JSON.fast_generate(
|
|
32
|
+
'name' => 'Anything',
|
|
33
|
+
'includes_pattern' => nil,
|
|
34
|
+
'excludes_pattern' => '',
|
|
35
|
+
'repositories' => ["ANY"],
|
|
36
|
+
'principals' => { 'users' => { 'anonymous' => ['r'] }, 'groups' => { 'readers' => ['r', 'm'] } }
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
app.put('/api/security/permissions/:name') do
|
|
41
|
+
return 415 unless request.content_type == 'application/vnd.org.jfrog.artifactory.security.PermissionTarget+json'
|
|
42
|
+
|
|
43
|
+
# Attempt to parse the response; if this succeeds, all is well...
|
|
44
|
+
JSON.parse(request.body.read)
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
app.delete('/api/security/permissions/:name') do
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -207,6 +207,56 @@ module Artifactory
|
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
+
describe '.usage_search' do
|
|
211
|
+
let(:response) { { 'results' => [] } }
|
|
212
|
+
|
|
213
|
+
it 'calls /api/search/usage' do
|
|
214
|
+
expect(client).to receive(:get).with('/api/search/usage', {}).once
|
|
215
|
+
described_class.usage_search
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it 'slices the correct parameters' do
|
|
219
|
+
expect(client).to receive(:get).with('/api/search/usage',
|
|
220
|
+
notUsedSince: 1414800000000,
|
|
221
|
+
createdBefore: 1414871200000,
|
|
222
|
+
).once
|
|
223
|
+
described_class.usage_search(
|
|
224
|
+
notUsedSince: 1414800000000,
|
|
225
|
+
createdBefore: 1414871200000,
|
|
226
|
+
fizz: 'foo',
|
|
227
|
+
)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'returns an array of objects' do
|
|
231
|
+
expect(described_class.usage_search).to be_a(Array)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe '.creation_search' do
|
|
236
|
+
let(:response) { { 'results' => [] } }
|
|
237
|
+
|
|
238
|
+
it 'calls /api/search/creation' do
|
|
239
|
+
expect(client).to receive(:get).with('/api/search/creation', {}).once
|
|
240
|
+
described_class.creation_search
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it 'slices the correct parameters' do
|
|
244
|
+
expect(client).to receive(:get).with('/api/search/creation',
|
|
245
|
+
from: 1414800000000,
|
|
246
|
+
to: 1414871200000,
|
|
247
|
+
).once
|
|
248
|
+
described_class.creation_search(
|
|
249
|
+
from: 1414800000000,
|
|
250
|
+
to: 1414871200000,
|
|
251
|
+
fizz: 'foo',
|
|
252
|
+
)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'returns an array of objects' do
|
|
256
|
+
expect(described_class.creation_search).to be_a(Array)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
210
260
|
describe '.versions' do
|
|
211
261
|
let(:response) { { 'results' => [] } }
|
|
212
262
|
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Artifactory
|
|
4
|
+
describe Resource::PermissionTarget do
|
|
5
|
+
let(:client) { double(:client) }
|
|
6
|
+
|
|
7
|
+
before(:each) do
|
|
8
|
+
allow(Artifactory).to receive(:client).and_return(client)
|
|
9
|
+
allow(client).to receive(:get).and_return(response) if defined?(response)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe '.all' do
|
|
13
|
+
let(:response) do
|
|
14
|
+
[
|
|
15
|
+
{ 'uri' => 'a' },
|
|
16
|
+
{ 'uri' => 'b' },
|
|
17
|
+
{ 'uri' => 'c' },
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
before do
|
|
21
|
+
allow(described_class).to receive(:from_url).with('a', client: client).and_return('a')
|
|
22
|
+
allow(described_class).to receive(:from_url).with('b', client: client).and_return('b')
|
|
23
|
+
allow(described_class).to receive(:from_url).with('c', client: client).and_return('c')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'gets /api/security/permissions' do
|
|
27
|
+
expect(client).to receive(:get).with('/api/security/permissions').once
|
|
28
|
+
described_class.all
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'returns the permissions' do
|
|
32
|
+
expect(described_class.all).to eq(['a', 'b', 'c'])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '.find' do
|
|
37
|
+
let(:response) { {} }
|
|
38
|
+
|
|
39
|
+
it 'gets /api/security/permissions/#{name}' do
|
|
40
|
+
expect(client).to receive(:get).with('/api/security/permissions/Any%20Remote').once
|
|
41
|
+
described_class.find('Any Remote')
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '.from_url' do
|
|
46
|
+
let(:response) { {} }
|
|
47
|
+
|
|
48
|
+
it 'constructs a new instance from the result' do
|
|
49
|
+
expect(described_class).to receive(:from_hash).once
|
|
50
|
+
described_class.from_url('/api/security/permissions/Any Remote')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '.from_hash' do
|
|
55
|
+
let(:hash) do
|
|
56
|
+
{
|
|
57
|
+
'name' => 'Test Remote',
|
|
58
|
+
'includes_pattern' => '**',
|
|
59
|
+
'excludes_pattern' => '',
|
|
60
|
+
'repositories' => ['ANY REMOTE'],
|
|
61
|
+
'principals' => { 'users' => { 'anonymous' => ['w', 'r'] }, 'groups' => {} }
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'creates a new instance' do
|
|
66
|
+
instance = described_class.from_hash(hash)
|
|
67
|
+
expect(instance.name).to eq('Test Remote')
|
|
68
|
+
expect(instance.includes_pattern).to eq('**')
|
|
69
|
+
expect(instance.excludes_pattern).to eq('')
|
|
70
|
+
expect(instance.repositories).to eq(['ANY REMOTE'])
|
|
71
|
+
expect(instance.principals).to eq({ 'users' => { 'anonymous' => ['deploy', 'read'] }, 'groups' => {} })
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe Artifactory::Resource::PermissionTarget::Principal do
|
|
76
|
+
context 'principal object' do
|
|
77
|
+
users = { 'anonymous_users' => ['admin', 'deploy', 'read'] }
|
|
78
|
+
groups = { 'anonymous_groups' => ['delete', 'read'] }
|
|
79
|
+
instance = described_class.new(users, groups)
|
|
80
|
+
|
|
81
|
+
it 'has unabbreviated users' do
|
|
82
|
+
expect(instance.users).to eq( { 'anonymous_users' => ['admin', 'deploy', 'read'] } )
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'has unabbreviated groups' do
|
|
86
|
+
expect(instance.groups).to eq( { 'anonymous_groups' => ['delete', 'read'] } )
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'abbreviates' do
|
|
90
|
+
expect(instance.to_abbreviated).to eq( { 'users' => { 'anonymous_users' => ['m', 'r', 'w'] }, 'groups' => { 'anonymous_groups' => ['d', 'r'] } } )
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe '#save' do
|
|
96
|
+
let(:client) { double }
|
|
97
|
+
before do
|
|
98
|
+
subject.client = client
|
|
99
|
+
subject.name = 'TestRemote'
|
|
100
|
+
subject.includes_pattern = nil
|
|
101
|
+
subject.excludes_pattern = ''
|
|
102
|
+
subject.repositories = ['ANY']
|
|
103
|
+
subject.principals = {
|
|
104
|
+
'users' => {
|
|
105
|
+
'anonymous_users' => ['read']
|
|
106
|
+
},
|
|
107
|
+
'groups' => {
|
|
108
|
+
'anonymous_readers' => ['read']
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
allow(described_class).to receive(:find).with(subject.name, client: client).and_return(nil)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'PUTS the permission target to the server' do
|
|
115
|
+
expect(client).to receive(:put).with("/api/security/permissions/TestRemote",
|
|
116
|
+
"{\"name\":\"TestRemote\",\"includesPattern\":null,\"excludesPattern\":\"\",\"repositories\":[\"ANY\"],\"principals\":{\"users\":{\"anonymous_users\":[\"r\"]},\"groups\":{\"anonymous_readers\":[\"r\"]}}}",
|
|
117
|
+
{ "Content-Type" => "application/vnd.org.jfrog.artifactory.security.PermissionTarget+json"})
|
|
118
|
+
subject.save
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe '#delete' do
|
|
123
|
+
let(:client) { double }
|
|
124
|
+
|
|
125
|
+
it 'sends DELETE to the client' do
|
|
126
|
+
subject.client = client
|
|
127
|
+
subject.name = 'My Permissions'
|
|
128
|
+
|
|
129
|
+
expect(client).to receive(:delete).with('/api/security/permissions/My%20Permissions')
|
|
130
|
+
subject.delete
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe 'getters' do
|
|
135
|
+
let(:client) { double }
|
|
136
|
+
before do
|
|
137
|
+
subject.client = client
|
|
138
|
+
subject.name = 'TestGetters'
|
|
139
|
+
subject.principals = {
|
|
140
|
+
'users' => {
|
|
141
|
+
'anonymous' => ['read']
|
|
142
|
+
},
|
|
143
|
+
'groups' => {
|
|
144
|
+
'readers' => ['read']
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
allow(described_class).to receive(:find).with(subject.name, client: client).and_return(nil)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it '#users returns the users hash' do
|
|
151
|
+
expect(subject.users).to eq({ 'anonymous' => ['read'] })
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it '#groups returns the groups hash' do
|
|
155
|
+
expect(subject.groups).to eq({ 'readers' => ['read'] })
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
describe 'setters' do
|
|
160
|
+
let(:client) { double }
|
|
161
|
+
before do
|
|
162
|
+
subject.client = client
|
|
163
|
+
subject.name = 'TestSetters'
|
|
164
|
+
subject.principals = {
|
|
165
|
+
'users' => {
|
|
166
|
+
'anonymous' => ['read']
|
|
167
|
+
},
|
|
168
|
+
'groups' => {
|
|
169
|
+
'readers' => ['read']
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
allow(described_class).to receive(:find).with(subject.name, client: client).and_return(nil)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it '#users= sets the users hash' do
|
|
176
|
+
subject.users = { 'spiders' => [ 'read', 'admin'] }
|
|
177
|
+
expect(subject.users).to eq({ 'spiders' => ['admin', 'read'] })
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it '#groups= sets the groups hash' do
|
|
181
|
+
subject.groups = { 'beatles' => [ 'deploy', 'delete'] }
|
|
182
|
+
expect(subject.groups).to eq({ 'beatles' => ['delete', 'deploy'] })
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: artifactory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Seth Vargo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -67,6 +67,7 @@ files:
|
|
|
67
67
|
- lib/artifactory/resources/layout.rb
|
|
68
68
|
- lib/artifactory/resources/ldap_setting.rb
|
|
69
69
|
- lib/artifactory/resources/mail_server.rb
|
|
70
|
+
- lib/artifactory/resources/permission_target.rb
|
|
70
71
|
- lib/artifactory/resources/plugin.rb
|
|
71
72
|
- lib/artifactory/resources/repository.rb
|
|
72
73
|
- lib/artifactory/resources/system.rb
|
|
@@ -81,6 +82,7 @@ files:
|
|
|
81
82
|
- spec/integration/resources/layout_spec.rb
|
|
82
83
|
- spec/integration/resources/ldap_setting_spec.rb
|
|
83
84
|
- spec/integration/resources/mail_server_spec.rb
|
|
85
|
+
- spec/integration/resources/permission_target_spec.rb
|
|
84
86
|
- spec/integration/resources/repository_spec.rb
|
|
85
87
|
- spec/integration/resources/system_spec.rb
|
|
86
88
|
- spec/integration/resources/url_base_spec.rb
|
|
@@ -90,6 +92,7 @@ files:
|
|
|
90
92
|
- spec/support/api_server/artifact_endpoints.rb
|
|
91
93
|
- spec/support/api_server/build_endpoints.rb
|
|
92
94
|
- spec/support/api_server/group_endpoints.rb
|
|
95
|
+
- spec/support/api_server/permission_target_endpoints.rb
|
|
93
96
|
- spec/support/api_server/repository_endpoints.rb
|
|
94
97
|
- spec/support/api_server/status_endpoints.rb
|
|
95
98
|
- spec/support/api_server/system_endpoints.rb
|
|
@@ -104,6 +107,7 @@ files:
|
|
|
104
107
|
- spec/unit/resources/layout_spec.rb
|
|
105
108
|
- spec/unit/resources/ldap_setting_spec.rb
|
|
106
109
|
- spec/unit/resources/mail_server_spec.rb
|
|
110
|
+
- spec/unit/resources/permission_target_spec.rb
|
|
107
111
|
- spec/unit/resources/plugin_spec.rb
|
|
108
112
|
- spec/unit/resources/repository_spec.rb
|
|
109
113
|
- spec/unit/resources/system_spec.rb
|
|
@@ -142,6 +146,7 @@ test_files:
|
|
|
142
146
|
- spec/integration/resources/layout_spec.rb
|
|
143
147
|
- spec/integration/resources/ldap_setting_spec.rb
|
|
144
148
|
- spec/integration/resources/mail_server_spec.rb
|
|
149
|
+
- spec/integration/resources/permission_target_spec.rb
|
|
145
150
|
- spec/integration/resources/repository_spec.rb
|
|
146
151
|
- spec/integration/resources/system_spec.rb
|
|
147
152
|
- spec/integration/resources/url_base_spec.rb
|
|
@@ -151,6 +156,7 @@ test_files:
|
|
|
151
156
|
- spec/support/api_server/artifact_endpoints.rb
|
|
152
157
|
- spec/support/api_server/build_endpoints.rb
|
|
153
158
|
- spec/support/api_server/group_endpoints.rb
|
|
159
|
+
- spec/support/api_server/permission_target_endpoints.rb
|
|
154
160
|
- spec/support/api_server/repository_endpoints.rb
|
|
155
161
|
- spec/support/api_server/status_endpoints.rb
|
|
156
162
|
- spec/support/api_server/system_endpoints.rb
|
|
@@ -165,6 +171,7 @@ test_files:
|
|
|
165
171
|
- spec/unit/resources/layout_spec.rb
|
|
166
172
|
- spec/unit/resources/ldap_setting_spec.rb
|
|
167
173
|
- spec/unit/resources/mail_server_spec.rb
|
|
174
|
+
- spec/unit/resources/permission_target_spec.rb
|
|
168
175
|
- spec/unit/resources/plugin_spec.rb
|
|
169
176
|
- spec/unit/resources/repository_spec.rb
|
|
170
177
|
- spec/unit/resources/system_spec.rb
|