gitlab-styles 9.2.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +14 -2
- data/.rubocop.yml +2 -1
- data/.rubocop_todo.yml +12 -0
- data/.tests_mapping.yml +10 -0
- data/Gemfile +9 -4
- data/gitlab-styles.gemspec +7 -7
- data/lefthook.yml +11 -3
- data/lib/gitlab/styles/version.rb +1 -1
- data/lib/rubocop/cop/active_record_dependent.rb +0 -5
- data/lib/rubocop/cop/active_record_serialize.rb +0 -6
- data/lib/rubocop/cop/avoid_return_from_blocks.rb +4 -4
- data/lib/rubocop/cop/gem_fetcher.rb +1 -1
- data/lib/rubocop/cop/gitlab_security/deep_munge.rb +36 -0
- data/lib/rubocop/cop/gitlab_security/json_serialization.rb +133 -0
- data/lib/rubocop/cop/gitlab_security/public_send.rb +47 -0
- data/lib/rubocop/cop/gitlab_security/redirect_to_params_update.rb +38 -0
- data/lib/rubocop/cop/gitlab_security/send_file_params.rb +40 -0
- data/lib/rubocop/cop/gitlab_security/sql_injection.rb +41 -0
- data/lib/rubocop/cop/gitlab_security/system_command_injection.rb +38 -0
- data/lib/rubocop/cop/in_batches.rb +0 -2
- data/lib/rubocop/cop/line_break_after_guard_clauses.rb +3 -5
- data/lib/rubocop/cop/migration/update_large_table.rb +1 -0
- data/lib/rubocop/cop/polymorphic_associations.rb +0 -5
- data/lib/rubocop/cop/rails/include_url_helper.rb +0 -2
- data/lib/rubocop/cop/redirect_with_status.rb +44 -30
- data/rubocop-capybara.yml +8 -0
- data/rubocop-default.yml +1 -1
- data/rubocop-layout.yml +2 -2
- data/rubocop-lint.yml +130 -2
- data/rubocop-naming.yml +5 -0
- data/rubocop-rails.yml +25 -0
- data/rubocop-rspec.yml +0 -5
- data/rubocop-security.yml +19 -1
- data/rubocop-style.yml +18 -3
- metadata +38 -29
- data/lib/gitlab/styles/rubocop/model_helpers.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be58fa1f46b81e0e8a73c3c85843048680518c23e846bcf54a1df301c53cfa18
|
4
|
+
data.tar.gz: 95f2466fb2ae6f5dcfcfce8b7e9343101588b9627f0c9c061c53beac597126e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb13dbe44128173fc03b4dddf53cfdfb67a6e8d37ffc6f4c32a4e30c33ead6e686b6023c2cff9fe7fbf95600d518b508fb9b9b68ffbb07dc8686765f65f3f638
|
7
|
+
data.tar.gz: 6a2774df245a7c42725e8989a8683b4953d91f70f059c0ceb41450b1c305b375f4e150ecb9418a56f60833ce166eca335ce94ba3a03fb7cf29575c7b72cbd54f
|
data/.gitlab-ci.yml
CHANGED
@@ -25,15 +25,27 @@ styles:
|
|
25
25
|
- bundle exec rubocop --debug --parallel
|
26
26
|
parallel:
|
27
27
|
matrix:
|
28
|
-
- RUBY_VERSION: ['2.7', '3.0']
|
28
|
+
- RUBY_VERSION: ['2.7', '3.0', '3.1', '3.2']
|
29
29
|
|
30
30
|
specs:
|
31
31
|
stage: test
|
32
32
|
script:
|
33
|
+
# Disable simplecov for all Ruby version other than 3.0
|
34
|
+
- if [[ "$RUBY_VERSION" != "3.0" ]]; then export SIMPLECOV=0; fi
|
33
35
|
- bundle exec rspec
|
34
36
|
parallel:
|
35
37
|
matrix:
|
36
|
-
- RUBY_VERSION: ['2.7', '3.0']
|
38
|
+
- RUBY_VERSION: ['2.7', '3.0', '3.1', '3.2']
|
39
|
+
artifacts:
|
40
|
+
name: coverage
|
41
|
+
expire_in: 31d
|
42
|
+
paths:
|
43
|
+
- coverage/index.html
|
44
|
+
- coverage/assets/
|
45
|
+
reports:
|
46
|
+
coverage_report:
|
47
|
+
coverage_format: cobertura
|
48
|
+
path: coverage/coverage.xml
|
37
49
|
|
38
50
|
include:
|
39
51
|
- project: 'gitlab-org/quality/pipeline-common'
|
data/.rubocop.yml
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
inherit_from:
|
2
|
+
- .rubocop_todo.yml
|
2
3
|
- rubocop-default.yml
|
3
4
|
|
4
5
|
require:
|
5
6
|
- rubocop/cop/internal_affairs
|
7
|
+
- rubocop-rake
|
6
8
|
|
7
9
|
AllCops:
|
8
10
|
NewCops: disable # https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles/-/issues/40
|
9
|
-
SuggestExtensions: false # https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles/-/issues/39
|
10
11
|
|
11
12
|
InternalAffairs/DeprecateCopHelper:
|
12
13
|
Enabled: true
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2023-01-11 12:59:00 UTC using RuboCop version 1.43.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
InternalAffairs/InheritDeprecatedCopClass:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/rubocop/cop/gitlab_security/json_serialization.rb'
|
data/.tests_mapping.yml
ADDED
data/Gemfile
CHANGED
@@ -6,12 +6,17 @@ source 'https://rubygems.org'
|
|
6
6
|
gemspec
|
7
7
|
|
8
8
|
group :development do
|
9
|
-
gem
|
9
|
+
gem 'lefthook', require: false
|
10
|
+
gem 'test_file_finder', '~> 0.1.4'
|
10
11
|
end
|
11
12
|
|
12
13
|
group :test do
|
13
14
|
# Pin these dependencies, otherwise a new rule could break the CI pipelines
|
14
|
-
gem 'rubocop', '1.
|
15
|
-
gem 'rubocop-rspec', '2.
|
16
|
-
gem 'rspec-parameterized', '0.
|
15
|
+
gem 'rubocop', '1.43.0'
|
16
|
+
gem 'rubocop-rspec', '2.18.1'
|
17
|
+
gem 'rspec-parameterized-table_syntax', '1.0.0', require: false
|
18
|
+
|
19
|
+
gem 'simplecov', '~> 0.22.0', require: false
|
20
|
+
gem 'simplecov-html', '~> 0.12.3', require: false
|
21
|
+
gem 'simplecov-cobertura', '~> 2.1.0', require: false
|
17
22
|
end
|
data/gitlab-styles.gemspec
CHANGED
@@ -22,15 +22,15 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
|
-
spec.add_dependency 'rubocop', '~> 1.
|
26
|
-
spec.add_dependency 'rubocop-
|
27
|
-
spec.add_dependency 'rubocop-
|
28
|
-
spec.add_dependency 'rubocop-
|
29
|
-
spec.add_dependency 'rubocop-
|
30
|
-
spec.add_dependency 'rubocop-rspec', '~> 2.15'
|
25
|
+
spec.add_dependency 'rubocop', '~> 1.43.0'
|
26
|
+
spec.add_dependency 'rubocop-graphql', '~> 0.18'
|
27
|
+
spec.add_dependency 'rubocop-performance', '~> 1.15'
|
28
|
+
spec.add_dependency 'rubocop-rails', '~> 2.17'
|
29
|
+
spec.add_dependency 'rubocop-rspec', '~> 2.18'
|
31
30
|
|
32
31
|
spec.add_development_dependency 'bundler', '~> 2.1'
|
33
32
|
spec.add_development_dependency 'gitlab-dangerfiles', '~> 2.11.0'
|
34
|
-
spec.add_development_dependency 'rake', '~>
|
33
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
35
34
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
36
36
|
end
|
data/lefthook.yml
CHANGED
@@ -10,7 +10,15 @@ pre-push:
|
|
10
10
|
glob: '*.{rb,rake}'
|
11
11
|
run: bundle exec rubocop --parallel --force-exclusion {files}
|
12
12
|
|
13
|
-
# Run
|
13
|
+
# Run only relevant specs.
|
14
14
|
rspec:
|
15
|
-
|
16
|
-
|
15
|
+
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
|
16
|
+
run: |
|
17
|
+
tests=$(tff --mapping-file .tests_mapping.yml {files})
|
18
|
+
if [ "$tests" != "" ]; then
|
19
|
+
echo "bundle exec rspec --format progress $tests"
|
20
|
+
bundle exec rspec --format progress $tests
|
21
|
+
else
|
22
|
+
echo "No specs to run."
|
23
|
+
exit 0
|
24
|
+
fi
|
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../gitlab/styles/rubocop/model_helpers'
|
4
|
-
|
5
3
|
module Rubocop
|
6
4
|
module Cop
|
7
5
|
# Cop that prevents the use of `dependent: ...` in ActiveRecord models.
|
8
6
|
class ActiveRecordDependent < RuboCop::Cop::Base
|
9
|
-
include Gitlab::Styles::Rubocop::ModelHelpers
|
10
|
-
|
11
7
|
MSG = 'Do not use `dependent:` to remove associated data, ' \
|
12
8
|
'use foreign keys with cascading deletes instead.'
|
13
9
|
|
@@ -15,7 +11,6 @@ module Rubocop
|
|
15
11
|
ALLOWED_OPTIONS = [:restrict_with_error].freeze
|
16
12
|
|
17
13
|
def on_send(node)
|
18
|
-
return unless in_model?(node)
|
19
14
|
return unless METHOD_NAMES.include?(node.children[1])
|
20
15
|
|
21
16
|
node.children.last.each_node(:pair) do |pair|
|
@@ -1,18 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../gitlab/styles/rubocop/model_helpers'
|
4
|
-
|
5
3
|
module Rubocop
|
6
4
|
module Cop
|
7
5
|
# Cop that prevents the use of `serialize` in ActiveRecord models.
|
8
6
|
class ActiveRecordSerialize < RuboCop::Cop::Base
|
9
|
-
include Gitlab::Styles::Rubocop::ModelHelpers
|
10
|
-
|
11
7
|
MSG = 'Do not store serialized data in the database, use separate columns and/or tables instead'
|
12
8
|
|
13
9
|
def on_send(node)
|
14
|
-
return unless in_model?(node)
|
15
|
-
|
16
10
|
add_offense(node.loc.selector) if node.children[1] == :serialize
|
17
11
|
end
|
18
12
|
end
|
@@ -23,7 +23,7 @@ module Rubocop
|
|
23
23
|
class AvoidReturnFromBlocks < RuboCop::Cop::Base
|
24
24
|
MSG = 'Do not return from a block, use next or break instead.'
|
25
25
|
DEF_METHODS = %i[define_method lambda].freeze
|
26
|
-
|
26
|
+
ALLOWED_METHODS = %i[each each_filename times loop].freeze
|
27
27
|
|
28
28
|
def on_block(node)
|
29
29
|
block_body = node.body
|
@@ -32,7 +32,7 @@ module Rubocop
|
|
32
32
|
return unless top_block?(node)
|
33
33
|
|
34
34
|
block_body.each_node(:return) do |return_node|
|
35
|
-
next if parent_blocks(node, return_node).all? { |block|
|
35
|
+
next if parent_blocks(node, return_node).all? { |block| allowed?(block) }
|
36
36
|
|
37
37
|
add_offense(return_node)
|
38
38
|
end
|
@@ -71,8 +71,8 @@ module Rubocop
|
|
71
71
|
(node.block_type? && DEF_METHODS.include?(node.method_name))
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
75
|
-
|
74
|
+
def allowed?(block_node)
|
75
|
+
ALLOWED_METHODS.include?(block_node.method_name)
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Checks for disabling the deep munge security control.
|
7
|
+
#
|
8
|
+
# Disabling this security setting can leave the application open to unsafe
|
9
|
+
# query generation
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# config.action_dispatch.perform_deep_munge = false
|
15
|
+
#
|
16
|
+
# See CVE-2012-2660, CVE-2012-2694, and CVE-2013-0155.
|
17
|
+
class DeepMunge < RuboCop::Cop::Base
|
18
|
+
MSG = 'Never disable the deep munge security option.'
|
19
|
+
|
20
|
+
# @!method disable_deep_munge?(node)
|
21
|
+
def_node_matcher :disable_deep_munge?, <<-PATTERN
|
22
|
+
(send
|
23
|
+
(send (send nil? :config) :action_dispatch) :perform_deep_munge=
|
24
|
+
{ (false) (send true :!) }
|
25
|
+
)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def on_send(node)
|
29
|
+
return unless disable_deep_munge?(node)
|
30
|
+
|
31
|
+
add_offense(node.loc.selector)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Checks for `to_json` / `as_json` without allowing via `only`.
|
7
|
+
#
|
8
|
+
# Either method called on an instance of a `Serializer` class will be
|
9
|
+
# ignored. Associations included via `include` are subject to the same
|
10
|
+
# rules.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# render json: @user.to_json
|
16
|
+
# render json: @user.to_json(except: %i[password])
|
17
|
+
# render json: @user.to_json(
|
18
|
+
# only: %i[username],
|
19
|
+
# include: [:identities]
|
20
|
+
# )
|
21
|
+
#
|
22
|
+
# # acceptable
|
23
|
+
# render json: UserSerializer.new.to_json
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# render json: @user.to_json(only: %i[name username])
|
27
|
+
# render json: @user.to_json(
|
28
|
+
# only: %i[username],
|
29
|
+
# include: { identities: { only: %i[provider] } }
|
30
|
+
# )
|
31
|
+
#
|
32
|
+
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/29661
|
33
|
+
class JsonSerialization < RuboCop::Cop::Cop
|
34
|
+
MSG = "Don't use `%s` without specifying `only`"
|
35
|
+
|
36
|
+
# Check for `to_json` sent to any object that's not a Hash literal or
|
37
|
+
# Serializer instance
|
38
|
+
# @!method json_serialization?(node)
|
39
|
+
def_node_matcher :json_serialization?, <<~PATTERN
|
40
|
+
(send !{nil? hash #serializer?} ${:to_json :as_json} $...)
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
# Check if node is a `only: ...` pair
|
44
|
+
# @!method only_pair?(node)
|
45
|
+
def_node_matcher :only_pair?, <<~PATTERN
|
46
|
+
(pair (sym :only) ...)
|
47
|
+
PATTERN
|
48
|
+
|
49
|
+
# Check if node is a `include: {...}` pair
|
50
|
+
# @!method include_pair?(node)
|
51
|
+
def_node_matcher :include_pair?, <<~PATTERN
|
52
|
+
(pair (sym :include) (hash $...))
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
# Check for a `only: [...]` pair anywhere in the node
|
56
|
+
# @!method contains_only?(node)
|
57
|
+
def_node_search :contains_only?, <<~PATTERN
|
58
|
+
(pair (sym :only) (array ...))
|
59
|
+
PATTERN
|
60
|
+
|
61
|
+
# Check for `SomeConstant.new`
|
62
|
+
# @!method constant_init(node)
|
63
|
+
def_node_search :constant_init, <<~PATTERN
|
64
|
+
(send (const nil? $_) :new ...)
|
65
|
+
PATTERN
|
66
|
+
|
67
|
+
def on_send(node)
|
68
|
+
matched = json_serialization?(node)
|
69
|
+
return unless matched
|
70
|
+
|
71
|
+
@_has_top_level_only = false
|
72
|
+
@method = matched.first
|
73
|
+
|
74
|
+
if matched.last.nil? || matched.last.empty?
|
75
|
+
# Empty `to_json` call
|
76
|
+
add_offense(node, location: :selector, message: format_message)
|
77
|
+
else
|
78
|
+
check_arguments(node, matched)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def format_message
|
85
|
+
format(MSG, @method)
|
86
|
+
end
|
87
|
+
|
88
|
+
def serializer?(node)
|
89
|
+
constant_init(node).any? { |name| name.to_s.end_with?('Serializer') }
|
90
|
+
end
|
91
|
+
|
92
|
+
def check_arguments(node, matched)
|
93
|
+
options = matched.last.first
|
94
|
+
|
95
|
+
# If `to_json` was given an argument that isn't a Hash, we don't
|
96
|
+
# know what to do here, so just move along
|
97
|
+
return unless options.hash_type?
|
98
|
+
|
99
|
+
options.each_child_node do |child_node|
|
100
|
+
check_pair(child_node)
|
101
|
+
end
|
102
|
+
|
103
|
+
return unless requires_only?
|
104
|
+
|
105
|
+
# Add a top-level offense for the entire argument list, but only if
|
106
|
+
# we haven't yet added any offenses to the child Hash values (such
|
107
|
+
# as `include`)
|
108
|
+
add_offense(node.children.last, message: format_message)
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_pair(pair)
|
112
|
+
if only_pair?(pair)
|
113
|
+
@_has_top_level_only = true
|
114
|
+
elsif include_pair?(pair)
|
115
|
+
includes = pair.value
|
116
|
+
|
117
|
+
includes.each_child_node do |child_node|
|
118
|
+
next if contains_only?(child_node)
|
119
|
+
|
120
|
+
add_offense(child_node, message: format_message)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def requires_only?
|
126
|
+
return false if @_has_top_level_only
|
127
|
+
|
128
|
+
offenses.count.zero?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Checks for the use of `public_send`, `send`, and `__send__` methods.
|
7
|
+
#
|
8
|
+
# If passed untrusted input these methods can be used to execute arbitrary
|
9
|
+
# methods on behalf of an attacker.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# myobj.public_send("#{params[:foo]}")
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# case params[:foo].to_s
|
18
|
+
# when 'choice1'
|
19
|
+
# items.choice1
|
20
|
+
# when 'choice2'
|
21
|
+
# items.choice2
|
22
|
+
# when 'choice3'
|
23
|
+
# items.choice3
|
24
|
+
# end
|
25
|
+
class PublicSend < RuboCop::Cop::Base
|
26
|
+
MSG = 'Avoid using `%s`.'
|
27
|
+
|
28
|
+
RESTRICT_ON_SEND = %i[send public_send __send__].freeze
|
29
|
+
|
30
|
+
# @!method send?(node)
|
31
|
+
def_node_matcher :send?, <<-PATTERN
|
32
|
+
({csend | send} _ ${:send :public_send :__send__} ...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
send?(node) do |match|
|
37
|
+
next unless node.arguments?
|
38
|
+
|
39
|
+
add_offense(node.loc.selector, message: format(MSG, match))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
alias_method :on_csend, :on_send
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Check for use of redirect_to(params.update())
|
7
|
+
#
|
8
|
+
# Passing user params to the redirect_to method provides an open redirect
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# redirect_to(params.update(action: 'main'))
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# redirect_to(allowed(params))
|
17
|
+
#
|
18
|
+
class RedirectToParamsUpdate < RuboCop::Cop::Base
|
19
|
+
MSG = 'Avoid using `redirect_to(params.%<name>s(...))`. ' \
|
20
|
+
'Only pass allowed arguments into redirect_to() (e.g. not including `host`)'
|
21
|
+
|
22
|
+
# @!method redirect_to_params_update_node(node)
|
23
|
+
def_node_matcher :redirect_to_params_update_node, <<-PATTERN
|
24
|
+
(send nil? :redirect_to $(send (send nil? :params) ${:update :merge} ...))
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
selected, name = redirect_to_params_update_node(node)
|
29
|
+
return unless name
|
30
|
+
|
31
|
+
message = format(MSG, name: name)
|
32
|
+
|
33
|
+
add_offense(selected, message: message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Check for use of send_file(..., params[], ...)
|
7
|
+
#
|
8
|
+
# Passing user params to the send_file() method allows directory traversal
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# send_file("/tmp/myproj/" + params[:filename])
|
14
|
+
#
|
15
|
+
# # good (verify directory)
|
16
|
+
|
17
|
+
# basename = File.expand_path("/tmp/myproj")
|
18
|
+
# filename = File.expand_path(File.join(basename, @file.public_filename))
|
19
|
+
# raise if basename != filename
|
20
|
+
# send_file filename, disposition: 'inline'
|
21
|
+
#
|
22
|
+
class SendFileParams < RuboCop::Cop::Base
|
23
|
+
MSG = 'Do not pass user provided params directly to send_file(), ' \
|
24
|
+
'verify the path with file.expand_path() first.'
|
25
|
+
|
26
|
+
# @!method params_node?(node)
|
27
|
+
def_node_search :params_node?, <<-PATTERN
|
28
|
+
(send (send nil? :params) ... )
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def on_send(node)
|
32
|
+
return unless node.command?(:send_file)
|
33
|
+
return unless node.arguments.any? { |e| params_node?(e) }
|
34
|
+
|
35
|
+
add_offense(node.loc.selector)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Check for use of where("name = '#{params[:name]}'")
|
7
|
+
#
|
8
|
+
# Passing user input to where() without parameterization can result in SQL Injection
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# u = User.where("name = '#{params[:name]}'")
|
14
|
+
#
|
15
|
+
# # good (parameters)
|
16
|
+
# u = User.where("name = ? AND id = ?", params[:name], params[:id])
|
17
|
+
# u = User.where(name: params[:name], id: params[:id])
|
18
|
+
#
|
19
|
+
class SqlInjection < RuboCop::Cop::Base
|
20
|
+
MSG = 'Parameterize all user-input passed to where(), do not directly embed user input in SQL queries.'
|
21
|
+
|
22
|
+
# @!method where_user_input?(node)
|
23
|
+
def_node_matcher :where_user_input?, <<-PATTERN
|
24
|
+
(send _ :where ...)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
# @!method string_var_string?(node)
|
28
|
+
def_node_matcher :string_var_string?, <<-PATTERN
|
29
|
+
(dstr (str ...) (begin ...) (str ...) ...)
|
30
|
+
PATTERN
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return unless where_user_input?(node)
|
34
|
+
return unless node.arguments.any? { |e| string_var_string?(e) }
|
35
|
+
|
36
|
+
add_offense(node.loc.selector)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GitlabSecurity
|
6
|
+
# Check for use of system("/bin/ls #{params[:file]}")
|
7
|
+
#
|
8
|
+
# Passing user input to system() without sanitization and parameterization can result in command injection
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# system("/bin/ls #{filename}")
|
14
|
+
#
|
15
|
+
# # good (parameters)
|
16
|
+
# system("/bin/ls", filename)
|
17
|
+
# # even better
|
18
|
+
# exec("/bin/ls", shell_escape(filename))
|
19
|
+
#
|
20
|
+
class SystemCommandInjection < RuboCop::Cop::Base
|
21
|
+
MSG = 'Do not include variables in the command name for system(). ' \
|
22
|
+
'Use parameters "system(cmd, params)" or exec() instead.'
|
23
|
+
|
24
|
+
# @!method system_var?(node)
|
25
|
+
def_node_matcher :system_var?, <<-PATTERN
|
26
|
+
(dstr (str ...) (begin ...) ...)
|
27
|
+
PATTERN
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
return unless node.command?(:system)
|
31
|
+
return unless node.arguments.any? { |e| system_var?(e) }
|
32
|
+
|
33
|
+
add_offense(node.loc.selector)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -56,6 +56,8 @@ module Rubocop
|
|
56
56
|
#
|
57
57
|
# do_something_more
|
58
58
|
class LineBreakAfterGuardClauses < RuboCop::Cop::Base
|
59
|
+
extend RuboCop::Cop::AutoCorrector
|
60
|
+
|
59
61
|
MSG = 'Add a line break after guard clauses'
|
60
62
|
|
61
63
|
# @!method guard_clause_node?(node)
|
@@ -68,11 +70,7 @@ module Rubocop
|
|
68
70
|
return unless guard_clause?(node)
|
69
71
|
return if next_line(node).blank? || clause_last_line?(next_line(node)) || guard_clause?(next_sibling(node))
|
70
72
|
|
71
|
-
add_offense(node)
|
72
|
-
end
|
73
|
-
|
74
|
-
def autocorrect(node)
|
75
|
-
lambda do |corrector|
|
73
|
+
add_offense(node) do |corrector|
|
76
74
|
corrector.insert_after(node.loc.expression, "\n")
|
77
75
|
end
|
78
76
|
end
|
@@ -1,17 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../gitlab/styles/rubocop/model_helpers'
|
4
|
-
|
5
3
|
module Rubocop
|
6
4
|
module Cop
|
7
5
|
# Cop that prevents the use of polymorphic associations
|
8
6
|
class PolymorphicAssociations < RuboCop::Cop::Base
|
9
|
-
include Gitlab::Styles::Rubocop::ModelHelpers
|
10
|
-
|
11
7
|
MSG = 'Do not use polymorphic associations, use separate tables instead'
|
12
8
|
|
13
9
|
def on_send(node)
|
14
|
-
return unless in_model?(node)
|
15
10
|
return unless node.children[1] == :belongs_to
|
16
11
|
|
17
12
|
node.children.last.each_node(:pair) do |pair|
|