Skip to content

Commit

Permalink
Merge branch 'release/3.3.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
coorasse committed Jun 21, 2021
2 parents 45bf553 + 2957182 commit f372180
Show file tree
Hide file tree
Showing 21 changed files with 304 additions and 113 deletions.
82 changes: 82 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Test & lint
on: [push, pull_request]

env:
RAILS_ENV: test
PGHOST: localhost
PGUSER: postgres

jobs:
tests:
name: Test & lint
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
ruby: ['2.4', '2.5', '2.6', '2.7', 'jruby', 'truffleruby']
gemfile: ['gemfiles/activerecord_4.2.0.gemfile', 'gemfiles/activerecord_5.0.2.gemfile', 'gemfiles/activerecord_5.1.0.gemfile', 'gemfiles/activerecord_5.2.2.gemfile', 'gemfiles/activerecord_6.0.0.gemfile', 'gemfiles/activerecord_6.1.0.gemfile', 'gemfiles/activerecord_master.gemfile']
exclude:
- gemfile: 'gemfiles/activerecord_4.2.0.gemfile'
ruby: '2.7' # rails 4.2 can't run on ruby 2.7 due to BigDecimal API change
- gemfile: 'gemfiles/activerecord_4.2.0.gemfile'
ruby: 'truffleruby' # TruffleRuby 21.0 targets Ruby 2.7, same as above
- gemfile: 'gemfiles/activerecord_master.gemfile'
ruby: '2.6' # rails 7+ requires ruby 3.0+
- gemfile: 'gemfiles/activerecord_master.gemfile'
ruby: '2.5' # rails 7+ requires ruby 3.0+
- gemfile: 'gemfiles/activerecord_6.0.0.gemfile'
ruby: '2.4' # rails 6+ requires ruby 2.5+
- gemfile: 'gemfiles/activerecord_6.1.0.gemfile'
ruby: '2.4' # rails 6+ requires ruby 2.5+
- gemfile: 'gemfiles/activerecord_master.gemfile'
ruby: '2.4' # rails 6+ requires ruby 2.5+
- gemfile: 'gemfiles/activerecord_5.0.2.gemfile'
ruby: 'jruby' # this *should* work - there's a test failure; it's not incompatible like the other excludes. could be an issue in Rails 5.0.2?
- gemfile: 'gemfiles/activerecord_6.1.0.gemfile'
ruby: 'jruby' # this *should* work. it seems like there's an issue with rails 6 on jruby.
- gemfile: 'gemfiles/activerecord_master.gemfile'
ruby: 'jruby' # this *should* work. it seems like there's an issue with rails 6 on jruby.

env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}

services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_DB: cancan_postgresql_spec
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports: ["5432:5432"]

steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: '20'

# https://github.com/CanCanCommunity/cancancan/pull/669#issuecomment-748019539
- name: Nokogiri support for Truffleruby
run: sudo apt-get -yqq install libxml2-dev libxslt-dev
if: ${{ matrix.ruby == 'truffleruby' }}

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Run linter
run: bundle exec rubocop

- name: Run tests on sqlite
run: DB=sqlite bundle exec rake

- name: Run tests on postgres
run: DB=postgres bundle exec rake
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ AllCops:
TargetRubyVersion: 2.2.0
Exclude:
- 'gemfiles/**/*'
- 'vendor/**/*'
- 'Appraisals'
82 changes: 0 additions & 82 deletions .travis.yml

This file was deleted.

8 changes: 4 additions & 4 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ appraise 'activerecord_6.1.0' do
end

platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.1.4'
gem 'sqlite3', '~> 1.4.0'
gem 'pg', '~> 1.2.3'
gem 'sqlite3', '~> 1.4.2'
end
end

Expand All @@ -113,7 +113,7 @@ appraise 'activerecord_master' do
end

platforms :ruby, :mswin, :mingw do
gem 'pg', '~> 1.1.4'
gem 'sqlite3', '~> 1.4.0'
gem 'pg', '~> 1.2.3'
gem 'sqlite3', '~> 1.4.2'
end
end
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 3.3.0

* [#675](https://github.com/CanCanCommunity/cancancan/pull/675): Support modifying the `accessible_by` querying strategy on a per-query basis. ([@ghiculescu][])
* [#714](https://github.com/CanCanCommunity/cancancan/pull/714): Don't hold unnecessary references to subjects in @rules_index. ([@mtoneil][])

## 3.2.2

* Added funding metadata to Gemspec. ([@coorasse][])

## 3.2.1

* [#674](https://github.com/CanCanCommunity/cancancan/pull/674): Fix accidental dependency on ActiveRecord in 3.2.0. ([@ghiculescu][])
Expand Down Expand Up @@ -679,3 +688,4 @@ Please read the [guide on migrating from CanCanCan 2.x to 3.0](https://github.co
[@ayumu838]: https://github.com/ayumu838
[@Liberatys]: https://github.com/Liberatys
[@ghiculescu]: https://github.com/ghiculescu
[@mtoneil]: https://github.com/mtoneil
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<img src="./logo/cancancan.png" width="200" />

[![Gem Version](https://badge.fury.io/rb/cancancan.svg)](http://badge.fury.io/rb/cancancan)
[![Travis badge](https://travis-ci.org/CanCanCommunity/cancancan.svg?branch=develop)](https://travis-ci.org/CanCanCommunity/cancancan)
[![Github Actions badge](https://github.com/CanCanCommunity/cancancan/actions/workflows/test.yml/badge.svg)](https://github.com/CanCanCommunity/cancancan/actions/workflows/test.yml/badge.svg)
[![Code Climate Badge](https://codeclimate.com/github/CanCanCommunity/cancancan.svg)](https://codeclimate.com/github/CanCanCommunity/cancancan)

[Wiki](./docs) |
Expand Down Expand Up @@ -36,6 +36,16 @@ of models automatically and reduce duplicated code.
</a>
<br/>
<br/>
<a href="https://bullettrain.co" target="_blank">
<img src="./logo/bullet_train.png" alt="Bullet Train" width="400"/>
</a>
<br/>
<br/>
<a href="https://jobs.goboony.com/fullstack-ruby-on-rails-developer" target="_blank">
<img src="./logo/goboony.png" alt="Goboony" width="310"/>
</a>
<br />
<br />

Do you want to sponsor CanCanCan and show your logo here?
Check our [Sponsors Page](https://github.com/sponsors/coorasse).
Expand Down Expand Up @@ -275,7 +285,7 @@ If you find a bug please add an [issue on GitHub](https://github.com/CanCanCommu
CanCanCan uses [appraisals](https://github.com/thoughtbot/appraisal) to test the code base against multiple versions
of Rails, as well as the different model adapters.

When first developing, you need to run `bundle install` and then `appraisal install`, to install the different sets.
When first developing, you need to run `bundle install` and then `bundle exec appraisal install`, to install the different sets.

You can then run all appraisal files (like CI does), with `appraisal rake` or just run a specific set `DB='sqlite' bundle exec appraisal activerecord_5.2.2 rake`.

Expand Down
10 changes: 5 additions & 5 deletions docs/Defining-Abilities-with-Blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ Here the block will be triggered for every `can?` check, even when only a class

## Additional Docs

* [[Defining Abilities]]
* [[Checking Abilities]]
* [[Testing Abilities]]
* [[Debugging Abilities]]
* [[Ability Precedence]]
* [Defining Abilities](./Defining-Abilities.md)
* [Checking Abilities](./Checking-Abilities.md)
* [Testing Abilities](./Testing-Abilities.md)
* [Debugging Abilities](./Debugging-Abilities.md)
* [Ability Precedence](./Ability-Precedence.md)
6 changes: 3 additions & 3 deletions docs/Defining-Abilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Ability
end
```

The `current_user` model is passed into the initialize method, so the permissions can be modified based on any user attributes. CanCanCan makes no assumption about how roles are handled in your application. See [[Role Based Authorization]] for an example.
The `current_user` model is passed into the initialize method, so the permissions can be modified based on any user attributes. CanCanCan makes no assumption about how roles are handled in your application. See [Role Based Authorization](./Role-Based-Authorization.md) for an example.

## The `can` Method

Expand All @@ -36,7 +36,7 @@ can :read, :all # user can read any object
can :manage, :all # user can perform any action on any object
```

Common actions are `:read`, `:create`, `:update` and `:destroy` but it can be anything. See [[Action Aliases]] and [[Custom Actions]] for more information on actions.
Common actions are `:read`, `:create`, `:update` and `:destroy` but it can be anything. See [Action Aliases](./Action-Aliases.md) and [Custom Actions](./Custom-Actions.md) for more information on actions.

You can pass an array for either of these parameters to match any one. For example, here the user will have the ability to update or destroy both articles and comments.

Expand Down Expand Up @@ -74,7 +74,7 @@ A hash of conditions can be passed to further restrict which records this permis
can :read, Project, active: true, user_id: user.id
```

It is important to only use database columns for these conditions so it can be reused for [[Fetching Records]].
It is important to only use database columns for these conditions so it can be reused for [Fetching Records](./Fetching-Records.md).

You can use nested hashes to define conditions on associations. Here the project can only be read if the category it belongs to is visible.

Expand Down
2 changes: 1 addition & 1 deletion docs/Ensure-Authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ApplicationController < ActionController::Base
end
```

This will add an `after_filter` to ensure authorization takes place in every inherited controller action. If no authorization happens it will raise a `CanCan::AuthorizationNotPerformed` exception. You can skip this check by adding `skip_authorization_check` to that controller. Both of these methods take the same arguments as `before_filter` so you can exclude certain actions with `:only` and `:except`.
This will add an `after_action` to ensure authorization takes place in every inherited controller action. If no authorization happens it will raise a `CanCan::AuthorizationNotPerformed` exception. You can skip this check by adding `skip_authorization_check` to that controller. Both of these methods take the same arguments as `before_action` so you can exclude certain actions with `:only` and `:except`.

```ruby
class UsersController < ApplicationController
Expand Down
42 changes: 41 additions & 1 deletion docs/Nested-Resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,46 @@ If the name of the association doesn't match the resource name, for instance `ha

If the resource name (`:project` in this case) does not match the controller then it will be considered a parent resource. You can manually specify parent/child resources using the `parent: false` option.

## Securing `through` changes

If you are using `through` you need to be wary of potential changes to the parent model. For example, consider this controller:

```ruby
class TasksController < ApplicationController
load_and_authorize_resource :project
load_and_authorize_resource :task, through: :project

def update
@task.update(task_params)
end

private

def task_params
params.require(:task).permit(:project_id)
end
end
```

Now consider a request to `/projects/1/tasks/42` with params `{ task: { project_id: 2 } }`.

- `load_and_authorize_resource :project` will load project 1 and authorize it.
- `load_and_authorize_resource :task, through: :project` will load task 42 from project 1, and authorize it.
- `@task.update(task_params)` will change the task's project ID from 1, to 2.
- Project 2 is never authorized! An attacker could inject a project belonging to another customer here.

How you handle this depends on your intended behavior.

- If you don't want a task's project ID to ever change, don't permit it as a param.
- If you allow tasks to be moved between projects, manually verify the ID change and avoid mass assigning it.

```ruby
def update
@task.project = Project.find(task_params[:project_id])
authorize!(@task)
@task.assign(task_params.except(:project_id))
end
```

## Nested through method

Expand Down Expand Up @@ -153,7 +193,7 @@ in ability.rb
can :create, User, groups_users: {group: {CONDITION_ON_GROUP} }
```

Don't forget the **inverse_of** option, is the trick to make it works correctly.
Don't forget the **inverse_of** option, it is the trick to make it work correctly.

Remember to define the ability through the **groups_users** model (i.e. don't write `can :create, User, groups: {CONDITION_ON_GROUP}`)

Expand Down
4 changes: 2 additions & 2 deletions gemfiles/activerecord_6.1.0.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ platforms :jruby do
end

platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.1.4"
gem "sqlite3", "~> 1.4.0"
gem "pg", "~> 1.2.3"
gem "sqlite3", "~> 1.4.2"
end

gemspec path: "../"
4 changes: 2 additions & 2 deletions gemfiles/activerecord_master.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ platforms :jruby do
end

platforms :ruby, :mswin, :mingw do
gem "pg", "~> 1.1.4"
gem "sqlite3", "~> 1.4.0"
gem "pg", "~> 1.2.3"
gem "sqlite3", "~> 1.4.2"
end

gemspec path: "../"
7 changes: 5 additions & 2 deletions lib/cancan/ability/rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ def add_rule(rule)
end

def add_rule_to_index(rule, position)
@rules_index ||= Hash.new { |h, k| h[k] = [] }
@rules_index ||= {}

subjects = rule.subjects.compact
subjects << :all if subjects.empty?

subjects.each do |subject|
@rules_index[subject] ||= []
@rules_index[subject] << position
end
end
Expand All @@ -48,7 +49,9 @@ def possible_relevant_rules(subject)
rules
else
positions = @rules_index.values_at(subject, *alternative_subjects(subject))
positions.flatten!.sort!
positions.compact!
positions.flatten!
positions.sort!
positions.map { |i| @rules[i] }
end
end
Expand Down

0 comments on commit f372180

Please sign in to comment.