yes-auth 1.0.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b8e3b75db27fa4e2079f268a02bbb3a3d3321a65dc25d7d167888cf8d7f222e
4
- data.tar.gz: 3def0c48b89e0a3b42032d215d574c6cfb388a8ca40b08d3d07045665520e907
3
+ metadata.gz: '014009744d8d8f4feb38d63ed996bbc9b7d28884b45e9ad8acbee77214013d09'
4
+ data.tar.gz: 906951c894c99d3135c3efff97df909354fd1c942b54ca0f7db587c587fc699b
5
5
  SHA512:
6
- metadata.gz: 60b40d20b625ca87978ed8238d7bb4f5d571217afeca6eb809cfaaff960d9278ff05c88d888740ae7dca9f059d90a07f8e2e552eb5f09ff762ee13df91a3e828
7
- data.tar.gz: 6f7bccb82e4c9b9f4074e76e9595454e1153a3cbb6147fc1dbe86aaf29c4e525aaf84580749dba78a08c6ac259ac44fe78ae1dae1072431f7d5e3d8a2a9db7d0
6
+ metadata.gz: 0d9bbc394efc60af86ced946a884a7cc6278181182434a4bd217cb81885aadb63edc3601efb8e34d8d5cef0c91f4f69f58e6a537a6a8217e22293114c69df9f6
7
+ data.tar.gz: 810e25ed15de0d2612916524d31c22c7b008b83f1d6a18b08dec9821980ec238921276b1e6efa8b93947c863ce3ccff5c04bb39a81afcf6294e94d17881e5c70
data/CHANGELOG.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## [1.0.0] - 2026-03-25
3
+ ## [1.1.0] - 2026-04-28
4
+
5
+ - See root CHANGELOG.md for details.
4
6
 
5
- ### Added
7
+ ## [1.0.0] - 2026-03-25
6
8
 
7
- - Initial release
8
- - Authorization principal models (User, Role, ReadResourceAccess, WriteResourceAccess)
9
- - Cerbos principal data builders for read and write resource access
9
+ - Initial open-source release (see root CHANGELOG.md for details)
data/README.md CHANGED
@@ -110,15 +110,47 @@ Yes::Core.configure do |config|
110
110
  end
111
111
  ```
112
112
 
113
- ## Database Schema
113
+ ## Database Setup
114
114
 
115
- The gem expects the following tables to exist:
115
+ Generate the required auth principal migrations:
116
116
 
117
- - `auth_principals_users` - stores user principals
117
+ ```bash
118
+ rails generate yes:auth:install
119
+ ```
120
+
121
+ This creates migrations for all principal tables. You can also generate them individually:
122
+
123
+ ```bash
124
+ rails generate yes:auth:principals:user
125
+ rails generate yes:auth:principals:role
126
+ rails generate yes:auth:principals:user_role
127
+ rails generate yes:auth:principals:read_resource_access
128
+ rails generate yes:auth:principals:write_resource_access
129
+ ```
130
+
131
+ Then run the migrations:
132
+
133
+ ```bash
134
+ rails db:migrate
135
+ ```
136
+
137
+ This creates the following tables:
138
+
139
+ - `auth_principals_users` - stores user principals with identity and auth attributes
118
140
  - `auth_principals_roles` - stores named roles
119
141
  - `auth_principals_read_resource_accesses` - stores read resource access records
120
142
  - `auth_principals_write_resource_accesses` - stores write resource access records
121
- - A join table for the users-roles HABTM association
143
+ - A join table for the users-roles HABTM association with UUID foreign keys
144
+
145
+ ### Subscriptions
146
+
147
+ The auth principal read models are kept in sync via event subscriptions. Register them in your subscription setup (e.g., in a Rake task or initializer):
148
+
149
+ ```ruby
150
+ Yes::Auth::Subscriptions.call(subscriptions)
151
+ ```
152
+
153
+ This subscribes builders for all four principal models to their respective authorization events (e.g., `Authorization::PrincipalRoleAdded`, `Authorization::WriteResourceAccessAttributeChanged`, etc.).
122
154
 
123
155
  ## Development
124
156
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ # Base class for auth principal migration generators
9
+ #
10
+ # Provides shared migration generation logic including timestamp calculation,
11
+ # existence checking, and template rendering.
12
+ #
13
+ # @abstract Subclass and implement {#_table_name} and {#_source_template}
14
+ class BaseGenerator < Rails::Generators::Base
15
+ include ::Rails::Generators::Migration
16
+
17
+ hide!
18
+
19
+ # Calculates the next migration number based on existing migrations
20
+ #
21
+ # @param migrations_root [String] path to the migrations directory
22
+ # @return [String] the next migration number as a timestamp string
23
+ def self.next_migration_number(migrations_root)
24
+ paths = Dir["#{migrations_root}/*.rb"].map do |path|
25
+ File.basename(path)
26
+ end
27
+ timestamps = paths.map { |name| name.split('_').first }
28
+ latest = timestamps.max || '0'
29
+ [Time.now.utc.strftime('%Y%m%d%H%M%S'), format('%.14d', latest.next)].max
30
+ end
31
+
32
+ def create
33
+ raise "Migration already exists in #{_migration_dir}" if self.class.migration_exists?(_migration_dir, _migration_file_name)
34
+
35
+ migration_template(_source_template, _destination)
36
+ end
37
+
38
+ def _table_name
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def _source_template
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def _destination
47
+ "#{_migration_dir}/#{_migration_file_name}"
48
+ end
49
+
50
+ def _migration_file_name
51
+ "create_#{_table_name.singularize}.rb"
52
+ end
53
+
54
+ def _migration_dir
55
+ 'db/migrate'
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yes
4
+ module Auth
5
+ module Generators
6
+ # Generates all auth principal migrations at once
7
+ #
8
+ # @example
9
+ # rails generate yes:auth:install
10
+ class InstallGenerator < Rails::Generators::Base
11
+ namespace 'yes:auth:install'
12
+ desc 'Create all migrations for Yes::Auth principals'
13
+
14
+ def run_generators
15
+ invoke 'yes:auth:principals:read_resource_access'
16
+ invoke 'yes:auth:principals:write_resource_access'
17
+ invoke 'yes:auth:principals:role'
18
+ invoke 'yes:auth:principals:user'
19
+ invoke 'yes:auth:principals:user_role'
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_generator'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ module Principals
9
+ # Generates the migration for the read resource access principals table
10
+ #
11
+ # @example
12
+ # rails generate yes:auth:principals:read_resource_access
13
+ class ReadResourceAccessGenerator < BaseGenerator
14
+ source_root File.expand_path('../templates', __dir__)
15
+
16
+ namespace 'yes:auth:principals:read_resource_access'
17
+ desc 'Create migration for Yes::Auth::Principals::ReadResourceAccess'
18
+
19
+ def _table_name
20
+ Yes::Auth::Principals::ReadResourceAccess.table_name
21
+ end
22
+
23
+ def _source_template
24
+ 'read_resource_access.erb'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_generator'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ module Principals
9
+ # Generates the migration for the roles principals table
10
+ #
11
+ # @example
12
+ # rails generate yes:auth:principals:role
13
+ class RoleGenerator < BaseGenerator
14
+ source_root File.expand_path('../templates', __dir__)
15
+
16
+ namespace 'yes:auth:principals:role'
17
+ desc 'Create migration for Yes::Auth::Principals::Role'
18
+
19
+ def _table_name
20
+ Yes::Auth::Principals::Role.table_name
21
+ end
22
+
23
+ def _source_template
24
+ 'role.erb'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_generator'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ module Principals
9
+ # Generates the migration for the user principals table
10
+ #
11
+ # @example
12
+ # rails generate yes:auth:principals:user
13
+ class UserGenerator < BaseGenerator
14
+ source_root File.expand_path('../templates', __dir__)
15
+
16
+ namespace 'yes:auth:principals:user'
17
+ desc 'Create migration for Yes::Auth::Principals::User'
18
+
19
+ def _table_name
20
+ Yes::Auth::Principals::User.table_name
21
+ end
22
+
23
+ def _source_template
24
+ 'user.erb'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_generator'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ module Principals
9
+ # Generates the migration for the user-role join table
10
+ #
11
+ # This generator creates a join table for the HABTM association between
12
+ # User and Role principals, with UUID foreign keys and cascade deletes.
13
+ #
14
+ # @example
15
+ # rails generate yes:auth:principals:user_role
16
+ class UserRoleGenerator < BaseGenerator
17
+ source_root File.expand_path('../templates', __dir__)
18
+
19
+ namespace 'yes:auth:principals:user_role'
20
+ desc 'Create migration for the User-Role join table'
21
+
22
+ def _table_name
23
+ "#{Yes::Auth::Principals::User.reflect_on_association(:roles).table_name}_" \
24
+ "#{Yes::Auth::Principals::Role.reflect_on_association(:users).plural_name}"
25
+ end
26
+
27
+ def _migration_file_name
28
+ "create_join_table_#{_user_table_name.singularize}_#{_role_table_name.singularize}.rb"
29
+ end
30
+
31
+ def _user_table_name
32
+ Yes::Auth::Principals::User.table_name
33
+ end
34
+
35
+ def _role_table_name
36
+ Yes::Auth::Principals::Role.table_name
37
+ end
38
+
39
+ def _user_primary_key
40
+ Yes::Auth::Principals::Role.reflect_on_association(:users).foreign_key
41
+ end
42
+
43
+ def _role_primary_key
44
+ Yes::Auth::Principals::User.reflect_on_association(:roles).foreign_key
45
+ end
46
+
47
+ def _source_template
48
+ 'user_role.erb'
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base_generator'
4
+
5
+ module Yes
6
+ module Auth
7
+ module Generators
8
+ module Principals
9
+ # Generates the migration for the write resource access principals table
10
+ #
11
+ # @example
12
+ # rails generate yes:auth:principals:write_resource_access
13
+ class WriteResourceAccessGenerator < BaseGenerator
14
+ source_root File.expand_path('../templates', __dir__)
15
+
16
+ namespace 'yes:auth:principals:write_resource_access'
17
+ desc 'Create migration for Yes::Auth::Principals::WriteResourceAccess'
18
+
19
+ def _table_name
20
+ Yes::Auth::Principals::WriteResourceAccess.table_name
21
+ end
22
+
23
+ def _source_template
24
+ 'write_resource_access.erb'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Create<%= _table_name.singularize.camelcase %> < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table <%= _table_name.to_sym.inspect %>, id: :uuid do |t|
6
+ t.uuid :principal_id
7
+ t.uuid :role_id
8
+ t.string :service
9
+ t.string :scope
10
+ t.string :resource_type
11
+ t.string :resource_id
12
+ t.jsonb :auth_attributes, default: {}
13
+
14
+ t.timestamps
15
+ end
16
+
17
+ add_index <%= _table_name.to_sym.inspect %>, :principal_id
18
+ add_index <%= _table_name.to_sym.inspect %>, :role_id
19
+ add_index <%= _table_name.to_sym.inspect %>, :resource_id
20
+ add_index <%= _table_name.to_sym.inspect %>, :service
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Create<%= _table_name.singularize.camelcase %> < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table <%= _table_name.to_sym.inspect %>, id: :uuid do |t|
6
+ t.string :name
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index <%= _table_name.to_sym.inspect %>, :name, unique: true
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Create<%= _table_name.singularize.camelcase %> < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table <%= _table_name.to_sym.inspect %>, id: :uuid do |t|
6
+ t.jsonb :auth_attributes, default: {}
7
+ t.uuid :identity_id
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index <%= _table_name.to_sym.inspect %>, :identity_id
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateJoinTable<%= _user_table_name.singularize.camelcase %><%= _role_table_name.singularize.camelcase %> < ActiveRecord::Migration[7.0]
4
+ def up
5
+ create_join_table(:<%= _role_table_name %>, :<%= _user_table_name %>, column_options: { type: :uuid, foreign_key: { on_delete: :cascade } }) do |t|
6
+ t.index %i[<%= _user_primary_key%> <%= _role_primary_key %>], name: :<%= _user_table_name %>_<%= _role_table_name %>, unique: true
7
+ t.index %i[<%= _role_primary_key %> <%= _user_primary_key%>], name: :<%= _role_table_name %>_<%= _user_table_name %>
8
+ end
9
+
10
+ Yes::Auth::Principals::User.find_each do |user|
11
+ user.role_ids.each do |role_id|
12
+ role = Yes::Auth::Principals::Role.find_by(id: role_id)
13
+ next unless role
14
+
15
+ user.roles << role
16
+ end
17
+ end
18
+
19
+ remove_column :<%= _user_table_name %>, :role_ids, if_exists: true
20
+ end
21
+
22
+ def down
23
+ add_column :<%= _user_table_name %>, :role_ids, :uuid, array: true, default: [], null: false
24
+
25
+ Yes::Auth::Principals::User.find_each do |user|
26
+ user.role_ids = user.roles.map(&:auth_principals_role_id)
27
+ user.save!
28
+ end
29
+
30
+ drop_table :<%= _table_name %>
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Create<%= _table_name.singularize.camelcase %> < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table <%= _table_name.to_sym.inspect %>, id: :uuid do |t|
6
+ t.uuid :principal_id
7
+ t.uuid :role_id
8
+ t.string :context
9
+ t.string :resource_id
10
+ t.string :resource_type
11
+ t.jsonb :auth_attributes, default: {}
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index <%= _table_name.to_sym.inspect %>, :principal_id
17
+ add_index <%= _table_name.to_sym.inspect %>, :role_id
18
+ add_index <%= _table_name.to_sym.inspect %>, :resource_id
19
+ end
20
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Yes
4
4
  module Auth
5
- VERSION = '1.0.0'
5
+ VERSION = '1.1.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yes-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nico Ritsche
@@ -53,6 +53,18 @@ files:
53
53
  - lib/yes/auth/cerbos/read_resource_access/principal_data.rb
54
54
  - lib/yes/auth/cerbos/write_resource_access/principal_attributes.rb
55
55
  - lib/yes/auth/cerbos/write_resource_access/principal_data.rb
56
+ - lib/yes/auth/generators/base_generator.rb
57
+ - lib/yes/auth/generators/install_generator.rb
58
+ - lib/yes/auth/generators/principals/read_resource_access_generator.rb
59
+ - lib/yes/auth/generators/principals/role_generator.rb
60
+ - lib/yes/auth/generators/principals/user_generator.rb
61
+ - lib/yes/auth/generators/principals/user_role_generator.rb
62
+ - lib/yes/auth/generators/principals/write_resource_access_generator.rb
63
+ - lib/yes/auth/generators/templates/read_resource_access.erb
64
+ - lib/yes/auth/generators/templates/role.erb
65
+ - lib/yes/auth/generators/templates/user.erb
66
+ - lib/yes/auth/generators/templates/user_role.erb
67
+ - lib/yes/auth/generators/templates/write_resource_access.erb
56
68
  - lib/yes/auth/principals/read_resource_access.rb
57
69
  - lib/yes/auth/principals/role.rb
58
70
  - lib/yes/auth/principals/user.rb