mdqt 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a4e1124b801ccc638cf0ffc2f8ce7f70321933f1a050506ce0ce3b39870b56b
4
- data.tar.gz: 7bebdb49dd714cf0f49c74dd31ec0505dd4957b408f781bf523c272262750496
3
+ metadata.gz: 1b4c3d3af10864847c7660c245d2ff0459ce87282011a7562ffa39c51c18f2f5
4
+ data.tar.gz: a1b470e3d206b7f5ed83f78afa970e13e7b1847ae96c5a1727b931c4a19846ec
5
5
  SHA512:
6
- metadata.gz: 9216f2cb673d91ca41ce2c029203527e5daa4aafa968d9a0645b62d28a000d52030417b02966b933986b6dd085c7a06217461d3b199cd310f53be1d9d6cbf930
7
- data.tar.gz: b594e5dba5098dfd0b5d6eb682a1d3196987888a5b48da2efe8707362439a34cf712f595afd949fe18816c46ff8d187e0144e3e340161c604030098c20e478cd
6
+ metadata.gz: 02fca67549a99277832129e8bf27344c9764c76519b464e57b8f28ddc5838f75d9cbd3e0adff603e9b2a57b985e7d93b61282a3b5d01e311f68f988cbdb64586
7
+ data.tar.gz: eed5827d3d9954211debb6bf52182777a01da7a8df266272bf338374c1bdd9f9ab54149d7cd5d86cf909ed645617d35791b0807814ed5c6823143d5cdb4a0554
data/.gitignore CHANGED
@@ -8,3 +8,6 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /out.xml
11
+ /out.txt
12
+ /mdqt_cache.log
13
+ *.gem
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
@@ -0,0 +1,296 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2018-05-03 07:42:59 +0100 using RuboCop version 0.55.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: Include, TreatCommentsAsGroupSeparators.
12
+ # Include: **/*.gemspec
13
+ Gemspec/OrderedDependencies:
14
+ Exclude:
15
+ - 'mdqt.gemspec'
16
+
17
+ # Offense count: 1
18
+ # Configuration parameters: Include.
19
+ # Include: **/*.gemspec
20
+ Gemspec/RequiredRubyVersion:
21
+ Exclude:
22
+ - 'mdqt.gemspec'
23
+
24
+ # Offense count: 1
25
+ # Cop supports --auto-correct.
26
+ Layout/CommentIndentation:
27
+ Exclude:
28
+ - 'lib/mdqt/cli/base.rb'
29
+
30
+ # Offense count: 1
31
+ # Cop supports --auto-correct.
32
+ # Configuration parameters: AllowBorderComment, AllowMarginComment.
33
+ Layout/EmptyComment:
34
+ Exclude:
35
+ - 'lib/mdqt/cli/base.rb'
36
+
37
+ # Offense count: 1
38
+ # Cop supports --auto-correct.
39
+ Layout/EmptyLineAfterMagicComment:
40
+ Exclude:
41
+ - 'mdqt.gemspec'
42
+
43
+ # Offense count: 3
44
+ # Cop supports --auto-correct.
45
+ Layout/EmptyLines:
46
+ Exclude:
47
+ - 'lib/mdqt/cli.rb'
48
+ - 'mdqt.gemspec'
49
+ - 'spec/client/client_spec.rb'
50
+
51
+ # Offense count: 3
52
+ # Cop supports --auto-correct.
53
+ # Configuration parameters: EnforcedStyle.
54
+ # SupportedStyles: empty_lines, no_empty_lines
55
+ Layout/EmptyLinesAroundBlockBody:
56
+ Exclude:
57
+ - 'exe/mdqt'
58
+ - 'spec/client/client_spec.rb'
59
+
60
+ # Offense count: 22
61
+ # Cop supports --auto-correct.
62
+ # Configuration parameters: EnforcedStyle.
63
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
64
+ Layout/EmptyLinesAroundClassBody:
65
+ Exclude:
66
+ - 'lib/mdqt/cli.rb'
67
+ - 'lib/mdqt/cli/base.rb'
68
+ - 'lib/mdqt/cli/defaults.rb'
69
+ - 'lib/mdqt/cli/get.rb'
70
+ - 'lib/mdqt/client.rb'
71
+ - 'lib/mdqt/client/metadata_service.rb'
72
+
73
+ # Offense count: 11
74
+ # Cop supports --auto-correct.
75
+ Layout/EmptyLinesAroundMethodBody:
76
+ Exclude:
77
+ - 'lib/mdqt/cli/base.rb'
78
+ - 'lib/mdqt/cli/get.rb'
79
+ - 'lib/mdqt/client.rb'
80
+ - 'lib/mdqt/client/metadata_service.rb'
81
+
82
+ # Offense count: 7
83
+ # Cop supports --auto-correct.
84
+ # Configuration parameters: EnforcedStyle.
85
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
86
+ Layout/EmptyLinesAroundModuleBody:
87
+ Exclude:
88
+ - 'lib/mdqt.rb'
89
+ - 'lib/mdqt/cli.rb'
90
+ - 'lib/mdqt/cli/base.rb'
91
+ - 'lib/mdqt/cli/get.rb'
92
+ - 'lib/mdqt/client.rb'
93
+ - 'lib/mdqt/client/metadata_service.rb'
94
+
95
+ # Offense count: 1
96
+ # Cop supports --auto-correct.
97
+ # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
98
+ Layout/ExtraSpacing:
99
+ Exclude:
100
+ - 'mdqt.gemspec'
101
+
102
+ # Offense count: 3
103
+ # Cop supports --auto-correct.
104
+ Layout/LeadingCommentSpace:
105
+ Exclude:
106
+ - 'exe/mdqt'
107
+ - 'lib/mdqt/client/metadata_service.rb'
108
+
109
+ # Offense count: 1
110
+ # Cop supports --auto-correct.
111
+ Layout/SpaceAfterComma:
112
+ Exclude:
113
+ - 'lib/mdqt/client/metadata_service.rb'
114
+
115
+ # Offense count: 1
116
+ # Cop supports --auto-correct.
117
+ # Configuration parameters: .
118
+ # SupportedStyles: space, no_space
119
+ Layout/SpaceAroundEqualsInParameterDefault:
120
+ EnforcedStyle: no_space
121
+
122
+ # Offense count: 1
123
+ # Cop supports --auto-correct.
124
+ # Configuration parameters: AllowForAlignment.
125
+ Layout/SpaceAroundOperators:
126
+ Exclude:
127
+ - 'mdqt.gemspec'
128
+
129
+ # Offense count: 1
130
+ # Cop supports --auto-correct.
131
+ # Configuration parameters: AllowForAlignment.
132
+ Layout/SpaceBeforeFirstArg:
133
+ Exclude:
134
+ - 'lib/mdqt/client/metadata_service.rb'
135
+
136
+ # Offense count: 2
137
+ # Cop supports --auto-correct.
138
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
139
+ # SupportedStyles: space, no_space
140
+ # SupportedStylesForEmptyBraces: space, no_space
141
+ Layout/SpaceInsideBlockBraces:
142
+ Exclude:
143
+ - 'lib/mdqt/cli/get.rb'
144
+
145
+ # Offense count: 7
146
+ # Cop supports --auto-correct.
147
+ # Configuration parameters: EnforcedStyle.
148
+ # SupportedStyles: final_newline, final_blank_line
149
+ Layout/TrailingBlankLines:
150
+ Exclude:
151
+ - 'exe/mdqt'
152
+ - 'lib/mdqt/cli.rb'
153
+ - 'lib/mdqt/cli/base.rb'
154
+ - 'lib/mdqt/cli/defaults.rb'
155
+ - 'lib/mdqt/client.rb'
156
+ - 'lib/mdqt/client/metadata_service.rb'
157
+ - 'spec/client/client_spec.rb'
158
+
159
+ # Offense count: 2
160
+ # Cop supports --auto-correct.
161
+ # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
162
+ Lint/UnusedBlockArgument:
163
+ Exclude:
164
+ - 'exe/mdqt'
165
+
166
+ # Offense count: 2
167
+ # Cop supports --auto-correct.
168
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
169
+ Lint/UnusedMethodArgument:
170
+ Exclude:
171
+ - 'lib/mdqt/cli/base.rb'
172
+
173
+ # Offense count: 1
174
+ Lint/UselessAssignment:
175
+ Exclude:
176
+ - 'lib/mdqt/client.rb'
177
+
178
+ # Offense count: 1
179
+ # Configuration parameters: CountComments.
180
+ Metrics/MethodLength:
181
+ Max: 13
182
+
183
+ # Offense count: 8
184
+ Style/Documentation:
185
+ Exclude:
186
+ - 'spec/**/*'
187
+ - 'test/**/*'
188
+ - 'lib/mdqt.rb'
189
+ - 'lib/mdqt/cli.rb'
190
+ - 'lib/mdqt/cli/base.rb'
191
+ - 'lib/mdqt/cli/defaults.rb'
192
+ - 'lib/mdqt/cli/get.rb'
193
+ - 'lib/mdqt/client.rb'
194
+ - 'lib/mdqt/client/metadata_service.rb'
195
+
196
+ # Offense count: 1
197
+ # Cop supports --auto-correct.
198
+ Style/Encoding:
199
+ Exclude:
200
+ - 'mdqt.gemspec'
201
+
202
+ # Offense count: 2
203
+ # Cop supports --auto-correct.
204
+ Style/ExpandPathArguments:
205
+ Exclude:
206
+ - 'mdqt.gemspec'
207
+ - 'spec/spec_helper.rb'
208
+
209
+ # Offense count: 16
210
+ # Cop supports --auto-correct.
211
+ # Configuration parameters: EnforcedStyle.
212
+ # SupportedStyles: when_needed, always, never
213
+ Style/FrozenStringLiteralComment:
214
+ Enabled: false
215
+
216
+ # Offense count: 2
217
+ # Cop supports --auto-correct.
218
+ # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
219
+ # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
220
+ Style/HashSyntax:
221
+ Exclude:
222
+ - 'Rakefile'
223
+ - 'lib/mdqt/client/metadata_service.rb'
224
+
225
+ # Offense count: 1
226
+ # Cop supports --auto-correct.
227
+ Style/MutableConstant:
228
+ Exclude:
229
+ - 'lib/mdqt/version.rb'
230
+
231
+ # Offense count: 1
232
+ # Cop supports --auto-correct.
233
+ # Configuration parameters: Whitelist.
234
+ # Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with
235
+ Style/NestedParenthesizedCalls:
236
+ Exclude:
237
+ - 'lib/mdqt/client/metadata_service.rb'
238
+
239
+ # Offense count: 2
240
+ # Cop supports --auto-correct.
241
+ # Configuration parameters: PreferredDelimiters.
242
+ Style/PercentLiteralDelimiters:
243
+ Exclude:
244
+ - 'mdqt.gemspec'
245
+
246
+ # Offense count: 1
247
+ # Cop supports --auto-correct.
248
+ Style/RedundantSelf:
249
+ Exclude:
250
+ - 'lib/mdqt/cli/base.rb'
251
+
252
+ # Offense count: 37
253
+ # Cop supports --auto-correct.
254
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
255
+ # SupportedStyles: single_quotes, double_quotes
256
+ Style/StringLiterals:
257
+ Exclude:
258
+ - 'Rakefile'
259
+ - 'bin/console'
260
+ - 'lib/mdqt.rb'
261
+ - 'lib/mdqt/cli/base.rb'
262
+ - 'lib/mdqt/cli/get.rb'
263
+ - 'lib/mdqt/client/metadata_service.rb'
264
+ - 'lib/mdqt/version.rb'
265
+ - 'mdqt.gemspec'
266
+ - 'spec/mdqt_spec.rb'
267
+ - 'spec/spec_helper.rb'
268
+
269
+ # Offense count: 1
270
+ # Cop supports --auto-correct.
271
+ # Configuration parameters: EnforcedStyleForMultiline.
272
+ # SupportedStylesForMultiline: comma, consistent_comma, no_comma
273
+ Style/TrailingCommaInHashLiteral:
274
+ Exclude:
275
+ - 'lib/mdqt/cli/defaults.rb'
276
+
277
+ # Offense count: 3
278
+ # Cop supports --auto-correct.
279
+ # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
280
+ # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
281
+ Style/TrivialAccessors:
282
+ Exclude:
283
+ - 'lib/mdqt/client.rb'
284
+ - 'lib/mdqt/client/metadata_service.rb'
285
+
286
+ # Offense count: 2
287
+ # Cop supports --auto-correct.
288
+ Style/UnneededPercentQ:
289
+ Exclude:
290
+ - 'mdqt.gemspec'
291
+
292
+ # Offense count: 7
293
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
294
+ # URISchemes: http, https
295
+ Metrics/LineLength:
296
+ Max: 130
@@ -1,5 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1.2
5
- before_install: gem install bundler -v 1.13.5
4
+ - 2.2.2
5
+ - 2.5.0
6
+ - jruby
7
+ before_install: gem install bundler -v 1.16.1
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ ### Improvements
6
+ - Option to cache HTTP requests to the MDQ service
7
+ - Supports Gzip compression by default
8
+ - Supports redirect responses
9
+ - Helpful error messages and status messages
10
+ - Verbose mode will show successful connection information
11
+ - Warnings about unspecified MDQ service
12
+ - Default MDQ service selection (rather crude, maybe not a good idea at all)
13
+ - Catch bad URLs for the MDQ service and fail with a better error message
14
+
15
+ ### Fixes
16
+ - Aggregates are now requested with /entities not /entities/, as per spec
17
+
18
+ ### Other
19
+ - First few Cucumber features to define and test the executable
20
+ - Beginning of an RSpec suit to define the API
21
+ - Minimum version of Ruby is now 2.1, but only 2.2+ is tested using CI
22
+
23
+ ## 0.1.1
24
+
25
+ ### Fixes
26
+ - Bug that prevented the mdqt executable from running outside a Bundler environment
27
+
28
+ ## 0.1.0
29
+
30
+ - Initial release
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in mdq.gemspec
4
4
  gemspec
5
+
6
+ gem 'simplecov', require: false, group: :test
data/README.md CHANGED
@@ -1,23 +1,31 @@
1
1
  # MDQT - A Metadata Query Tool
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/mdqt.svg)](https://badge.fury.io/rb/mdqt) [![Maintainability](https://api.codeclimate.com/v1/badges/111c46aaebfe25e4a4a9/maintainability)](https://codeclimate.com/github/Digital-Identity-Labs/mdqt/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/111c46aaebfe25e4a4a9/test_coverage)](https://codeclimate.com/github/Digital-Identity-Labs/mdqt/test_coverage) [![Build Status](https://travis-ci.org/Digital-Identity-Labs/mdqt.svg?branch=master)](https://travis-ci.org/Digital-Identity-Labs/mdqt)
4
+
3
5
  MDQT is small library and commandline tool to query MDQ services for SAML metadata.
4
- You can do this with `curl` but it's a little more convenient to use `mdqt` instead.
6
+ You could do this with `curl` but it's a little more convenient to use `mdqt` instead.
5
7
 
6
8
  At present `mdqt` does *not* verify signed metadata, so an extra step is required to use it
7
- securely. It is also not yet fully compliant with the MDQ client specification.
9
+ securely.
10
+
11
+ MDQ currently supports:
12
+
13
+ - Downloading single entities, lists or aggregates
14
+ - Caching entity metadata on disk
15
+ - Gzip compression
8
16
 
9
17
  ## MDQ?
10
18
 
11
19
  MDQ is a simple HTTP-based standard for looking up individual SAML entity metadata. Rather than regularly
12
20
  downloading large metadata aggregates containing thousands of entity descriptions,
13
- an IdP or SP can download the metadata for individual entities using MDQ when they are needed.
21
+ an IdP or SP can download the metadata for an individual entity whenever it is needed.
14
22
 
15
23
  The UK Access Management Federation has a
16
24
  [useful page explaining MDQ](https://www.ukfederation.org.uk/content/Documents/MDQ)
17
25
 
18
26
  ## Installation
19
27
 
20
- To add mdqt to a project, add this line to your application's Gemfile
28
+ To add MDQT to a project, include this line in your application's Gemfile
21
29
 
22
30
  ```ruby
23
31
  gem 'mdqt'
@@ -35,33 +43,47 @@ If using a per-user Ruby such via `rbenv` or similar, you'll just need
35
43
 
36
44
  $ gem install mdqt
37
45
 
46
+ MDQT should work with Ruby 2.1.0 or later.
47
+
38
48
  ## Commandline Usage as an MDQ client
39
49
 
40
- You can see a list of commandline options by typing
50
+ You can see a list of commandline options by typing:
41
51
 
42
52
  $ mdqt --help
43
53
 
44
- Specifying the MDQ service with a commandline option
54
+ To see more information about a command, use the `--help` option after the command:
55
+
56
+ $ mdqt get --help
57
+
58
+ Specifying the MDQ service with a commandline option:
45
59
 
46
60
  $ mdqt get --service https://mdq.example.com/mdq http://entity.ac.uk/shibboleth
47
61
 
48
62
  It's more convenient to set an environment variable to specify a default MDQ
49
- service. Set MDQT_SERVICE or MDQ_BASE_URL to the base URL of your MDQ service.
63
+ service. Set `MDQT_SERVICE` or `MDQ_BASE_URL` to the base URL of your MDQ service.
50
64
 
51
- Downloading entity metadata to STDOUT
65
+ Downloading entity metadata to STDOUT:
52
66
 
53
67
  $ mdqt get https://test-idp.ukfederation.org.uk/idp/shibboleth
54
68
 
55
- Using sha1 hashed version of entity IDs requires quotes or escaping
69
+ Using the sha1 hashed version of entity IDs requires quotes or escaping:
56
70
 
57
71
  $ mdqt get "{sha1}52e2065fc0d53744e8d4ee2c2f30696ebfc5def9"
58
72
 
59
73
  $ mdqt get \{sha1\}52e2065fc0d53744e8d4ee2c2f30696ebfc5def9
60
74
 
61
- Requesting all metadata from an MDQ endpoint is done by specifying `--all`
75
+ Requesting all metadata from an MDQ endpoint is done by specifying `--all`:
62
76
 
63
77
  $ mdqt get --all
64
78
 
79
+ Caching can be enabled using `--cache`. At the moment the `mdqt` executable
80
+ only supports caching to disk. It will create a cache directory in your temporary
81
+ directory.
82
+
83
+ $ mdqt get --cache --service https://mdq.example.com/mdq http://entity.ac.uk/shibboleth
84
+
85
+ If you don't specify an MDQ service with `--service' or `MDQT_SERVICE` then `mdqt` *might* be
86
+ able to guess your local NREN's MDQ service. Do not do this in production.
65
87
 
66
88
  ## Library Usage
67
89
 
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
2
 
4
- RSpec::Core::RakeTask.new(:spec)
3
+ Dir.glob('lib/tasks/*.rake').each { |r| load r}
5
4
 
6
- task :default => :spec
5
+ task :default => :tests
data/exe/mdqt CHANGED
@@ -23,14 +23,16 @@ Commander.configure do
23
23
  end
24
24
 
25
25
  command :get do |c|
26
- c.syntax = 'mdqt get [options] [entity id] [entity id] '
26
+ c.syntax = 'mdqt get [options] entityidentifier '
27
27
  c.description = 'Download one entity record or an aggregate of entity records'
28
28
  c.option '--service URL', String, 'MDQ service to search for entities. Defaults to MDQT_SERVICE or MDQ_BASE_URL env variables'
29
+ c.option '--cache', "Cache downloads and try to fetch from cache where appropriate"
29
30
  #c.option '--verify-with PATH', String, 'Validate downloads using specified certificate'
30
31
  #c.option '--stdin', 'accept one or more entity ids from STDIN'
31
32
  c.option '--all', 'Request all entity records'
32
33
  c.action do |args, options|
33
34
  options.default MDQT::CLI::Defaults.cli_defaults
35
+ options.default({service: MDQT::CLI::Defaults.base_url }) if options.service.nil?
34
36
  MDQT::CLI::Get.run(args, options)
35
37
  end
36
38
  end
@@ -5,12 +5,75 @@ module MDQT
5
5
  class Base
6
6
 
7
7
  def self.run(args, options)
8
- self.new.run(args, options)
8
+
9
+ #args = options.stdin ? absorb_piped_args(args) : args
10
+
11
+ check_requirements(args, options)
12
+ introduce(args, options)
13
+
14
+ self.new(args, options).run
15
+ end
16
+
17
+ def self.check_requirements(args, options)
18
+ abort "Error: No MDQ service URL has been specified." unless options.service
19
+ end
20
+
21
+ def self.introduce(args, options)
22
+ if options.verbose
23
+ STDERR.puts "Using #{options.service}"
24
+ STDERR.puts "Caching is #{options.service ? 'on' : 'off'}"
25
+ STDERR.puts
26
+ end
27
+ end
28
+
29
+ def self.absorb_piped_args(args)
30
+ piped = piped? ? parse_stdin : []
31
+ args + piped
32
+ end
33
+
34
+ def self.piped?
35
+ !STDIN.tty? && !STDIN.closed?
36
+ end
37
+
38
+ def self.parse_stdin
39
+ STDIN.gsub("\s", "\n").each_line.collect {|l| l.strip }
40
+ end
41
+
42
+ def initialize(args, options)
43
+ @args = args
44
+ @options = options
45
+ end
46
+
47
+ def args=(new_args)
48
+ @args = new_args
49
+ end
50
+
51
+ def args
52
+ @args
53
+ end
54
+
55
+ def options=(new_options)
56
+ @options = new_options
57
+ end
58
+
59
+ def options
60
+ @options
61
+ end
62
+
63
+ def output(response)
64
+ if response.ok?
65
+ STDERR.puts response.message if options.verbose
66
+ trailer = response.data[-1] == "\n" ? "" : "\n"
67
+ response.data + trailer
68
+ else
69
+ STDERR.puts response.message
70
+ end
71
+
9
72
  end
10
73
 
11
- def run(args, options)
74
+ def run
12
75
 
13
- puts "No action has been defined for this command!"
76
+ abort "No action has been defined for this command!"
14
77
 
15
78
  end
16
79
 
File without changes
File without changes
@@ -6,7 +6,7 @@ module MDQT
6
6
  class << self
7
7
 
8
8
  def base_url
9
- ENV['MDQT_SERVICE'] || ENV['MDQ_BASE_URL'] || 'http://mdq.ukfederation.org.uk/'
9
+ ENV['MDQT_SERVICE'] || ENV['MDQ_BASE_URL'] || guess_service
10
10
  end
11
11
 
12
12
  def force_hash?
@@ -15,11 +15,32 @@ module MDQT
15
15
 
16
16
  def cli_defaults
17
17
  {
18
- service: base_url,
19
18
  hash: force_hash?,
19
+ cache: false
20
20
  }
21
21
  end
22
22
 
23
+ def guess_service
24
+
25
+ locale = ENV['LANG']
26
+
27
+ #STDERR.puts("Detected locale #{locale}")
28
+
29
+ service = case locale
30
+ when 'en_GB.UTF-8'
31
+ 'http://mdq.ukfederation.org.uk/'
32
+ when 'en_US.UTF-8'
33
+ 'http://mdq-beta.incommon.org/global'
34
+ else
35
+ abort "Please specify an MDQ service using --service, MDQT_SERVICE or MDQ_BASE_URL"
36
+ end
37
+
38
+ STDERR.puts "MDQT is assuming that you want to use #{service}\nPlease configure this using --service, MDQT_SERVICE or MDQ_BASE_URL\n\n"
39
+
40
+ service
41
+
42
+ end
43
+
23
44
  end
24
45
 
25
46
  end
@@ -6,26 +6,58 @@ module MDQT
6
6
 
7
7
  class Get < Base
8
8
 
9
- def run(args, options)
9
+ def run
10
10
 
11
- client = MDQT::Client.new(base_url: options.service)
11
+ abort("Please specify --all if you wish to request all entities from #{options.service}") if args.empty? && !options.all
12
12
 
13
- if args.empty?
13
+ results = get_results(args, options)
14
14
 
15
- if options.all
16
- results = [client.get_metadata("")]
17
- else
18
- abort("Please specify --all if you wish to request all entities from #{options.service}")
19
- end
15
+ #results = MetadataValidator.validate_responses(results) if options.validate
20
16
 
17
+ #results = MetadataAggregator.aggregate_responses(results) if options.aggregate
18
+
19
+ output_metadata(results, options)
20
+
21
+ end
22
+
23
+ def get_results(args, options)
24
+
25
+ client = MDQT::Client.new(
26
+ options.service,
27
+ verbose: options.verbose,
28
+ cache_type: options.cache ? :file : :none
29
+ )
30
+
31
+ args.empty? ? [client.get_metadata("")] : args.collect {|entity_id| client.get_metadata(entity_id)}
32
+
33
+ end
34
+
35
+ def output_metadata(results, options)
36
+ case action(results, options)
37
+ when :save_files
38
+ output_files(results, options)
39
+ when :print_to_stdout
40
+ output_to_stdout(results, options)
21
41
  else
22
- results = args.collect {|entity_id| client.get_metadata(entity_id)}
42
+ abort "Error - can't determine output type"
23
43
  end
44
+ end
24
45
 
25
- results.each do |result|
26
- puts result.body
46
+ def action(results, options)
47
+ case
48
+ when options.save
49
+ :save_files
50
+ else
51
+ :print_to_stdout
27
52
  end
53
+ end
54
+
55
+ def output_to_stdout(results, options)
56
+ results.each {|r| puts output(r)}
57
+ end
28
58
 
59
+ def output_files(results, options)
60
+ abort "Unimplemented feature"
29
61
  end
30
62
 
31
63
  end
File without changes
@@ -3,27 +3,40 @@ module MDQT
3
3
 
4
4
  require 'mdqt/client/metadata_service'
5
5
 
6
- def initialize(options={})
6
+ def initialize(base_url, options={})
7
7
 
8
- @base_url = options[:base_url]
9
- @md_service = MetadataService.new(@base_url)
8
+ @base_url = base_url
9
+ @verbose = options[:verbose] || false
10
+ @cache_type = options[:cache_type] || :none
11
+
12
+ @md_service = MetadataService.new(@base_url, verbose: @verbose, cache_type: @cache_type)
10
13
 
11
14
  end
12
15
 
13
16
  def get_metadata(entity_id)
14
17
 
15
- result = md_service.get(entity_id)
18
+ md_service.get(entity_id)
16
19
 
17
20
  end
18
21
 
19
- def md_service
20
- @md_service
21
- end
22
-
23
22
  def base_url
24
23
  @base_url
25
24
  end
26
25
 
26
+ def verbose?
27
+ @verbose
28
+ end
29
+
30
+ def cache_type
31
+ @cache_type
32
+ end
33
+
34
+ private
35
+
36
+ def md_service
37
+ @md_service
38
+ end
39
+
27
40
  end
28
41
 
29
42
  end
@@ -0,0 +1,101 @@
1
+ module MDQT
2
+ class Client
3
+
4
+ class MetadataResponse
5
+
6
+ require 'digest'
7
+
8
+ def initialize(identifier, service, http_response)
9
+
10
+ @requested_identitier = identifier
11
+ @identifier = URI.decode(identifier)
12
+ @service = service
13
+ @code = http_response.status || 500
14
+ @data = http_response.body || ""
15
+ @type = http_response.headers['Content-Type']
16
+ @expires = http_response.headers['Expires']
17
+ @etag = http_response.headers['ETag']
18
+ @last_modified = http_response.headers['Last-Modified']
19
+ @ok = http_response.success?
20
+ end
21
+
22
+ def identifier
23
+ @identifier
24
+ end
25
+
26
+ def requested_identifier
27
+ @identifier
28
+ end
29
+
30
+ def service
31
+ @service
32
+ end
33
+
34
+ def code
35
+ @code
36
+ end
37
+
38
+ def data
39
+ @data || ""
40
+ end
41
+
42
+ def type
43
+ @type
44
+ end
45
+
46
+ def expires
47
+ @expires
48
+ end
49
+
50
+ def etag
51
+ @etag
52
+ end
53
+
54
+ def last_modified
55
+ @last_modified
56
+ end
57
+
58
+ def ok?
59
+ @ok
60
+ end
61
+
62
+ def signed?
63
+ @data.include? "<Signature" # This is... not great
64
+ end
65
+
66
+ def filename
67
+ "#{Digest::SHA1.hexdigest(@identifier)}.xml"
68
+ end
69
+
70
+ def message
71
+ case code
72
+ when 200
73
+ "[200] OK! Data for '#{identifier}' has been downloaded from #{service}"
74
+ when 304
75
+ "[200] OK! Data for '#{identifier}' is already available in a local cache"
76
+ when 400
77
+ "[400] The identifier '#{identifier}' ('#{requested_identifier}') is malformed or service URL #{service} is incorrect"
78
+ when 401
79
+ "[401] Credentials are incorrect or missing for '#{identifier}'"
80
+ when 403
81
+ identifier.empty? ? "[403] The MDQ service at #{service} does not support aggregate downloads" :
82
+ "[403] You do not have access rights to '#{identifier}' at #{service}"
83
+ when 404
84
+ identifier.empty? ? "[404] The MDQ service at #{service} is not responding with aggregated metadata or the correct status" :
85
+ "[404] Entity metadata for '#{identifier}' was not found at #{service}"
86
+ when 405
87
+ "[405] The service at #{service} believes the wrong HTTP method was used. We should have used HTTP GET..."
88
+ when 406
89
+ "[406] The requested content type is not available at #{service}"
90
+ when 505
91
+ "[505] The service at #{service} claims our request was using pre-1999 web protocols, not HTTP 1.1 or later"
92
+ else
93
+ "[#{code}] Sorry - an unknown error has occured requesting '#{identifier}' from #{service}.\nPlease report this bug!"
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -8,10 +8,21 @@ module MDQT
8
8
  require 'typhoeus/adapters/faraday'
9
9
  require 'cgi'
10
10
 
11
- def initialize(base_url)
11
+ require 'faraday_middleware'
12
+ require 'faraday-http-cache'
12
13
 
13
- @base_url = base_url
14
+ require 'active_support/cache'
15
+ require 'active_support/cache/file_store'
16
+ require 'active_support/cache/mem_cache_store'
17
+ require 'active_support/logger'
18
+
19
+ require_relative './metadata_response'
14
20
 
21
+ def initialize(base_url, options = {})
22
+ @base_url = base_url
23
+ @cache_type = options[:cache_type] ? options[:cache_type].to_sym : :none
24
+ @store_config = options[:cache_store]
25
+ @verbose = options[:verbose] ? true : false
15
26
  end
16
27
 
17
28
  def base_url
@@ -22,13 +33,18 @@ module MDQT
22
33
 
23
34
  entity_id = prepare_id(entity_id)
24
35
 
25
- connection.get do |req|
26
- req.url ['entities/', entity_id].join
27
- req.options.timeout = 100
28
- req.options.open_timeout = 5
29
- req.headers['Content-Type'] = 'application/samlmetadata+xml'
30
- req.headers['User-Agent'] = "MDQT v#{MDQT::VERSION}"
36
+ begin
37
+ http_response = connection.get do |req|
38
+ req.url request_path(entity_id)
39
+ req.options.timeout = 100
40
+ req.options.open_timeout = 5
41
+ end
42
+ rescue Faraday::ConnectionFailed => oops
43
+ abort "Error - can't connect to MDQ service at URL #{base_url}"
31
44
  end
45
+
46
+ MetadataResponse.new(entity_id, base_url, http_response)
47
+
32
48
  end
33
49
 
34
50
  def prepare_id(id)
@@ -38,17 +54,83 @@ module MDQT
38
54
  when /^{sha1}/i
39
55
  CGI.escape(id.downcase.strip)
40
56
  when /^\[sha1\]/i
41
- CGI.escape(id.downcase.strip.gsub"[sha1]","{sha1}")
57
+ CGI.escape(id.downcase.strip.gsub "[sha1]", "{sha1}")
42
58
  else
43
59
  CGI.escape(id.strip)
44
60
  end
45
61
  end
46
62
 
63
+ def verbose?
64
+ @verbose
65
+ end
66
+
67
+ def cache?
68
+ cache_type == :none ? false : true
69
+ end
70
+
71
+ def cache_type
72
+ @cache_type || :none
73
+ end
74
+
75
+ def store_config
76
+ @store_config || default_store_config
77
+ end
78
+
79
+ private
80
+
81
+ def request_path(entity_id)
82
+ case entity_id
83
+ when nil, ""
84
+ 'entities'
85
+ else
86
+ ['entities', entity_id].join('/')
87
+ end
88
+ end
89
+
47
90
  def connection
48
91
  Faraday.new(:url => base_url) do |faraday|
49
92
  faraday.request :url_encoded
50
- #faraday.response :logger # log requests to STDOUT
93
+ faraday.use FaradayMiddleware::Gzip
94
+ faraday.use FaradayMiddleware::FollowRedirects
95
+ faraday.use :http_cache, faraday_cache_config if cache?
96
+ faraday.headers['Content-Type'] = 'application/samlmetadata+xml'
97
+ faraday.headers['User-Agent'] = "MDQT v#{MDQT::VERSION}"
51
98
  faraday.adapter :typhoeus
99
+ #faraday.response :logger
100
+ end
101
+ end
102
+
103
+ def default_store_config
104
+ case cache_type
105
+ when :none, nil
106
+ nil
107
+ when :file, :files
108
+ File.absolute_path(File.join(Dir.tmpdir, 'mdqt_cache'))
109
+ when :memcached, :memcache
110
+ 'localhost:11211'
111
+ end
112
+ end
113
+
114
+ def faraday_cache_config
115
+ {
116
+ store: cache_store,
117
+ shared_cache: false,
118
+ serializer: Marshal,
119
+ #logger: cache_logger,
120
+ instrumenter: ActiveSupport::Notifications
121
+ }
122
+ end
123
+
124
+ def cache_logger
125
+ verbose? ? Logger.new('mdqt_cache.log') : nil
126
+ end
127
+
128
+ def cache_store
129
+ case cache_type
130
+ when :file, :files, nil
131
+ @cache_store = ActiveSupport::Cache.lookup_store(:file_store, store_config)
132
+ when :memcache, :memcached
133
+ @cache_store = ActiveSupport::Cache.lookup_store(:mem_cache_store, [store_config])
52
134
  end
53
135
  end
54
136
 
@@ -0,0 +1,23 @@
1
+ module MDQT
2
+ class Client
3
+
4
+ class MetadataValidator
5
+
6
+ def initialize(response)
7
+
8
+ puts response.inspect
9
+
10
+ end
11
+
12
+
13
+ def ok?
14
+ true
15
+ end
16
+
17
+
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -1,3 +1,3 @@
1
1
  module MDQT
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'cucumber'
3
+ require 'cucumber/rake/task'
4
+
5
+ desc "Run Cucumber tests"
6
+ Cucumber::Rake::Task.new(:features) do |t|
7
+ t.cucumber_opts = "features --format pretty"
8
+ end
@@ -0,0 +1,5 @@
1
+ require "rspec/core/rake_task"
2
+
3
+
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,6 @@
1
+
2
+ desc "Run all tests and gather coverage information"
3
+ task :tests => [:spec, :features] do
4
+
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['features/*.feature', 'features/*.rb']
5
+ t.options = ['--any', '--extra', '--opts'] # optional
6
+ end
@@ -9,11 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Pete Birkinshaw"]
10
10
  spec.email = ["pete@digitalidentitylabs.com"]
11
11
 
12
- spec.summary = %q{Library and utility for accessing MDQ services}
13
- spec.description = %q{Library and utility for accessing MDQ service}
12
+ spec.summary = %q{Library and commandline utility for accessing MDQ services}
13
+ spec.description = %q{Library and commandline utility for downloading SAML metadata from MDQ services}
14
14
  spec.homepage = "https://github.com/Digital-Identity-Labs/mdqt"
15
15
  spec.license = "MIT"
16
16
 
17
+ spec.required_ruby_version = '>= 2.1.0'
18
+
17
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
21
  # if spec.respond_to?(:metadata)
@@ -30,13 +32,22 @@ Gem::Specification.new do |spec|
30
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
33
  spec.require_paths = ["lib"]
32
34
 
33
- spec.add_dependency "faraday", "~>0.15"
35
+ spec.add_dependency 'commander', "~>4.4"
36
+ spec.add_dependency 'faraday', "~>0.15"
37
+ spec.add_dependency 'faraday_middleware', "~>0.12"
34
38
  spec.add_dependency 'faraday-http-cache', "~>2.0"
35
- spec.add_dependency "typhoeus", "~>1.3"
36
- spec.add_dependency "commander", "~>4.4"
39
+ spec.add_dependency 'typhoeus', "~>1.3"
40
+ spec.add_dependency 'activesupport', "~>5.2"
41
+ spec.add_dependency 'dalli', "~>2.7"
37
42
 
43
+ #spec.add_dependency 'xmldsig'
38
44
 
39
45
  spec.add_development_dependency "bundler", "~> 1.13"
40
46
  spec.add_development_dependency "rake", "~> 10.0"
41
47
  spec.add_development_dependency "rspec", "~> 3.0"
48
+ spec.add_development_dependency "cucumber", "~> 3.1"
49
+ spec.add_development_dependency "aruba", "~> 0.14"
50
+ spec.add_development_dependency "vcr", "~> 4.0"
51
+ spec.add_development_dependency "yard", "~> 0.9"
52
+ spec.add_development_dependency "yard-cucumber", "~> 4.0"
42
53
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mdqt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Birkinshaw
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-02 00:00:00.000000000 Z
11
+ date: 2018-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: commander
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.4'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday_middleware
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.12'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.12'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: faraday-http-cache
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -53,19 +81,33 @@ dependencies:
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.3'
55
83
  - !ruby/object:Gem::Dependency
56
- name: commander
84
+ name: activesupport
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '4.4'
89
+ version: '5.2'
62
90
  type: :runtime
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '4.4'
96
+ version: '5.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dalli
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.7'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.7'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: bundler
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +150,78 @@ dependencies:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
152
  version: '3.0'
111
- description: Library and utility for accessing MDQ service
153
+ - !ruby/object:Gem::Dependency
154
+ name: cucumber
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: aruba
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.14'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.14'
181
+ - !ruby/object:Gem::Dependency
182
+ name: vcr
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '4.0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '4.0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: yard
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '0.9'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '0.9'
209
+ - !ruby/object:Gem::Dependency
210
+ name: yard-cucumber
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '4.0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '4.0'
223
+ description: Library and commandline utility for downloading SAML metadata from MDQ
224
+ services
112
225
  email:
113
226
  - pete@digitalidentitylabs.com
114
227
  executables:
@@ -118,8 +231,11 @@ extra_rdoc_files: []
118
231
  files:
119
232
  - ".gitignore"
120
233
  - ".rspec"
234
+ - ".rubocop.yml"
235
+ - ".rubocop_todo.yml"
121
236
  - ".ruby-version"
122
237
  - ".travis.yml"
238
+ - CHANGELOG.md
123
239
  - CODE_OF_CONDUCT.md
124
240
  - Gemfile
125
241
  - LICENSE.txt
@@ -131,11 +247,20 @@ files:
131
247
  - lib/mdqt.rb
132
248
  - lib/mdqt/cli.rb
133
249
  - lib/mdqt/cli/base.rb
250
+ - lib/mdqt/cli/clean.rb
251
+ - lib/mdqt/cli/compliance.rb
134
252
  - lib/mdqt/cli/defaults.rb
135
253
  - lib/mdqt/cli/get.rb
254
+ - lib/mdqt/cli/stream.rb
136
255
  - lib/mdqt/client.rb
256
+ - lib/mdqt/client/metadata_response.rb
137
257
  - lib/mdqt/client/metadata_service.rb
258
+ - lib/mdqt/client/metadata_validator.rb
138
259
  - lib/mdqt/version.rb
260
+ - lib/tasks/cucumber.rake
261
+ - lib/tasks/spec.rake
262
+ - lib/tasks/tests.rake
263
+ - lib/tasks/yard.rake
139
264
  - mdqt.gemspec
140
265
  homepage: https://github.com/Digital-Identity-Labs/mdqt
141
266
  licenses:
@@ -149,7 +274,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
274
  requirements:
150
275
  - - ">="
151
276
  - !ruby/object:Gem::Version
152
- version: '0'
277
+ version: 2.1.0
153
278
  required_rubygems_version: !ruby/object:Gem::Requirement
154
279
  requirements:
155
280
  - - ">="
@@ -160,5 +285,5 @@ rubyforge_project:
160
285
  rubygems_version: 2.7.3
161
286
  signing_key:
162
287
  specification_version: 4
163
- summary: Library and utility for accessing MDQ services
288
+ summary: Library and commandline utility for accessing MDQ services
164
289
  test_files: []