claws-scan 0.9.5 → 0.10.1
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/.rubocop.yml +3 -1
- data/Gemfile +3 -0
- data/Gemfile.lock +33 -19
- data/README.md +2 -2
- data/lib/claws/application.rb +1 -1
- data/lib/claws/base_rule.rb +1 -1
- data/lib/claws/engine.rb +1 -1
- data/lib/claws/rule/checkout_with_static_credentials.rb +4 -1
- data/lib/claws/rule/command_injection.rb +3 -1
- data/lib/claws/rule/global_permissions_block.rb +10 -2
- data/lib/claws/rule/shellcheck.rb +4 -1
- data/lib/claws/version.rb +1 -1
- data/lib/claws/workflow.rb +3 -2
- data/mise.lock +46 -0
- data/mise.toml +2 -0
- metadata +6 -8
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b391e0e7bd1ca6d4aa75feb0cec5153e04f6e67add1091e6b5598457e8c302f
|
|
4
|
+
data.tar.gz: b8cbceff5a7faa2aaafddc877f7471314fc185c9ba5909a5716ce4a51e2ce2ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b5fbbba1250282c7e92395a8f2120e31b4f4376ff0949b9cabe200c0d774ef10c517684f144d0947cdabd7aeca2b64d03912c9089c776dfc85c63324ab51fd78
|
|
7
|
+
data.tar.gz: 2d11e730351d6f719068461646b7e70eb9dae159130b6a9f617e052b85f49cd254e6d0c2b6e57023ef37a1c738177ab9c4f82533ba8b1cd46f6406e176707a5b
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
|
+
ruby "3.4.10"
|
|
6
7
|
|
|
7
8
|
gem "rake", "~> 13.0"
|
|
8
9
|
gem "rspec", "~> 3.0"
|
|
9
10
|
gem "rubocop", "~> 1.21"
|
|
10
11
|
|
|
12
|
+
gem "base64"
|
|
11
13
|
gem "equation"
|
|
12
14
|
gem "fakefs"
|
|
13
15
|
gem "faraday-retry"
|
|
14
16
|
gem "octokit"
|
|
15
17
|
gem "pry"
|
|
18
|
+
gem "racc"
|
|
16
19
|
gem "slop", "~> 4.9"
|
|
17
20
|
gem "treetop"
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
claws-scan (0.
|
|
4
|
+
claws-scan (0.10.1)
|
|
5
5
|
equation (~> 0.6)
|
|
6
6
|
pry
|
|
7
7
|
slop (~> 4.9)
|
|
@@ -12,7 +12,8 @@ GEM
|
|
|
12
12
|
specs:
|
|
13
13
|
addressable (2.9.0)
|
|
14
14
|
public_suffix (>= 2.0.2, < 8.0)
|
|
15
|
-
ast (2.4.
|
|
15
|
+
ast (2.4.3)
|
|
16
|
+
base64 (0.3.0)
|
|
16
17
|
coderay (1.1.3)
|
|
17
18
|
diff-lcs (1.5.0)
|
|
18
19
|
equation (0.6.2)
|
|
@@ -25,7 +26,9 @@ GEM
|
|
|
25
26
|
net-http (~> 0.5)
|
|
26
27
|
faraday-retry (2.0.0)
|
|
27
28
|
faraday (~> 2.0)
|
|
28
|
-
json (
|
|
29
|
+
json (3.0.2)
|
|
30
|
+
language_server-protocol (3.17.0.6)
|
|
31
|
+
lint_roller (1.1.0)
|
|
29
32
|
logger (1.7.0)
|
|
30
33
|
method_source (1.0.0)
|
|
31
34
|
net-http (0.9.1)
|
|
@@ -33,18 +36,20 @@ GEM
|
|
|
33
36
|
octokit (6.0.1)
|
|
34
37
|
faraday (>= 1, < 3)
|
|
35
38
|
sawyer (~> 0.9)
|
|
36
|
-
parallel (
|
|
37
|
-
parser (3.
|
|
39
|
+
parallel (2.2.0)
|
|
40
|
+
parser (3.3.12.0)
|
|
38
41
|
ast (~> 2.4.1)
|
|
42
|
+
racc
|
|
39
43
|
polyglot (0.3.5)
|
|
44
|
+
prism (1.9.0)
|
|
40
45
|
pry (0.14.2)
|
|
41
46
|
coderay (~> 1.1)
|
|
42
47
|
method_source (~> 1.0)
|
|
43
48
|
public_suffix (7.0.5)
|
|
49
|
+
racc (1.8.1)
|
|
44
50
|
rainbow (3.1.1)
|
|
45
51
|
rake (13.0.6)
|
|
46
|
-
regexp_parser (2.
|
|
47
|
-
rexml (3.4.2)
|
|
52
|
+
regexp_parser (2.12.0)
|
|
48
53
|
rspec (3.11.0)
|
|
49
54
|
rspec-core (~> 3.11.0)
|
|
50
55
|
rspec-expectations (~> 3.11.0)
|
|
@@ -58,26 +63,30 @@ GEM
|
|
|
58
63
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
59
64
|
rspec-support (~> 3.11.0)
|
|
60
65
|
rspec-support (3.11.1)
|
|
61
|
-
rubocop (1.
|
|
62
|
-
json (
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
rubocop (1.91.0)
|
|
67
|
+
json (>= 2.3)
|
|
68
|
+
language_server-protocol (~> 3.17.0.2)
|
|
69
|
+
lint_roller (~> 1.1.0)
|
|
70
|
+
parallel (>= 1.10)
|
|
71
|
+
parser (>= 3.3.0.2)
|
|
65
72
|
rainbow (>= 2.2.2, < 4.0)
|
|
66
|
-
regexp_parser (>=
|
|
67
|
-
|
|
68
|
-
rubocop-ast (>= 1.23.0, < 2.0)
|
|
73
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
74
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
69
75
|
ruby-progressbar (~> 1.7)
|
|
70
|
-
unicode-display_width (>=
|
|
71
|
-
rubocop-ast (1.
|
|
72
|
-
parser (>= 3.
|
|
73
|
-
|
|
76
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
77
|
+
rubocop-ast (1.50.0)
|
|
78
|
+
parser (>= 3.3.7.2)
|
|
79
|
+
prism (~> 1.7)
|
|
80
|
+
ruby-progressbar (1.13.0)
|
|
74
81
|
sawyer (0.9.2)
|
|
75
82
|
addressable (>= 2.3.5)
|
|
76
83
|
faraday (>= 0.17.3, < 3)
|
|
77
84
|
slop (4.9.3)
|
|
78
85
|
treetop (1.6.12)
|
|
79
86
|
polyglot (~> 0.3)
|
|
80
|
-
unicode-display_width (2.
|
|
87
|
+
unicode-display_width (3.2.0)
|
|
88
|
+
unicode-emoji (~> 4.1)
|
|
89
|
+
unicode-emoji (4.2.0)
|
|
81
90
|
uri (1.1.1)
|
|
82
91
|
|
|
83
92
|
PLATFORMS
|
|
@@ -89,17 +98,22 @@ PLATFORMS
|
|
|
89
98
|
x86_64-linux
|
|
90
99
|
|
|
91
100
|
DEPENDENCIES
|
|
101
|
+
base64
|
|
92
102
|
claws-scan!
|
|
93
103
|
equation
|
|
94
104
|
fakefs
|
|
95
105
|
faraday-retry
|
|
96
106
|
octokit
|
|
97
107
|
pry
|
|
108
|
+
racc
|
|
98
109
|
rake (~> 13.0)
|
|
99
110
|
rspec (~> 3.0)
|
|
100
111
|
rubocop (~> 1.21)
|
|
101
112
|
slop (~> 4.9)
|
|
102
113
|
treetop
|
|
103
114
|
|
|
115
|
+
RUBY VERSION
|
|
116
|
+
ruby 3.4.10p104
|
|
117
|
+
|
|
104
118
|
BUNDLED WITH
|
|
105
119
|
2.4.2
|
data/README.md
CHANGED
|
@@ -40,9 +40,9 @@ jobs:
|
|
|
40
40
|
runs-on: ubuntu-latest
|
|
41
41
|
steps:
|
|
42
42
|
- name: Set Up Ruby
|
|
43
|
-
uses: ruby/setup-ruby@
|
|
43
|
+
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
44
44
|
with:
|
|
45
|
-
ruby-version: '3.
|
|
45
|
+
ruby-version: '3.4'
|
|
46
46
|
# Grab your configuration file however makes sense for you
|
|
47
47
|
# We keep ours in a separate Github repo.
|
|
48
48
|
- name: Set Up Claws Config
|
data/lib/claws/application.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Claws
|
|
|
27
27
|
def get_violations(filename, workflow)
|
|
28
28
|
violations = get_workflow_violations(filename, workflow)
|
|
29
29
|
|
|
30
|
-
workflow.jobs.
|
|
30
|
+
workflow.jobs.each_value do |job|
|
|
31
31
|
violations += get_job_violations(filename, workflow, job)
|
|
32
32
|
|
|
33
33
|
job.fetch("steps", []).each do |step|
|
data/lib/claws/base_rule.rb
CHANGED
|
@@ -15,7 +15,7 @@ class BaseRule
|
|
|
15
15
|
difference: ->(arr1, arr2) { arr1.difference arr2 },
|
|
16
16
|
intersection: ->(arr1, arr2) { arr1.intersection arr2 },
|
|
17
17
|
get_key: ->(arr, key) { (arr || {}).fetch(key, nil) },
|
|
18
|
-
count:
|
|
18
|
+
count: lambda(&:length),
|
|
19
19
|
dig: lambda { |object, path, default = nil|
|
|
20
20
|
# sometimes we might want to traverse the object as if it were a hash
|
|
21
21
|
# sometimes we might want to traverse it as a Ruby object
|
data/lib/claws/engine.rb
CHANGED
|
@@ -18,7 +18,7 @@ class ExpressionParser
|
|
|
18
18
|
startswith: ->(string, needle) { string.to_s.start_with? needle },
|
|
19
19
|
endswith: ->(string, needle) { string.to_s.end_with? needle },
|
|
20
20
|
difference: ->(arr1, arr2) { arr1.difference arr2 },
|
|
21
|
-
count:
|
|
21
|
+
count: lambda(&:length)
|
|
22
22
|
}
|
|
23
23
|
)
|
|
24
24
|
end
|
|
@@ -24,10 +24,13 @@ module Claws
|
|
|
24
24
|
)
|
|
25
25
|
), highlight: "with.ssh-key"
|
|
26
26
|
|
|
27
|
+
# secrets.GITHUB_TOKEN is the short lived per-run token, not a static credential.
|
|
28
|
+
# the regex retries at each secrets. reference, so GITHUB_TOKEN alongside another secret is still flagged.
|
|
29
|
+
# %() is double quoted, so \\b is needed to reach the regex as a word boundary (\b would be a backspace)
|
|
27
30
|
on_step %(
|
|
28
31
|
$step.meta.action.name == "actions/checkout" &&
|
|
29
32
|
(
|
|
30
|
-
get_key($step.with, "token") =~ "{{.*secrets
|
|
33
|
+
get_key($step.with, "token") =~ "{{.*secrets\.(?!(?i:GITHUB_TOKEN)\\b)" ||
|
|
31
34
|
get_key($step.with, "token") =~ "{{.*env\..*" ||
|
|
32
35
|
get_key($step.with, "token") =~ "{{.*vars\..*" ||
|
|
33
36
|
get_key($step.with, "token") =~ "gh[a-z]_.*"
|
|
@@ -8,7 +8,9 @@ module Claws
|
|
|
8
8
|
https://github.com/betterment/claws/blob/main/README.md#commandinjection
|
|
9
9
|
DESC
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# only ${{ }} is expanded by the runner; bare {{ }} (e.g. gh-aw prompt templates) is literal text.
|
|
12
|
+
# (?:(?!\}\}).)* keeps the match inside a single expression while still allowing a lone } like format('{0}', ...)
|
|
13
|
+
on_step '$step.run =~ "\$\{\{(?:(?!\}\}).)*(github\.event|inputs)\."', highlight: "run"
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
end
|
|
@@ -9,7 +9,8 @@ module Claws
|
|
|
9
9
|
|
|
10
10
|
This rule will flag workflows that have multiple jobs and a root level
|
|
11
11
|
permissions block. If there is a root level permissions block but just one job,
|
|
12
|
-
it will not be flagged.
|
|
12
|
+
it will not be flagged. An empty root level block (`permissions: {}`) grants
|
|
13
|
+
nothing and will not be flagged either.
|
|
13
14
|
|
|
14
15
|
For more information:
|
|
15
16
|
https://github.com/betterment/claws/blob/main/README.md#globalpermissionsblock
|
|
@@ -17,9 +18,10 @@ module Claws
|
|
|
17
18
|
|
|
18
19
|
on_workflow :test_root_level_permissions
|
|
19
20
|
|
|
20
|
-
def test_root_level_permissions(workflow:, job:, step:) # rubocop:disable Lint/UnusedMethodArgument
|
|
21
|
+
def test_root_level_permissions(workflow:, job:, step:) # rubocop:disable Lint/UnusedMethodArgument, Metrics/CyclomaticComplexity
|
|
21
22
|
root_permission_block_line = workflow.keys.filter { |x| x == "permissions" }.first&.line
|
|
22
23
|
return if root_permission_block_line.nil?
|
|
24
|
+
return if empty_permissions?(workflow.permissions)
|
|
23
25
|
|
|
24
26
|
job_count = workflow["jobs"]&.count || 0
|
|
25
27
|
return if job_count < 2
|
|
@@ -29,6 +31,12 @@ module Claws
|
|
|
29
31
|
description:
|
|
30
32
|
)
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def empty_permissions?(permissions)
|
|
38
|
+
permissions.is_a?(Hash) && permissions.empty?
|
|
39
|
+
end
|
|
32
40
|
end
|
|
33
41
|
end
|
|
34
42
|
end
|
|
@@ -66,8 +66,11 @@ module Claws
|
|
|
66
66
|
def analyze_script(script, shell)
|
|
67
67
|
sanitized_script, variables = *sanitize_script(script)
|
|
68
68
|
|
|
69
|
+
# scripts are piped in via stdin, so sourced files can never be followed
|
|
70
|
+
# https://www.shellcheck.net/wiki/SC1090
|
|
71
|
+
# https://www.shellcheck.net/wiki/SC1091
|
|
69
72
|
Open3.popen3(
|
|
70
|
-
shellcheck_bin, "-", "-s", shell
|
|
73
|
+
shellcheck_bin, "-", "-s", shell, "-e", "SC1090,SC1091"
|
|
71
74
|
) do |stdin, stdout, stderr, wait_thr|
|
|
72
75
|
stdin.write(sanitized_script)
|
|
73
76
|
stdin.close
|
data/lib/claws/version.rb
CHANGED
data/lib/claws/workflow.rb
CHANGED
|
@@ -36,7 +36,8 @@ class Workflow
|
|
|
36
36
|
return @on if key.to_s == "on"
|
|
37
37
|
return @jobs if key.to_s == "jobs"
|
|
38
38
|
return @name if key.to_s == "name"
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
@env if key.to_s == "env"
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def get_snippet(line, context: 3)
|
|
@@ -162,7 +163,7 @@ class Workflow
|
|
|
162
163
|
return [] if env.nil?
|
|
163
164
|
|
|
164
165
|
secrets = []
|
|
165
|
-
env.
|
|
166
|
+
env.each_value do |v|
|
|
166
167
|
next unless v.is_a? String
|
|
167
168
|
|
|
168
169
|
secrets += v.scan(/secrets\.([a-zA-Z0-9_]+)/).flatten
|
data/mise.lock
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html
|
|
2
|
+
|
|
3
|
+
lockfile_version = 2
|
|
4
|
+
|
|
5
|
+
[[tools.ruby]]
|
|
6
|
+
version = "3.4.10"
|
|
7
|
+
backend = "core:ruby"
|
|
8
|
+
specifiers = ["3.4.10"]
|
|
9
|
+
|
|
10
|
+
[tools.ruby."platforms.windows-x64"]
|
|
11
|
+
checksum = "sha256:89e3c5e235ac88b9b7e8daaf639eaaab74d7c470667354f6bf0f7432f3191ebb"
|
|
12
|
+
url = "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.10-1/rubyinstaller-3.4.10-1-x64.7z"
|
|
13
|
+
|
|
14
|
+
[[tools.ruby]]
|
|
15
|
+
version = "3.4.10"
|
|
16
|
+
backend = "core:ruby"
|
|
17
|
+
specifiers = ["3.4.10"]
|
|
18
|
+
|
|
19
|
+
[tools.ruby.options]
|
|
20
|
+
compile = "true"
|
|
21
|
+
ruby_build_repo = "https://github.com/rbenv/ruby-build.git"
|
|
22
|
+
ruby_install = "false"
|
|
23
|
+
|
|
24
|
+
[tools.ruby."platforms.linux-arm64"]
|
|
25
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
26
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
|
27
|
+
|
|
28
|
+
[tools.ruby."platforms.linux-arm64-musl"]
|
|
29
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
30
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
|
31
|
+
|
|
32
|
+
[tools.ruby."platforms.linux-x64"]
|
|
33
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
34
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
|
35
|
+
|
|
36
|
+
[tools.ruby."platforms.linux-x64-musl"]
|
|
37
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
38
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
|
39
|
+
|
|
40
|
+
[tools.ruby."platforms.macos-arm64"]
|
|
41
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
42
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
|
43
|
+
|
|
44
|
+
[tools.ruby."platforms.macos-x64"]
|
|
45
|
+
checksum = "sha256:ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec"
|
|
46
|
+
url = "https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.10.tar.gz"
|
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claws-scan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Omar
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: equation
|
|
@@ -76,7 +75,6 @@ extra_rdoc_files: []
|
|
|
76
75
|
files:
|
|
77
76
|
- ".rspec"
|
|
78
77
|
- ".rubocop.yml"
|
|
79
|
-
- ".ruby-version"
|
|
80
78
|
- CONTRIBUTING.md
|
|
81
79
|
- Gemfile
|
|
82
80
|
- Gemfile.lock
|
|
@@ -114,12 +112,13 @@ files:
|
|
|
114
112
|
- lib/claws/version.rb
|
|
115
113
|
- lib/claws/violation.rb
|
|
116
114
|
- lib/claws/workflow.rb
|
|
115
|
+
- mise.lock
|
|
116
|
+
- mise.toml
|
|
117
117
|
homepage: https://github.com/Betterment/claws
|
|
118
118
|
licenses: []
|
|
119
119
|
metadata:
|
|
120
120
|
homepage_uri: https://github.com/Betterment/claws
|
|
121
121
|
source_code_uri: https://github.com/Betterment/claws
|
|
122
|
-
post_install_message:
|
|
123
122
|
rdoc_options: []
|
|
124
123
|
require_paths:
|
|
125
124
|
- lib
|
|
@@ -127,15 +126,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
127
126
|
requirements:
|
|
128
127
|
- - ">="
|
|
129
128
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '3.
|
|
129
|
+
version: '3.4'
|
|
131
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
131
|
requirements:
|
|
133
132
|
- - ">="
|
|
134
133
|
- !ruby/object:Gem::Version
|
|
135
134
|
version: '0'
|
|
136
135
|
requirements: []
|
|
137
|
-
rubygems_version: 3.
|
|
138
|
-
signing_key:
|
|
136
|
+
rubygems_version: 3.6.7
|
|
139
137
|
specification_version: 4
|
|
140
138
|
summary: Analyzes your Github Actions
|
|
141
139
|
test_files: []
|
data/.ruby-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.2.3
|