Created
June 24, 2020 08:53
-
-
Save pocke/1962a9212e879c451936b81d241880fe to your computer and use it in GitHub Desktop.
This file contains 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
rules: | |
- id: sample.delete_all | |
pattern: | |
- delete_all | |
- update_all | |
message: | | |
これらはvalidationやcallbackをスキップするので危険かもしれません。 | |
justification: | |
- どうしても高速に update/destroy したい場合 | |
- callbacks/validations が不要な場合 | |
before: | |
- records.delete_all | |
- records.update_all | |
after: | |
- records.each(&:destroy) | |
- | | |
records.each do |record| | |
record.update(field: nil) | |
end | |
- id: sample.save_not_conditional | |
pattern: | |
- "save(!validate: false, ...) [!conditional]" | |
- "update(...) [!conditional]" | |
- "update_attributes(...) [!conditional]" | |
- "destroy(...) [!conditional]" | |
message: | | |
save / update(_attributes) / destroy は失敗するとfalseを返します。 | |
戻り値をチェックするか、 `!` 付きのメソッドを呼んでください。 | |
justification: | |
- "StripeのメソッドはActiveRecord由来ではないので `!` 付きでなくても問題ありません。" | |
before: | |
- record.save() | |
- "record.update(foo: bar)" | |
- "record.update(attrs)" | |
after: | |
- if record.save() then do_something end | |
- "record.save(validate: false)" | |
- "record.update(foo: 1) or fail" | |
- id: sample.skip_validation | |
pattern: | |
- "save(validate: false)" | |
- "save!(validate: false)" | |
message: "validationをスキップするのは危険です。" | |
justification: | |
- When you want to skip validation | |
- When you have done validation code in other than ActiveRecord's validation mechanism | |
- id: sample.net_http | |
pattern: Net::HTTP | |
message: Use Faraday to make Web api calls | |
before: | |
- Net::HTTP.get(url) | |
after: | |
- Faraday.new.get_content(url) | |
- id: sample.oj | |
pattern: | |
- JSON.parse | |
- JSON.generate | |
message: Use Oj for JSON load and dump | |
- id: sample.metaprogramming_abuse | |
pattern: | |
- classify | |
- constantize | |
- eval | |
- instance_values | |
- safe_constantize | |
message: "本当にメタプログラミングが必要か3回考えてください。" | |
- id: sample.activesupport.try | |
pattern: "try" | |
message: "tryではなく &. 演算子を使ってください" | |
- id: kibela.activerecord.serialize | |
pattern: "serialize(:symbol:, ...)" | |
message: "ActiveRecordのserializeを使う必要はありません。jsonb型をそのまま使ってください。" | |
- id: kibela.user_roles | |
pattern: "User.roles[:symbol:]" | |
message: "User.roles[:member] は多くの場合で必要ありません。たとえばupdateやwhereではenum symbolを使えます。" | |
- id: kibela.current_user_locale | |
pattern: "current_user.locale" | |
message: "current_userはログインしていない場合nilになります。 I18n.localeを使ってください。" | |
- id: kibela.order_by_created_at | |
pattern: "order(created_at: :symbol:, !id: :symbol:)" | |
message: "order(created_at: ...) は order(id: ...) または order(created_at: ..., id: ...) と書くべきです。idは常にindexが有効だし、1ms未満の時間差で作成されたとしても必ず順番が確定するからです。" | |
- id: kibela.order_by_string | |
pattern: | |
- "order(:dstr:)" | |
- "where(:dstr:)" | |
- "find(:dstr:)" | |
- "exists?(:dstr:)" | |
message: "文字列によるSQL構築は本当に必要ですか? SQL Injection を引き起こさないように気をつけてください。" | |
- id: kibela.block_call | |
pattern: | |
- "yield" | |
message: "yieldではなくblock.callを使いましょう。そのほうが渡す引数が明確になります。" | |
- id: kibela.graphql_null_after_type | |
pattern: "field(:symbol:, _, !null: _, ...)" | |
message: "GraphQLのfield宣言は、typeの直後にnullオプションを書いてください。GraphQL schemaでは `T` (nullable) と `T!` (non-null) と書くように、nullabilityは型の一部なのです。" | |
- id: kibela.yard_class_name | |
pattern: "class_name()" | |
message: "Class#class_name は yard gem による拡張なのでproductionでは使えません。必要なのはビルトインメソッドの Class#name ではないですか。" | |
- id: kibela.cgi_escape | |
pattern: "CGI.escape" | |
message: "path component のescapeに CGI.escape を使うのは不適切です。 URI::DEFAULT_PARSER.escape を使ってください" | |
- id: kibela.connection_type_without_resolver | |
pattern: "field(:symbol:, _.connection_type, ..., !resolve: _, ...)" | |
message: "Relay connection に resolver が設定されていません。 AR::Relation に対するconnectionは resolver でソートを指定すべきです。" | |
- id: kibela.accessible_for | |
pattern: "accessible_for(_)" | |
message: "accessible_for(user) は古いメソッドです。 readable_by(user) または manageable_by(user) を使ってください" | |
justification: "testでは一部残っています。余裕があれば新しいメソッドに書き換えてください" | |
- id: kibela.accessible_for_p | |
pattern: "accessible_for?(_)" | |
message: "accessible_for?(user) は古いメソッドです。 readable_by?(user) または manageable_by?(user) を使ってください" | |
justification: "testでは一部残っています。余裕があれば新しいメソッドに書き換えてください" | |
- id: kibela.prefer_fetch_for_rails_secrets | |
pattern: | |
subject: "Rails.application.'credentials.'key()" | |
where: | |
key: '/.+/' | |
credentials: '/(?:secrets|credentials)/' | |
message: "`Rails.application.secrets.fetch(...)` を使いましょう。" | |
before: | |
- "Rails.application.secrets.foo" | |
- "Rails.application.credentials.foo" | |
after: | |
- "Rails.application.secrets.fetch(:foo)" | |
- "Rails.application.credentials.fetch(:foo)" | |
- id: kibela.prefer_fetch_for_graphql_context | |
pattern: "context.[](:symbol:)" | |
message: "GraphQL contextのエントリの参照は `context.fetch(...)` を使いましょう。" | |
before: | |
- "context[:foo]" | |
after: | |
- "context.fetch(:foo)" | |
- id: kibela.migration_belongs_to | |
message: "外部キーを定義する際は`integer`ではなく`belongs_to`や`references`を使いましょう。これによりデータ型がbigintになります。" | |
before: | |
- 't.integer :user_id' | |
- 't.integer :user_id, index: true, null: false' | |
- 'add_column :notes, :user_id, :integer, null: false, index: true' | |
after: | |
- 't.belongs_to :user' | |
- 't.references :user_id, index: true, null: false' | |
- 'add_reference :notes, :user, :integer, null: false, index: true' | |
pattern: | |
- subject: "t.integer(:symbol: as 'column, ...)" | |
where: | |
column: '/.+_id/' | |
- subject: "add_column(_, :symbol: as 'column, :integer, ...)" | |
where: | |
column: '/.+_id/' | |
preprocessor: | |
.haml: hamlit compile - |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment