{"id":18585992,"url":"https://github.com/cloud66-oss/roleback","last_synced_at":"2025-10-04T16:38:42.577Z","repository":{"id":216539201,"uuid":"740215732","full_name":"cloud66-oss/roleback","owner":"cloud66-oss","description":"A simple DSL for building RBAC rule sets in Ruby","archived":false,"fork":false,"pushed_at":"2024-02-05T16:42:53.000Z","size":63,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-26T19:17:17.732Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloud66-oss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-07T21:11:42.000Z","updated_at":"2024-01-13T12:22:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"869bea34-2dcc-461d-9d0a-acefc517b9ae","html_url":"https://github.com/cloud66-oss/roleback","commit_stats":null,"previous_names":["cloud66-oss/roleback"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Froleback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Froleback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Froleback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Froleback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloud66-oss","download_url":"https://codeload.github.com/cloud66-oss/roleback/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239340505,"owners_count":19622702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T00:36:17.992Z","updated_at":"2025-10-04T16:38:37.491Z","avatar_url":"https://github.com/cloud66-oss.png","language":"Ruby","readme":"# Roleback\n\nRoleback is a simple DSL for writing static RBAC rules for your application. Roleback is not concerned with how you store or enforce your roles, it only cares about how you define them. Storing roles against a user class is easy enough, and there are plenty of gems out there to help you enforce them, like [Pundit](https://github.com/varvet/pundit) and [CanCanCan](https://github.com/CanCanCommunity/cancancan).\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'roleback'\n```\n\nAnd then execute:\n\n```bash\n$ bundle\n```\n\nOr install it yourself as:\n\n```bash\n$ gem install roleback\n```\n\n## Usage\n\nUsing Roleback is simple. Define your roles in a ruby file, and then load them into your application. For example in Rails, you can create a file loaded during your application load, like `config/initializers/roles.rb`:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n  end\nend\n```\n\nRoleback defines permissions on by roles. In the example above, we've defined a role called `admin` that can `manage` anything. Usually permissions are defined with three pieces of information: `scope`, `resource` and `action`.\n\n`resource` is the object you want to check permissions against. `action` is the action you want to check permissions for. For example, you might want to check `read` action, on a blog `post`:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    resource :post do\n      can :read\n    end\n  end\nend\n```\n\n`resource` however, always includes 7 more actions: `create`, `read`, `update`, `delete`, `list`, `edit` and `new` to make it easier to define permissions for common actions. You can change this behavior using the `only` and `except` options:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    resource :post, only: [:read, :create, :update, :destroy] do\n      can :read\n    end\n  end\nend\n```\n\n`scope` adds context to your permissions. For example, you might want to grant `read` on a `post` in the web, but not in other contexts (like an API):\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    scope :web do\n      resource :post do\n        can :read\n      end\n    end\n  end\nend\n```\n\n## Grant and Deny\nPermissions are granted using `can` and denied using `cannot`:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    scope :web do\n      resource :post do\n        can :read\n        cannot :write\n      end\n    end\n  end\nend\n```\n\nBy default, all `resource` default permissions (create, read, update, delete, list, edit and new) are granted (ie `can`).\n\n## Inheritance\nRoles can inherit from other roles:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n  end\n\n  role :editor, inherits_from: :admin do\n    cannot :destroy\n  end\nend\n```\n\nRoles can also inherit from multiple roles:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n  end\n\n  role :author do\n    can :write\n  end\n\n  role :editor, inherits_from: [:admin, :author] do\n    cannot :destroy\n  end\nend\n```\n\nWhile you don't need to define a parent role before the child role, circular dependencies are not allowed, within the same parental line. For example, if `:moderator` inherits from `:admin`, `:admin` cannot inherit from `:moderator`, directly or indirectly. However, when inheriting from multiple parents, circular dependencies are allowed, as long as they are not in the same parental line. For example, `:editor` can inherit from `:admin` and `:author`, and `:author` can inherit from `:editor`, as long as `:editor` does not inherit from `:author` directly or indirectly.\n\nWhen it comes to consolidating the rules of inherited roles, Roleback allows repeated rules as long as they don't belong to the same role. For example, it is not allowed to define a rule twice, even with the same outcome:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n    can :manage # \u003c- not allowed\n  end\nend\n```\n\nYou can however, define the same rule in different roles, as long as they don't contradict each other:\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n  end\n\n  role :editor, inherits_from: :admin do\n    can :manage\n  end\nend\n```\n\n```ruby\n# config/initializers/roles.rb\nRoleback.define do\n  role :admin do\n    can :manage\n  end\n\n  role :editor, inherits_from: :admin do\n    cannot :manage # \u003c- not allowed\n  end\nend\n```\n\n## Checking Permissions\nRoleback doesn't care how you check permissions, but it does provide a simple API for doing so:\n\n```ruby\nRoleback.can?(:admin, resource: :post, action: :read) # =\u003e true\nRoleback.can?(:editor, resource: :post, action: :destroy) # =\u003e false\n```\n\nAfter the definition of roles is finished (`Roleback.define`), all each role, ends up with the collection of all rules it has plus all the rules it has inherited from other roles. These rules are used to check for permissions. When the `can?` method is called with `scope`, `resource` and `action`, `can?` will return the outcome of the most specific rule that matches the given `scope`, `resource` and `action`. If no rule matches, `can?` will return `false`. If you have both `can` and `cannot` rules for a check, `cannot` will take precedence (deny over grant).\n\n### `User` class\nIf you have a `User` class, Roleback will automatically, add a `can?` method to it:\n\n```ruby\nuser = User.find(1) # user.roles =\u003e [:admin]\nuser.can?(resource: :post, action: :read) # =\u003e true\nuser.can?(resource: :post, action: :destroy) # =\u003e false\n```\n\nYour `User` class has to have a method called `roles` that returns an array of role names as symbols.\n\nThe `User` class returns an array of roles, then Roleback will check each role for a match and will return `true` (grant) when the first role matches. If no role matches, `can?` will return `false`. This is an important point to remember when using class extension, which basically means if you grant the user multiple rules, it will return `true` if any of the rules match, even you have rules that deny access to the same resource and action.\n\nYou can change the class to be extended from `User`, using `user_class` option in `define`:\n\n```ruby\nRoleback.define user_class: Admin do\n  # ...\nend\n```\n\nIf you don't want to extend your `User` class, pass in `nil` as the `user_class` option:\n\n```ruby\nRoleback.define user_class: nil do\n  # ...\nend\n```\n\n## Recommendations\n\nEven though Roleback doesn't impose any opinions on how define your rules (sacrilegious in Rails world, I know), here are some recommendations that might help using it with more ease:\n\n1. Although Roleback, support deny permissions (`cannot`), I recommend against using those and always define your rules with grant permissions (`can`). This will make it easier to reason about your rules and will make it easier to debug them.\n2. Either map your roles to actual organizational roles (marketing, support, etc), or define them based on their access context (commenter, editor, etc). Don't mix the two. Use multiple inheritance when defining the roles based on access context and use single inheritance when defining them based on organizational roles.\n3. Define your roles in a single file, and load them during application load. (`config/initializers/roles.rb` in Rails is a good place).\n\n## Contributing\n\nBug reports and pull requests are welcome on this GitHub repository. PRs are welcome and more likely to be accepted if they include tests.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud66-oss%2Froleback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloud66-oss%2Froleback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud66-oss%2Froleback/lists"}