Open
Conversation
Catches `WorkPackage.where(id: params[...])` patterns that silently drop semantic identifiers (e.g. "PROJ-42") because PostgreSQL casts the string to integer 0 inside `where(id: ...)`. Suggests `where_display_id_in`, which partitions numeric and semantic inputs and consults the alias table. The cop only fires when the receiver chain demonstrably starts at the `WorkPackage` constant and the value is derived from `params[...]`, so internal subquery composition (`where(id: scope.pluck(:id))`) and primary-key literals are left untouched. Autocorrects when the value is a pure `params[...]` access or `||` chain of them; flags without-correcting cases like `params[:id].to_i`. Verified against the full openproject tree (6,746 files): 1 real offense, 0 false positives.
Extend the work_package_relation? matcher to also recognize chains passing through an association call whose method name ends in `work_packages`. Catches: project.work_packages.where(id: params[:work_package_id]) current_user.assigned_work_packages.where(id: params[:ids]) project.work_packages.includes(:project).where(id: params[:ids]) while leaving unrelated associations (`project.users`, ...) alone. Verified against opf/openproject again: still 1 real offense, 0 false positives.
There was a problem hiding this comment.
Pull request overview
This PR introduces a new RuboCop cop to prevent a known class of bugs where user-supplied semantic WorkPackage identifiers (e.g., PROJ-42) are passed to WorkPackage.where(id: ...) and silently fail due to PostgreSQL integer coercion, and guides developers toward where_display_id_in.
Changes:
- Add
OpenProject/NoParamsInWorkPackageWhereIdcop with autocorrect towhere_display_id_infor directparams[...](andparams[...] || params[...]) inputs. - Add a dedicated spec suite covering rooted/chained receivers, association receivers, and non-autocorrectable wrapped params.
- Bump gem version to
0.5.0and register the new cop in defaults, require list, and changelog.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
lib/rubocop/cop/open_project/no_params_in_work_package_where_id.rb |
Implements the new cop, receiver detection, params detection, and autocorrect logic. |
spec/rubocop/cop/open_project/no_params_in_work_package_where_id_spec.rb |
Adds coverage for offense detection and autocorrection behavior across receiver forms. |
lib/rubocop/cop/open_project_cops.rb |
Registers the new cop for loading. |
config/default.yml |
Enables the new cop by default and records VersionAdded. |
CHANGELOG.md |
Documents the newly added cop under Unreleased. |
lib/rubocop/open_project/version.rb |
Bumps gem version to 0.5.0. |
Gemfile.lock |
Updates lockfile to reflect the new gem version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Two fixes from PR review: - Don't autocorrect `where(id: params[:id], project_id: 5)` to `where_display_id_in(params[:id])` — the rewrite would silently drop the `project_id:` predicate. Refuse to autocorrect when the hash has more than one pair; the offense is still flagged for manual fix. - Move the changelog entry from `[Unreleased]` to a dated `0.5.0` section to match the release-bundling convention from the prior cop PR (NoNotImplementedError → 0.4.0). Version was already bumped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Catches
WorkPackage.where(id: params[...])patterns that silently drop semantic work package identifiers (e.g."PROJ-42") because PostgreSQL casts the string to integer0insidewhere(id: ...)and the row set comes back empty. The cop suggestsWorkPackage.where_display_id_in(...)(added in opf/openproject#23016), which partitions numeric and semantic inputs and consults the alias table.Background
Self-review thread on opf/openproject#23016 raised the question of whether to extend the runtime guard already in place on
WorkPackage.find_by(id: "PROJ-42")(which raisesUnsupportedLookup) toWorkPackage.where(id: "PROJ-42"). The conclusion was: don't —whereis AR's universal predicate primitive, composed into joins, scopes, association preloading, and Rails internals; guarding it would invert the docstring's "low-level code uses primary keys" rationale and risks subtle breakage. The actual bug class is narrow (user input flowing intowhere(id:)) and lints cleanly. See discussion.Behaviour
The cop fires only when:
WorkPackageconstant (WorkPackage,WorkPackage.foo.bar(:baz), ...) or passing through an association call whose method name ends inwork_packages(project.work_packages,current_user.assigned_work_packages, ...).Foo::WorkPackageand unrelated associations (project.users) are correctly not matched.params[...]access (direct or in any descendant)It autocorrects
where(id: X)→where_display_id_in(X)when X is a pureparams[...]access or||chain of them. Cases likeparams[:id].to_iflag without an autocorrection (the cast defeatswhere_display_id_in's smart partition).Verification
bundle exec rakegreen: 38 specs, 0 failures, RuboCop self-lint clean.app/controllers/application_controller.rb:273, the very site Resolve semantic work package id when moving a work package openproject#23016 fixes), 0 false positives.Release plan
Marked draft pending opf/openproject#23016 merging (which introduces
where_display_id_in, the autocorrect target). Once both land, cut a0.5.0release and bump the gem version in opf/openproject in a separate PR.Test plan
bundle exec rake(specs + self-lint) greenapp/,modules/,lib/— exactly the expected offense, no false positivesproject.work_packages.where(id: params[...])) covered by spec