Gusto's custom RuboCop cops and shared configuration, distributed as a gem and integrated via the lint_roller plugin interface.
Add this line to your application's Gemfile:
gem 'rubocop-gusto', require: falseAnd then execute:
$ bundlerubocop-gusto ships with a CLI that sets up your project's .rubocop.yml:
bundle exec rubocop-gusto initThis adds rubocop-gusto to your .rubocop.yml plugins: list and includes any relevant configuration (e.g. Rails-specific rules when Rails is detected, Sidekiq-specific rules when the Sidekiq gem is present).
If this is an existing project, it is recommended to run the autocorrector (bundle exec rubocop -a) and then to regenerate the .rubocop_todo.yml (bundle exec rubocop --auto-gen-config), so issues can be dealt with piecemeal.
The Gusto/Graphql cops lint the graphql-ruby schema
DSL. They live in config/graphql.yml, which also configures the GraphQL cops from
rubocop-graphql — several of them cops Gusto
contributed upstream rather than keep here. Neither is in config/default.yml, so projects without
a GraphQL schema are not linted for those patterns.
Running bundle exec rubocop-gusto init does all of it when graphql is in your Gemfile or
Gemfile.lock: adds rubocop-graphql to your Gemfile and plugins: list, and adds
config/graphql.yml to your inherit_gem list. rubocop-graphql is deliberately not a dependency
of this gem, for the same reason rubocop-rails is not — so rubocop-gusto stays usable from a plain
gem.
GraphQL/DisallowedTypes is where a project names the types it has decided not to expose. It is
inert until configured, and the reason is per type, so it needs no Details::
GraphQL/DisallowedTypes:
Types:
Float: 'Use MyApp::GraphQL::Scalars::Decimal, which serializes as a string.'
MyApp::Scalars::LegacyDate: 'Use GraphQL::Types::ISO8601Date.'By default the Gusto/Graphql department is scoped to **/graphql/**/*.
Gusto/Graphql/ResolverIgnoresObject reads NodeAccessors, which lists methods your GraphQL base
classes provide that read the node without naming object; leave it empty and the cop reports
those resolvers as offenses.
Several of these cops replace a project-specific convention with a generic message. Put the
convention your project actually follows in the cop's Details:, and set
AllCops: ExtraDetails: true so it is appended to the offense message:
AllCops:
ExtraDetails: true
Gusto/Graphql/PaginateArrays:
Details: 'Use `paginated_list(<Type>)`, or `non_paginated_list(<Type>)` for a bounded list.'Sidekiq-specific cops live in config/sidekiq.yml and are not included in config/default.yml, so projects without Sidekiq are not linted for those patterns. Running bundle exec rubocop-gusto init adds config/sidekiq.yml to your inherit_gem list automatically when Sidekiq is listed in your Gemfile or Gemfile.lock.
For an existing project that already uses Sidekiq, add the Sidekiq config to your .rubocop.yml:
inherit_gem:
rubocop-gusto:
- config/default.yml
- config/sidekiq.ymlIf your project also uses Rails, include config/rails.yml as well (order does not matter). Re-run bundle exec rubocop-gusto init to merge this in automatically.
The Gusto/Logging cops report likely sensitive data in Rails.logger, Sidekiq.logger,
and bare logger calls, including chained .tagged(...) loggers and message blocks.
Each cop has its own severity, exclusions, todo entries, and inline disables:
PiiAccessorchecks configured PII methods such asuser.email.RawParamschecks unfilteredparams, including serialization andrequirewithout narrowing.
All ship at Severity: info, which does not fail RuboCop at its default failure threshold.
Spec and test files are excluded. Promote each cop independently after reviewing its hits;
for example, set Gusto/Logging/PiiAccessor: Severity: warning in your project configuration.
Configure PiiMethods on Gusto/Logging to customize the shared sensitive-method list.
These are syntax-based heuristics: selecting a params key is allowed, not proof that it is safe; plain local variables and values assembled outside the log call may escape detection.
Custom cops live under the following namespaces:
Gusto/— general Gusto-specific cops (seelib/rubocop/cop/gusto/)Gusto/Graphql/— cops scoped to the graphql-ruby schema DSL (seelib/rubocop/cop/gusto/graphql/); configured inconfig/graphql.ymlGusto/Logging/— independently configurable checks for sensitive data in logs (seelib/rubocop/cop/gusto/logging/)Gusto/Sidekiq/— cops scoped to Sidekiq patterns (seelib/rubocop/cop/gusto/sidekiq/); enabled byconfig/sidekiq.yml
Releases are fully automated via release-please.
How it works:
- Merge PRs to
mainusing Conventional Commits in the PR title (enforced by CI). - release-please automatically creates and maintains a "Release PR" that bumps the version and updates the changelog.
- When you merge the Release PR, a GitHub Release and git tag are created, and the gem is published to RubyGems.
Conventional commit types and version bumps:
| PR title prefix | Version bump | Example |
|---|---|---|
feat: |
Minor (10.8.0 -> 10.9.0) | feat: add Gusto/NewCop cop |
fix: |
Patch (10.8.0 -> 10.8.1) | fix: correct false positive in DefaultScope |
feat!: or BREAKING CHANGE footer |
Major (10.8.0 -> 11.0.0) | feat!: drop Ruby 3.1 support |
chore:, docs:, ci:, etc. |
No release | chore: update dev dependencies |
Submit new rules, updated configuration, and other checks to be used organization wide by submitting a Pull Request!
PR titles must use Conventional Commits format (enforced by CI) — see the version bump table above for which prefixes trigger releases.
- Create
lib/rubocop/cop/gusto/<cop_name>.rb, see how to create a new cop and how to choose a name - Add an entry to
config/default.yml, then sort it:bundle exec rubocop-gusto sort config/default.yml - Add a spec in
spec/rubocop/cop/gusto/<cop_name>_spec.rb - Run tests and lint:
bundle exec rspec bundle exec rubocop
rubocop-gusto generally follows semver, with the exception that the only thing that is considered a breaking change is a change in the public API to use rubocop-gusto.
Users can generally expect to need to regenerate their rubocop todo when they make a minor version bump to rubocop-gusto.
git config core.hooksPath script/githooks