pragma-policy 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3558b9e18dec8f44921f49f1390ac27ec81d0633
4
+ data.tar.gz: ae90ff0b36bbd2ba93c66af2f33f540727517140
5
+ SHA512:
6
+ metadata.gz: e3dfe25ea37762ef45e30d474a5176d38f558d528f0352b3cc342a4f18c1508e9c8fe8f6605b67082ef5a8fa06f352bad19a6df420b8d42b2f5d8aa2acfdbeac
7
+ data.tar.gz: 3d15e2cceb67dc0236f0d9204d3938f0e248946688d07346e4f19bb572ae68b2767987fd1c34a8210659e681f1ee2e29d748164d57a46b487f813cf546d1f6bd
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /spec/examples.txt
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,84 @@
1
+ require: rubocop-rspec
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.3
5
+ Include:
6
+ - '**/Gemfile'
7
+ - '**/Rakefile'
8
+ Exclude:
9
+ - 'bin/*'
10
+ - 'db/**/*'
11
+ - 'vendor/bundle/**/*'
12
+ - 'spec/spec_helper.rb'
13
+ - 'spec/rails_helper.rb'
14
+ - 'spec/support/**/*'
15
+ - 'config/**/*'
16
+ - '**/Rakefile'
17
+ - '**/Gemfile'
18
+
19
+ RSpec/DescribeClass:
20
+ Exclude:
21
+ - 'spec/requests/**/*'
22
+
23
+ Style/BlockDelimiters:
24
+ Exclude:
25
+ - 'spec/**/*'
26
+
27
+ Style/AlignParameters:
28
+ EnforcedStyle: with_fixed_indentation
29
+
30
+ Style/ClosingParenthesisIndentation:
31
+ Enabled: false
32
+
33
+ Metrics/LineLength:
34
+ Max: 100
35
+ AllowURI: true
36
+
37
+ Style/FirstParameterIndentation:
38
+ Enabled: false
39
+
40
+ Style/MultilineMethodCallIndentation:
41
+ EnforcedStyle: indented
42
+
43
+ Style/IndentArray:
44
+ EnforcedStyle: consistent
45
+
46
+ Style/IndentHash:
47
+ EnforcedStyle: consistent
48
+
49
+ Style/SignalException:
50
+ EnforcedStyle: semantic
51
+
52
+ Style/BracesAroundHashParameters:
53
+ EnforcedStyle: context_dependent
54
+
55
+ Lint/EndAlignment:
56
+ AlignWith: variable
57
+ AutoCorrect: true
58
+
59
+ Style/AndOr:
60
+ EnforcedStyle: conditionals
61
+
62
+ Style/MultilineBlockChain:
63
+ Enabled: false
64
+
65
+ RSpec/NamedSubject:
66
+ Enabled: false
67
+
68
+ RSpec/ExampleLength:
69
+ Enabled: false
70
+
71
+ Style/MultilineMethodCallBraceLayout:
72
+ Enabled: false
73
+
74
+ Metrics/MethodLength:
75
+ Enabled: false
76
+
77
+ Metrics/AbcSize:
78
+ Enabled: false
79
+
80
+ Metrics/PerceivedComplexity:
81
+ Enabled: false
82
+
83
+ Metrics/CyclomaticComplexity:
84
+ Enabled: false
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.13.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pragma-policy.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Alessandro Desantis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,182 @@
1
+ # Pragma::Policy
2
+
3
+ [![Build Status](https://img.shields.io/travis/pragmarb/pragma-policy.svg?maxAge=3600&style=flat-square)](https://travis-ci.org/pragmarb/pragma-policy)
4
+ [![Dependency Status](https://img.shields.io/gemnasium/pragmarb/pragma-policy.svg?maxAge=3600&style=flat-square)](https://gemnasium.com/github.com/pragmarb/pragma-policy)
5
+ [![Code Climate](https://img.shields.io/codeclimate/github/pragmarb/pragma-policy.svg?maxAge=3600&style=flat-square)](https://codeclimate.com/github/pragmarb/pragma-policy)
6
+ [![Coveralls](https://img.shields.io/coveralls/pragmarb/pragma-policy.svg?maxAge=3600&style=flat-square)](https://coveralls.io/github/pragmarb/pragma-policy)
7
+
8
+ Policies provide fine-grained access control for your API resources.
9
+
10
+ They are built on top of [Reform](https://github.com/apotonick/reform).
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'pragma-policy'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ ```console
23
+ $ bundle
24
+ ```
25
+
26
+ Or install it yourself as:
27
+
28
+ ```console
29
+ $ gem install pragma-policy
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ To create a policy, simply inherit from `Pragma::Policy::Base`:
35
+
36
+ ```ruby
37
+ module API
38
+ module V1
39
+ module Post
40
+ class Policy < Pragma::Policy::Base
41
+ end
42
+ end
43
+ end
44
+ end
45
+ ```
46
+
47
+ By default, the policy does not return any objects and forbids all operations.
48
+
49
+ You can start customizing your policy by defining a scope and operation predicates:
50
+
51
+ ```ruby
52
+ module API
53
+ module V1
54
+ module Post
55
+ class Policy < Pragma::Policy::Base
56
+ def self.accessible_by(user:, scope:)
57
+ scope.where('published = ? OR author_id = ?', true, user.id)
58
+ end
59
+
60
+ def show?
61
+ resource.published? || resource.author_id == user.id
62
+ end
63
+
64
+ def update?
65
+ resource.author_id == user.id
66
+ end
67
+
68
+ def destroy?
69
+ resource.author_id == user.id
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ ```
76
+
77
+ You are ready to use your policy!
78
+
79
+ ### Retrieving records
80
+
81
+ To retrieve all the records accessible by a user, use the `.accessible_by` class method:
82
+
83
+ ```ruby
84
+ posts = API::V1::Post::Policy.accessible_by(user: user, scope: Post.all)
85
+ ```
86
+
87
+ ### Authorizing operations
88
+
89
+ To authorize an operation, first instantiate the policy, then use the predicate methods:
90
+
91
+ ```ruby
92
+ policy = API::V1::Post::Policy.new(user: user, resource: post)
93
+ fail 'You cannot update this post!' unless policy.update?
94
+ ```
95
+
96
+ Since raising when the operation is forbidden is so common, we provide bang methods a shorthand
97
+ syntax. `Pragma::Policy::ForbiddenError` is raised if the predicate method returns `false`:
98
+
99
+ ```ruby
100
+ policy = API::V1::Post::Policy.new(user: user, resource: post)
101
+ policy.update! # raises if the user cannot update the post
102
+ ```
103
+
104
+ ### Attribute-level authorization
105
+
106
+ In some cases, you'll want to prevent a user from updating a certain attribute. You can do that with
107
+ the `#authorize_attr` method:
108
+
109
+ ```ruby
110
+ module API
111
+ module V1
112
+ module Post
113
+ class Policy < Pragma::Policy::Base
114
+ def update?
115
+ # admins can do whatever they want
116
+ return true if user.admin?
117
+
118
+ (
119
+ resource.author_id == user.id &&
120
+ # regular users cannot change the 'featured' attribute
121
+ authorize_attr(:featured)
122
+ )
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ ```
129
+
130
+ You can also allow specific values for an enumerated attribute:
131
+
132
+ ```ruby
133
+ module API
134
+ module V1
135
+ module Post
136
+ class Policy < Pragma::Policy::Base
137
+ def update?
138
+ # admins can do whatever they want
139
+ return true if user.admin?
140
+
141
+ (
142
+ resource.author_id == user.id &&
143
+ # regular users can only set status to 'draft' or 'published'
144
+ authorize_attr(:status, only: ['draft', 'published'])
145
+ )
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ ```
152
+
153
+ Or you can invert the condition and specify the forbidden attributes:
154
+
155
+ ```ruby
156
+ module API
157
+ module V1
158
+ module Post
159
+ class Policy < Pragma::Policy::Base
160
+ def update?
161
+ # admins can do whatever they want
162
+ return true if user.admin?
163
+
164
+ (
165
+ resource.author_id == user.id &&
166
+ # regular users cannot set the status to 'rejected'
167
+ authorize_attr(:status, except: ['rejected'])
168
+ )
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ ```
175
+
176
+ ## Contributing
177
+
178
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pragmarb/pragma-policy.
179
+
180
+ ## License
181
+
182
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pragma/policy"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'pragma/policy/version'
3
+ require 'pragma/policy/base'
4
+ require 'pragma/policy/attribute_authorizer'
5
+
6
+ module Pragma
7
+ # Fine-grained access control for your API resources.
8
+ #
9
+ # @author Alessandro Desantis
10
+ module Policy
11
+ end
12
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+ module Pragma
3
+ module Policy
4
+ # The attribute authorizer provides attribute-level authorization for resource updates.
5
+ #
6
+ # It allows you to specify whether a resource attribute can be changed and, if you want, what
7
+ # values should be allowed.
8
+ #
9
+ # If you want, you can subclass this base authorizer to avoid repeating code.
10
+ #
11
+ # @author Alessandro Desantis
12
+ class AttributeAuthorizer
13
+ # @!attribute [r] resource
14
+ # @return [ActiveRecord::Base|Reform::Form] the resource being authorized
15
+ #
16
+ # @!attribute [r] attribute
17
+ # @return [Symbol] the attribute being authorized
18
+ attr_reader :resource, :attribute
19
+
20
+ # Initializes the authorizer.
21
+ #
22
+ # @param resource [ActiveRecord::Base|Reform::Form] the resource being authorized
23
+ # @param attribute [Symbol] the attribute being authorized
24
+ #
25
+ # @raise [UnknownEngineError] if the resource is not based on Reform or ActiveRecord
26
+ def initialize(resource:, attribute:)
27
+ @resource = resource
28
+ @attribute = attribute
29
+
30
+ validate_resource
31
+ end
32
+
33
+ # Returns the old value of the attribute (if any).
34
+ #
35
+ # For Reform, this retrieves the current value of the attribute from the model. For
36
+ # ActiveRecord, uses the +<attribute>_was+ method.
37
+ #
38
+ # @return [Object|NilClass]
39
+ def old_value
40
+ case resource_engine
41
+ when :reform
42
+ resource.model.send(attribute)
43
+ when :active_record
44
+ resource.send("#{attribute}_was")
45
+ end
46
+ end
47
+
48
+ # Returns the new (i.e. current) value of the attribute.
49
+ #
50
+ # Simply sends the attribute name to the resource.
51
+ #
52
+ # @return [Object]
53
+ def new_value
54
+ resource.send(attribute)
55
+ end
56
+
57
+ # Returns whether the attribute has changed, by comparing the new and the old value.
58
+ #
59
+ # @return [Boolean]
60
+ def changed?
61
+ old_value != new_value
62
+ end
63
+
64
+ # Returns the engine used for the resource being authorized (Reform or ActiveRecord).
65
+ #
66
+ # @return [Symbol] +:reform+ or +:active_record+
67
+ #
68
+ # @raise [UnknownEngineError] if the engine cannot be detected
69
+ def resource_engine
70
+ if defined?(Reform::Form) && resource.is_a?(Reform::Form)
71
+ :reform
72
+ elsif defined?(ActiveRecord::Base) && resource.is_a?(ActiveRecord::Base)
73
+ :active_record
74
+ else
75
+ fail UnknownEngineError(resource: resource, attribute: attribute)
76
+ end
77
+ end
78
+
79
+ # Ensures that the attribute was changed according to the provided options.
80
+ #
81
+ # When neither +only+ nor +except+ are passed, simply ensures that the attribute was not
82
+ # changed.
83
+ #
84
+ # When +only+ is passed and is not empty, ensures that the value is part of the given array.
85
+ #
86
+ # When +except+ is passed and not empty, also ensures that the value is NOT part of the given
87
+ # array.
88
+ #
89
+ # @param options [Hash] a hash of options
90
+ #
91
+ # @option options [Array<String>] :only an optional list of allowed values
92
+ # @option options [Array<String>] :except an optional list of forbidden values
93
+ #
94
+ # @return [Boolean] whether the attribute has an authorized value
95
+ def authorize(options = {})
96
+ options[:only] = ([options[:only]] || []).flatten.map(&:to_s).reject(&:empty?)
97
+ options[:except] = ([options[:except]] || []).flatten.map(&:to_s).reject(&:empty?)
98
+
99
+ if options[:only].any? && options[:except].any?
100
+ fail(
101
+ ArgumentError,
102
+ 'The :only and :except options cannot be used at the same time.'
103
+ )
104
+ end
105
+
106
+ return true unless changed?
107
+
108
+ if options[:only].any?
109
+ options[:only].include?(new_value.to_s)
110
+ elsif options[:except].any?
111
+ !options[:except].include?(new_value.to_s)
112
+ end || false
113
+ end
114
+
115
+ private
116
+
117
+ def validate_resource
118
+ resource_engine
119
+ end
120
+
121
+ # This error when the engine behind a resource cannot be detected for attribute authorization.
122
+ #
123
+ # @author Alessanro Desantis
124
+ class UnknownEngineError < StandardError
125
+ MESSAGE = 'Attribute authorization only works with Reform forms and ActiveRecord models.'
126
+
127
+ # @!attribute [r] resource
128
+ # @return [Object] the resource
129
+ attr_reader :resource
130
+
131
+ # Initializes the error.
132
+ #
133
+ # @param resource [Object] the resource
134
+ def initialize(resource:)
135
+ @resource = resource
136
+
137
+ super MESSAGE
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+ module Pragma
3
+ module Policy
4
+ # This is the base policy class that all your resource-specific policies should inherit from.
5
+ #
6
+ # A policy provides predicate methods for determining whether a user can perform a specific
7
+ # action on a resource.
8
+ #
9
+ # @author Alessandro Desantis
10
+ #
11
+ # @abstract Subclass and implement action methods to create a policy.
12
+ class Base
13
+ # @!attribute [r] user
14
+ # @return [Object] the user operating on the resource
15
+ #
16
+ # @!attribute [r] resource
17
+ # @return [Object] the resource being operated on
18
+ attr_reader :user, :resource
19
+
20
+ # Returns the records accessible by the given user.
21
+ #
22
+ # @param user [Object] the user accessing the records
23
+ # @param relation [Object] the relation to use as a base
24
+ #
25
+ # @return [Object]
26
+ #
27
+ # @abstract Override to implement retrieving the accessible records
28
+ def self.accessible_by(user, relation:) # rubocop:disable Lint/UnusedMethodArgument
29
+ fail NotImplementedError
30
+ end
31
+
32
+ # Initializes the policy.
33
+ #
34
+ # @param user [Object] the user operating on the resource
35
+ # @param resource [Object] the resource being operated on
36
+ def initialize(user:, resource:)
37
+ @user = user
38
+ @resource = resource
39
+ end
40
+
41
+ # Returns whether the policy responds to the provided missing method.
42
+ #
43
+ # Supports bang forms of predicates (+create!+, +update!+ etc.).
44
+ #
45
+ # @param method_name [String] the method name
46
+ # @param include_private [Boolean] whether to consider private methods
47
+ #
48
+ # @return [Boolean]
49
+ def respond_to_missing?(method_name, include_private = false)
50
+ return super unless method_name[-1] == '!'
51
+ respond_to?("#{method_name[0..-2]}?", include_private) || super
52
+ end
53
+
54
+ # Provides bang form of predicates (+create!+, +update!+ etc.).
55
+ #
56
+ # @param method_name [String] the method name
57
+ # @param *args [Array<Object>] the method arguments
58
+ #
59
+ # @return [Object]
60
+ def method_missing(method_name, *args, &block)
61
+ return super unless method_name[-1] == '!'
62
+ authorize method_name[0..-2], *args
63
+ end
64
+
65
+ # Authorizes the user to perform the given action. If not authorized, raises a
66
+ # {ForbiddenError}.
67
+ #
68
+ # @param action [Symbol] the action to authorize
69
+ #
70
+ # @raise [ArgumentError] if the action is not defined in this policy
71
+ # @raise [ForbiddenError] if the user is not authorized to perform the action
72
+ def authorize(action)
73
+ unless respond_to?("#{action}?")
74
+ fail(
75
+ ArgumentError,
76
+ "'#{action}' is not a valid action for this policy."
77
+ )
78
+ end
79
+
80
+ return if send("#{action}?")
81
+
82
+ fail(
83
+ ForbiddenError,
84
+ user: user,
85
+ action: action,
86
+ resource: resource
87
+ )
88
+ end
89
+
90
+ protected
91
+
92
+ # Authorizes a resource attribute.
93
+ #
94
+ # @param attribute [Symbol] the name of the attribute
95
+ # @param options [Hash] options (see {AttributeAuthorizer#authorize} for allowed options)
96
+ #
97
+ # @return [Boolean] whether the attribute's value is allowed
98
+ def authorize_attr(attribute, options = {})
99
+ AttributeAuthorizer.new(
100
+ resource: resource,
101
+ attribute: attribute
102
+ ).authorize(options)
103
+ end
104
+ end
105
+
106
+ # This error is raised when a user attempts to perform an unauthorized operation on a
107
+ # resource.
108
+ #
109
+ # @author Alessandro Desantis
110
+ class ForbiddenError < StandardError
111
+ MESSAGE = "User is not authorized to perform the '%{action}' action on this resource."
112
+
113
+ # @!attribtue [r] user
114
+ # @return [Object] the user operating on the resource
115
+ #
116
+ # @!attribute [r] action
117
+ # @return [Symbol] the attempted action
118
+ #
119
+ # @!attribute [r] resource
120
+ # @return [Object] the resource being operated on
121
+ attr_reader :user, :action, :resource
122
+
123
+ # Initializes the error.
124
+ #
125
+ # @param user [Object] the user operating on the resource
126
+ # @param action [Symbol] the attempted action
127
+ # @param resource [Object] the resource being operated on
128
+ def initialize(user:, action:, resource:)
129
+ @user = user
130
+ @action = action.to_sym
131
+ @resource = resource
132
+
133
+ super MESSAGE.gsub('%{action}', action.to_s)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module Pragma
3
+ module Policy
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pragma/policy/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pragma-policy"
8
+ spec.version = Pragma::Policy::VERSION
9
+ spec.authors = ["Alessandro Desantis"]
10
+ spec.email = ["desa.alessandro@gmail.com"]
11
+
12
+ spec.summary = 'Fine-grained access control for your API resources.'
13
+ spec.homepage = "https://github.com/pragmarb/pragma-policy"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rubocop"
27
+ spec.add_development_dependency "rubocop-rspec"
28
+ spec.add_development_dependency "coveralls"
29
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pragma-policy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alessandro Desantis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - desa.alessandro@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - lib/pragma/policy.rb
115
+ - lib/pragma/policy/attribute_authorizer.rb
116
+ - lib/pragma/policy/base.rb
117
+ - lib/pragma/policy/version.rb
118
+ - pragma-policy.gemspec
119
+ homepage: https://github.com/pragmarb/pragma-policy
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.5.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Fine-grained access control for your API resources.
143
+ test_files: []