access_forge 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48aa9fe17d4661aa26bbcbfa0d23881788f5cc56e1e20cf04584991e7d046050
4
- data.tar.gz: c4fa5e43b04d69a2f0222988404f1291caa6eb711f4adb5ddc17f33d8c6a62b4
3
+ metadata.gz: 5ce9503a123b98c43d0627caf65f3de41581b16a41d142b00d3d00d23d5045bb
4
+ data.tar.gz: fb8a30a4295783dd14bd507a4a8b6c3da67b00128220b13148fe0a6030c49e76
5
5
  SHA512:
6
- metadata.gz: c0503b9ef7b6d4d60780044947f2e6dee0db5e36b5c40a4815b7101ebe5e88a60139e0547a4e8ff09b42d941bb31eb78c45b5ac64f928f6ccde0db555b2233eb
7
- data.tar.gz: c301490d1b7d795ca3676398041dfac4b9b6b6361129f6b4218c36664cdd18bf92d8e6e6f18031dea4f8016753da90a0dac1ccb3163c00c58e61725ba03d81b0
6
+ metadata.gz: 640ed26fed01e313e9ed8219802dc2b12d83065a22aac5184b03594fad2a1031f1ee3a3a9d04577d4de085d7faf170e677b3c8c69b919715927486394cca09c5
7
+ data.tar.gz: d52746024392d65f39601b84c42cfd8ed0ed9f6be38b5efe2711f23422745fb3a3540bc3f07c3046a7a28a262c076f0be2db421a2f577168d536859a5efc3b3c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- access_forge (0.1.0)
4
+ access_forge (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -49,6 +49,7 @@ GEM
49
49
  unicode-display_width (2.5.0)
50
50
 
51
51
  PLATFORMS
52
+ aarch64-linux
52
53
  x86_64-darwin-20
53
54
 
54
55
  DEPENDENCIES
data/README.md CHANGED
@@ -1,34 +1,237 @@
1
1
  # AccessForge
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ AccessForge is a controller-oriented authorization engine with composable rule objects for Ruby on Rails.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/access_forge`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ It provides:
6
+ * Convention-based policy resolution
7
+ * Action-oriented authorization methods
8
+ * Composable, reusable policy rules
9
+ * A clean extension surface for custom authorization strategies
6
10
 
7
- ## Installation
11
+ AccessForge treats authorization as an application concern at the controller boundary — explicit, testable, and decoupled from persistence.
12
+
13
+ ## Why AccessForge?
14
+
15
+ AccessForge is designed around three principles:
16
+ 1. Authorization decisions occur at the controller boundary.
17
+ 2. Authorization should be explicit per action.
18
+ 3. Authorization logic should be reusable and composable.
19
+
20
+ Rather than embedding complex logic directly inside policy methods, AccessForge encourages the use of Policy Rule classes — small, focused, testable units of authorization behavior.
21
+
22
+ This keeps policies readable while allowing authorization strategies to evolve independently.
23
+
24
+ ## Design Philosophy
25
+
26
+ AccessForge separates policy orchestration from authorization strategy.
8
27
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
28
+ It does not impose a persistence model or assume how permissions are stored. Instead, it provides a composable rule system that allows you to implement your own authorization strategy.
10
29
 
11
- Install the gem and add to the application's Gemfile by executing:
30
+ Authorization strategies such as group-based RBAC can be implemented via extension gems without modifying your policies.
12
31
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
32
+ Policies remain stable. Strategies remain replaceable.
14
33
 
15
- If bundler is not being used to manage dependencies, install the gem by executing:
34
+ ## Installation
35
+
36
+ Add this line to your application's Gemfile:
16
37
 
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
38
+ ```ruby
39
+ gem 'access_forge'
40
+ ```
41
+
42
+ Then execute:
43
+ ```bash
44
+ bundle install
45
+ ```
18
46
 
19
47
  ## Usage
20
48
 
21
- TODO: Write usage instructions here
49
+ ### Step 1: Enable policy resolution in your controllers
50
+
51
+ Include `AccessForge::ControllerHelpers` to enable convention-based policy resolution:
52
+
53
+ ```
54
+ class ApplicationController < ActionController::API
55
+ include AccessForge::ControllerHelpers
56
+ end
57
+ ```
58
+
59
+ ### Step 2: Register the authorization hook
60
+
61
+ Register the `authorize_user!` hook to enforce authorization before each action:
62
+
63
+ ```
64
+ class ApplicationController < ActionController::API
65
+ include AccessForge::ControllerHelpers
66
+
67
+ before_action :authorize_user!
68
+ end
69
+ ```
70
+
71
+ ### Step 3: Define your policy classes
72
+
73
+ AccessForge resolves policy classes using controller naming conventions.
74
+
75
+ For example:
76
+ * `EmployeesController` → `EmployeePolicy`
77
+
78
+ Policies should inherit from `AccessForge::Policy`, either directly or via an application-level base policy.
79
+
80
+ ```
81
+ class ApplicationPolicy < AccessForge::Policy
82
+ end
83
+
84
+ class EmployeePolicy < ApplicationPolicy
85
+ end
86
+ ```
87
+
88
+ If you need to override the default resolution behavior, you may define #policy_class in your controller:
89
+
90
+ ```
91
+ class EmployeesController < ApplicationController
92
+ def policy_class
93
+ DifferentPolicy
94
+ end
95
+ end
96
+ ```
97
+
98
+ ### Step 4: Implement policy methods
99
+
100
+ For each controller action, AccessForge calls the corresponding predicate method on the policy.
101
+
102
+ For example:
103
+ * `show` → `show?`
104
+ * `create` → `create?`
105
+
106
+ Each method should return `true` or `false`.
107
+
108
+ A false result will prevent the action from being performed and return a 401 response. A true result allows execution to proceed.
109
+
110
+ ```
111
+ class EmployeePolicy < ApplicationPolicy
112
+ def index?
113
+ true
114
+ end
115
+
116
+ def create?
117
+ false
118
+ end
119
+ end
120
+ ```
121
+
122
+ If multiple actions share identical logic, you may use:
123
+ * `can_read?` for `index` and `show`
124
+ * `can_write?` for `create`, `update`, and `destroy`
125
+
126
+ ```
127
+ class EmployeePolicy < ApplicationPolicy
128
+ def can_read?
129
+ true
130
+ end
131
+
132
+ def can_write?
133
+ false
134
+ end
135
+ end
136
+ ```
137
+
138
+ ### Step 5: Extract reusable logic with Policy Rules
139
+
140
+ Up until now, authorization logic has lived directly inside policy methods.
141
+
142
+ For reusable or cross-cutting logic, AccessForge provides Policy Rules.
143
+
144
+ Policy Rules allow authorization behavior to be extracted, composed, and reused across policies without coupling policies to persistence or infrastructure concerns.
145
+
146
+ `AccessForge::Policy` exposes an `authorized?` helper:
147
+
148
+ ```
149
+ authorized?(rules, options = {})
150
+ ```
151
+
152
+ * `rules` — an array of Policy Rule classes
153
+ * `options` — optional parameters passed to each rule
154
+
155
+ If any rule returns `true`, authorization succeeds.
156
+
157
+ AccessForge includes two default rules:
158
+ * `OpenPolicyRule` — always grants access
159
+ * `ClosedPolicyRule` — always denies access
160
+
161
+ ```
162
+ module AccessForge
163
+ class OpenPolicyRule
164
+ def self.authorized?(_user, _controller, _options)
165
+ true
166
+ end
167
+ end
168
+
169
+ class ClosedPolicyRule
170
+ def self.authorized?(_user, _controller, _options)
171
+ false
172
+ end
173
+ end
174
+ end
175
+ ```
176
+
177
+ You may define custom rules:
178
+
179
+ ```
180
+ class PermissionPolicyRule
181
+ def self.authorized?(user, _controller, options)
182
+ permission_name = "Can #{options[:verb]} #{options[:feature]}"
183
+ user.permissions.exists?({ permissions: { name: permission_name } })
184
+ end
185
+ end
186
+
187
+ class EmployeePolicy < ApplicationPolicy
188
+ def index?
189
+ authorized?(
190
+ [ PermissionPolicyRule ],
191
+ { feature: 'Employees', verb: :read }
192
+ )
193
+ end
194
+ end
195
+ ```
196
+
197
+ This approach keeps policy classes focused while allowing authorization strategies to scale independently.
198
+
199
+ ## Extensions
200
+
201
+ AccessForge is designed to be extended.
202
+
203
+ Official and third-party extensions may provide:
204
+ * Persistence-backed authorization strategies
205
+ * RBAC implementations
206
+ * Alternative rule sets
207
+ * Integration layers
208
+
209
+ Because policies depend only on rule interfaces, new strategies can be introduced without rewriting existing policies.
22
210
 
23
211
  ## Development
24
212
 
25
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
213
+ After checking out the repository:
214
+ ```
215
+ bin/setup
216
+ rake spec
217
+ ```
26
218
 
27
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
219
+ To release a new version:
220
+ 1. Update the version number in `version.rb`
221
+ 2. Run:
222
+ ```
223
+ bundle exec rake release
224
+ ```
225
+
226
+ This will tag the release, push commits, and publish the gem to RubyGems.
28
227
 
29
228
  ## Contributing
30
229
 
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/access_forge. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/access_forge/blob/main/CODE_OF_CONDUCT.md).
230
+ Bug reports and pull requests are welcome on GitHub:
231
+
232
+ [https://github.com/CodeTectonics/access_forge](https://github.com/CodeTectonics/access_forge).
233
+
234
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/CodeTectonics/access_forge/blob/main/CODE_OF_CONDUCT.md).
32
235
 
33
236
  ## License
34
237
 
@@ -36,4 +239,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
36
239
 
37
240
  ## Code of Conduct
38
241
 
39
- Everyone interacting in the AccessForge project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/access_forge/blob/main/CODE_OF_CONDUCT.md).
242
+ Everyone interacting in the AccessForge project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/CodeTectonics/access_forge/blob/main/CODE_OF_CONDUCT.md).
data/access_forge.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Mark Harbison"]
9
9
  s.email = ["mark@tyne-solutions.com"]
10
10
 
11
- s.summary = "A simple, extendable authorization framework for Ruby on Rails applications."
12
- s.description = "A simple, extendable authorization framework for Ruby on Rails applications."
11
+ s.summary = "Controller-oriented authorization with composable rule objects."
12
+ s.description = "Controller-oriented authorization with composable rule objects."
13
13
  s.homepage = "https://github.com/CodeTectonics/access_forge"
14
14
  s.license = "MIT"
15
15
  s.required_ruby_version = ">= 2.6.0"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AccessForge
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: access_forge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Harbison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-28 00:00:00.000000000 Z
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.7'
55
- description: A simple, extendable authorization framework for Ruby on Rails applications.
55
+ description: Controller-oriented authorization with composable rule objects.
56
56
  email:
57
57
  - mark@tyne-solutions.com
58
58
  executables: []
@@ -106,10 +106,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  - !ruby/object:Gem::Version
107
107
  version: '0'
108
108
  requirements: []
109
- rubygems_version: 3.4.21
109
+ rubygems_version: 3.4.19
110
110
  signing_key:
111
111
  specification_version: 4
112
- summary: A simple, extendable authorization framework for Ruby on Rails applications.
112
+ summary: Controller-oriented authorization with composable rule objects.
113
113
  test_files:
114
114
  - spec/closed_policy_rule_spec.rb
115
115
  - spec/dummy/dummy_controller.rb