scryer 0.3.0 → 1.1.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/CHANGELOG.md +322 -0
- data/README.md +546 -43
- data/lib/generators/scryer/USAGE +10 -2
- data/lib/generators/scryer/templates/scryer_initializer.rb +15 -0
- data/lib/scryer/ai_fix_suggester.rb +29 -9
- data/lib/scryer/ast.rb +95 -6
- data/lib/scryer/authorization_watcher.rb +156 -0
- data/lib/scryer/baseline.rb +75 -0
- data/lib/scryer/cli.rb +209 -11
- data/lib/scryer/dependency_audit.rb +108 -5
- data/lib/scryer/finding.rb +6 -0
- data/lib/scryer/fix_verifier.rb +82 -0
- data/lib/scryer/minitest.rb +48 -0
- data/lib/scryer/performance_rules/inefficient_save_loop_rule.rb +32 -0
- data/lib/scryer/performance_rules/missing_pagination_rule.rb +1 -0
- data/lib/scryer/performance_rules/n_plus_one_query_rule.rb +1 -0
- data/lib/scryer/performance_rules/unbounded_table_scan_rule.rb +1 -0
- data/lib/scryer/report_renderer.rb +637 -44
- data/lib/scryer/rspec.rb +55 -0
- data/lib/scryer/rule.rb +22 -2
- data/lib/scryer/rules/action_cable_forgery_protection_rule.rb +50 -0
- data/lib/scryer/rules/active_storage_inline_disposition_rule.rb +50 -0
- data/lib/scryer/rules/active_storage_missing_content_type_validation_rule.rb +79 -0
- data/lib/scryer/rules/authentication_bypass_rule.rb +95 -0
- data/lib/scryer/rules/command_injection_rule.rb +3 -0
- data/lib/scryer/rules/consider_all_requests_local_rule.rb +51 -0
- data/lib/scryer/rules/cors_misconfiguration_rule.rb +100 -0
- data/lib/scryer/rules/csrf_protection_rule.rb +60 -11
- data/lib/scryer/rules/force_ssl_rule.rb +48 -0
- data/lib/scryer/rules/graphql_missing_query_limits_rule.rb +106 -0
- data/lib/scryer/rules/hardcoded_basic_auth_rule.rb +51 -0
- data/lib/scryer/rules/hardcoded_secret_key_base_rule.rb +58 -0
- data/lib/scryer/rules/hardcoded_secret_rule.rb +3 -0
- data/lib/scryer/rules/host_authorization_disabled_rule.rb +50 -0
- data/lib/scryer/rules/idor_rule.rb +165 -0
- data/lib/scryer/rules/insecure_cookie_serializer_rule.rb +47 -0
- data/lib/scryer/rules/job_raw_params_rule.rb +131 -0
- data/lib/scryer/rules/jwt_insecure_rule.rb +123 -0
- data/lib/scryer/rules/mass_assignment_rule.rb +34 -10
- data/lib/scryer/rules/missing_authorization_rule.rb +103 -0
- data/lib/scryer/rules/missing_policy_scope_rule.rb +134 -0
- data/lib/scryer/rules/open_redirect_rule.rb +3 -0
- data/lib/scryer/rules/path_traversal_rule.rb +110 -0
- data/lib/scryer/rules/security_headers_rule.rb +133 -0
- data/lib/scryer/rules/sql_injection_rule.rb +3 -0
- data/lib/scryer/rules/ssrf_rule.rb +139 -0
- data/lib/scryer/rules/unsafe_deserialization_rule.rb +3 -0
- data/lib/scryer/rules/verbose_production_log_level_rule.rb +53 -0
- data/lib/scryer/rules/weak_crypto_rule.rb +37 -2
- data/lib/scryer/rules/weak_session_cookie_rule.rb +51 -0
- data/lib/scryer/rules/xss_unsafe_html_rule.rb +41 -0
- data/lib/scryer/style_rules/frozen_string_literal_rule.rb +1 -0
- data/lib/scryer/version.rb +1 -1
- data/lib/scryer.rb +15 -0
- data/lib/tasks/scryer.rake +138 -13
- metadata +41 -12
data/lib/tasks/scryer.rake
CHANGED
|
@@ -8,7 +8,7 @@ require "fileutils"
|
|
|
8
8
|
# ActiveSupport methods (`.presence`/`.blank?`) for the same reason — plain
|
|
9
9
|
# Ruby nil-or-empty checks only.
|
|
10
10
|
namespace :scryer do
|
|
11
|
-
desc "Run Scryer and write a report. Args are any mix of json/html/csv (which formats " \
|
|
11
|
+
desc "Run Scryer and write a report. Args are any mix of json/html/csv/sarif (which formats " \
|
|
12
12
|
"to write — default json,html), the token 'nodeps' (skip the dependency audit — OSV.dev " \
|
|
13
13
|
"vulnerable gems + insecure git/http sources — that otherwise runs by default; use for a " \
|
|
14
14
|
"fast, fully offline run), plus at most one path (a directory when writing more than one " \
|
|
@@ -16,7 +16,9 @@ namespace :scryer do
|
|
|
16
16
|
"so pass each token as its own item rather than one comma-joined string. " \
|
|
17
17
|
"e.g. rails scryer:report, rails 'scryer:report[html]', " \
|
|
18
18
|
"rails 'scryer:report[json,doc/security.json]', rails 'scryer:report[json,html]', " \
|
|
19
|
-
"rails 'scryer:report[html,nodeps]', rails 'scryer:report[csv]'"
|
|
19
|
+
"rails 'scryer:report[html,nodeps]', rails 'scryer:report[csv]', rails 'scryer:report[sarif]'. " \
|
|
20
|
+
"Set SCRYER_BASELINE=PATH (an env var, not a bracket arg — see scryer:save_baseline) to " \
|
|
21
|
+
"report only findings new since that baseline was saved."
|
|
20
22
|
task :report, [:format] do |_, args|
|
|
21
23
|
root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
|
|
22
24
|
dirs = Scryer.configuration.dirs
|
|
@@ -38,12 +40,27 @@ namespace :scryer do
|
|
|
38
40
|
dependency_findings = []
|
|
39
41
|
if run_deps
|
|
40
42
|
puts "Scryer: querying OSV.dev for known-vulnerable gems (needs network)..."
|
|
41
|
-
dependency_findings = Scryer::DependencyAudit.insecure_sources(root) + Scryer::DependencyAudit.vulnerable_gems(root)
|
|
43
|
+
dependency_findings = Scryer::DependencyAudit.insecure_sources(root) + Scryer::DependencyAudit.vulnerable_gems(root) +
|
|
44
|
+
Scryer::DependencyAudit.ruby_eol_check(root) + Scryer::DependencyAudit.credentials_exposure_check(root)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Rake bracket args are already stretched thin (format tokens + nodeps +
|
|
48
|
+
# one output path) — an ENV var is the more conventional way Rails rake
|
|
49
|
+
# tasks take an extra config value without overloading positional args
|
|
50
|
+
# further. `rails 'scryer:save_baseline[tmp/scryer_baseline.json]'` writes
|
|
51
|
+
# one; `SCRYER_BASELINE=tmp/scryer_baseline.json rails scryer:report`
|
|
52
|
+
# reads it back. See Scryer::Baseline / the CLI's --baseline flag for
|
|
53
|
+
# what this actually does (fingerprint-based new-vs-fixed diffing, not
|
|
54
|
+
# tied to line number).
|
|
55
|
+
baseline_path = blank_to_nil(ENV["SCRYER_BASELINE"])
|
|
56
|
+
fixed_count = 0
|
|
57
|
+
if baseline_path
|
|
58
|
+
dependency_findings, fixed_count = ScryerTasks.apply_baseline(baseline_path, result, dependency_findings)
|
|
42
59
|
end
|
|
43
60
|
|
|
44
61
|
if Scryer.configuration.ai_client
|
|
45
62
|
puts "Scryer: rewriting suggested fixes via the configured AI client..."
|
|
46
|
-
Scryer::AiFixSuggester.enhance_result!(result)
|
|
63
|
+
Scryer::AiFixSuggester.enhance_result!(result, root: root)
|
|
47
64
|
Scryer::AiFixSuggester.enhance_many!(dependency_findings) unless dependency_findings.empty?
|
|
48
65
|
end
|
|
49
66
|
|
|
@@ -63,12 +80,14 @@ namespace :scryer do
|
|
|
63
80
|
content = case format
|
|
64
81
|
when "json" then renderer.as_json
|
|
65
82
|
when "csv" then renderer.as_csv
|
|
83
|
+
when "sarif" then renderer.as_sarif
|
|
66
84
|
else renderer.as_html
|
|
67
85
|
end
|
|
68
86
|
File.write(path, content)
|
|
69
87
|
end
|
|
70
88
|
|
|
71
|
-
ScryerTasks.print_summary(result: result, dependency_findings: dependency_findings, ran_deps: run_deps, paths: paths
|
|
89
|
+
ScryerTasks.print_summary(result: result, dependency_findings: dependency_findings, ran_deps: run_deps, paths: paths,
|
|
90
|
+
renderer: renderer, fixed_count: fixed_count, baseline_path: baseline_path)
|
|
72
91
|
|
|
73
92
|
# Same gate as the `scryer` executable and scryer:audit_dependencies
|
|
74
93
|
# below: fail the task (and so the CI job running it) on any security or
|
|
@@ -81,6 +100,37 @@ namespace :scryer do
|
|
|
81
100
|
end
|
|
82
101
|
end
|
|
83
102
|
|
|
103
|
+
desc "Convenience wrapper for CI: runs scryer:report with CI-sensible defaults — JSON + " \
|
|
104
|
+
"SARIF written under tmp/ (SARIF for GitHub Code Scanning / similar dashboards, JSON as " \
|
|
105
|
+
"the machine-readable form other CI steps can parse), dependency audit on, same " \
|
|
106
|
+
"SCRYER_BASELINE support and same fail-the-build-on-findings behavior as scryer:report. " \
|
|
107
|
+
"Equivalent to `rails 'scryer:report[json,sarif]'` under a name that doesn't require " \
|
|
108
|
+
"remembering the bracket-arg syntax. e.g. rails scryer:ci"
|
|
109
|
+
task :ci do
|
|
110
|
+
Rake::Task["scryer:report"].invoke("json", "sarif")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
desc "Run Scryer and save every finding's fingerprint to PATH, for later comparison via " \
|
|
114
|
+
"SCRYER_BASELINE=PATH rails scryer:report (see that task's SCRYER_BASELINE note). " \
|
|
115
|
+
"Runs the same scan as scryer:report (including the dependency audit) but writes no " \
|
|
116
|
+
"report files. e.g. rails 'scryer:save_baseline[tmp/scryer_baseline.json]'"
|
|
117
|
+
task :save_baseline, [:path] do |_, args|
|
|
118
|
+
path = args[:path] || abort("Scryer: scryer:save_baseline needs a path, " \
|
|
119
|
+
"e.g. rails 'scryer:save_baseline[tmp/scryer_baseline.json]'")
|
|
120
|
+
root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
|
|
121
|
+
dirs = Scryer.configuration.dirs
|
|
122
|
+
|
|
123
|
+
result = Scryer::Scanner.new(root: root, dirs: dirs, skip_rules: Scryer.configuration.skip_rules).call
|
|
124
|
+
puts "Scryer: querying OSV.dev for known-vulnerable gems (needs network)..."
|
|
125
|
+
dependency_findings = Scryer::DependencyAudit.insecure_sources(root) + Scryer::DependencyAudit.vulnerable_gems(root) +
|
|
126
|
+
Scryer::DependencyAudit.ruby_eol_check(root) + Scryer::DependencyAudit.credentials_exposure_check(root)
|
|
127
|
+
|
|
128
|
+
all_findings = (result.security_findings + result.performance_findings + result.style_findings).map(&:to_h) +
|
|
129
|
+
dependency_findings.map(&:to_h)
|
|
130
|
+
Scryer::Baseline.save(path, all_findings)
|
|
131
|
+
puts "Scryer: saved baseline of #{all_findings.size} finding(s) to #{path}."
|
|
132
|
+
end
|
|
133
|
+
|
|
84
134
|
desc "Check Gemfile.lock for known-vulnerable gem versions (via OSV.dev — needs network) " \
|
|
85
135
|
"and insecure git/http gem sources (offline). Exits non-zero if anything is found, so " \
|
|
86
136
|
"this can gate CI the same way `bundle-audit check` does."
|
|
@@ -92,20 +142,23 @@ namespace :scryer do
|
|
|
92
142
|
|
|
93
143
|
puts "Scryer: querying OSV.dev for known vulnerabilities (needs network)..."
|
|
94
144
|
vulnerable = Scryer::DependencyAudit.vulnerable_gems(root)
|
|
145
|
+
ruby_eol = Scryer::DependencyAudit.ruby_eol_check(root)
|
|
146
|
+
credentials_exposure = Scryer::DependencyAudit.credentials_exposure_check(root)
|
|
95
147
|
|
|
96
|
-
(insecure + vulnerable).each do |f|
|
|
97
|
-
|
|
98
|
-
puts label
|
|
148
|
+
(insecure + vulnerable + ruby_eol + credentials_exposure).each do |f|
|
|
149
|
+
puts "[#{f.severity.upcase}] #{ScryerTasks.dependency_label(f)}"
|
|
99
150
|
puts " fix: #{f.suggested_fix}"
|
|
100
151
|
end
|
|
101
152
|
|
|
102
|
-
total = insecure.size + vulnerable.size
|
|
103
|
-
puts "\nScryer: #{total} dependency finding(s) (#{insecure.size} insecure source,
|
|
153
|
+
total = insecure.size + vulnerable.size + ruby_eol.size + credentials_exposure.size
|
|
154
|
+
puts "\nScryer: #{total} dependency finding(s) (#{insecure.size} insecure source, " \
|
|
155
|
+
"#{vulnerable.size} vulnerable gem, #{ruby_eol.size} Ruby EOL, " \
|
|
156
|
+
"#{credentials_exposure.size} credentials exposure)."
|
|
104
157
|
abort("Scryer: dependency audit failed.") if total.positive?
|
|
105
158
|
end
|
|
106
159
|
|
|
107
|
-
VALID_FORMATS = %w[json html csv].freeze
|
|
108
|
-
EXTENSION_FOR_FORMAT = { "json" => "json", "html" => "html", "csv" => "csv" }.freeze
|
|
160
|
+
VALID_FORMATS = %w[json html csv sarif].freeze
|
|
161
|
+
EXTENSION_FOR_FORMAT = { "json" => "json", "html" => "html", "csv" => "csv", "sarif" => "sarif" }.freeze
|
|
109
162
|
NO_DEPS_TOKEN = "nodeps".freeze
|
|
110
163
|
|
|
111
164
|
# tokens is every bracket arg Rake was given, e.g. %w[json doc/security.json] or
|
|
@@ -178,11 +231,47 @@ module ScryerTasks
|
|
|
178
231
|
nil
|
|
179
232
|
end
|
|
180
233
|
|
|
234
|
+
def dependency_label(f)
|
|
235
|
+
return f.message if f.kind == "insecure_source"
|
|
236
|
+
return "#{f.gem_name} #{f.installed_version} - #{f.advisory_id}: #{f.title}" if f.advisory_id
|
|
237
|
+
|
|
238
|
+
"#{f.gem_name} #{f.installed_version}: #{f.title}"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Same logic as Scryer::CLI#apply_baseline (see that method's comment for
|
|
242
|
+
# why fixed_count has to be computed once against the combined set of
|
|
243
|
+
# every category's current fingerprints, not once per category summed).
|
|
244
|
+
def apply_baseline(path, result, dependency_findings)
|
|
245
|
+
baseline_fingerprints = Scryer::Baseline.load(path)
|
|
246
|
+
|
|
247
|
+
security_hashes = result.security_findings.map(&:to_h)
|
|
248
|
+
performance_hashes = result.performance_findings.map(&:to_h)
|
|
249
|
+
style_hashes = result.style_findings.map(&:to_h)
|
|
250
|
+
dependency_hashes = dependency_findings.map(&:to_h)
|
|
251
|
+
|
|
252
|
+
all_current_fingerprints = Scryer::Baseline.fingerprints(security_hashes + performance_hashes + style_hashes + dependency_hashes)
|
|
253
|
+
fixed_count = (baseline_fingerprints - all_current_fingerprints.to_set).size
|
|
254
|
+
|
|
255
|
+
result.security_findings = filter_new(result.security_findings, security_hashes, baseline_fingerprints)
|
|
256
|
+
result.performance_findings = filter_new(result.performance_findings, performance_hashes, baseline_fingerprints)
|
|
257
|
+
result.style_findings = filter_new(result.style_findings, style_hashes, baseline_fingerprints)
|
|
258
|
+
filtered_deps = filter_new(dependency_findings, dependency_hashes, baseline_fingerprints)
|
|
259
|
+
|
|
260
|
+
[filtered_deps, fixed_count]
|
|
261
|
+
rescue Scryer::Baseline::LoadError => e
|
|
262
|
+
abort("Scryer: #{e.message}")
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def filter_new(objects, hashes, baseline_fingerprints)
|
|
266
|
+
fingerprints = Scryer::Baseline.fingerprints(hashes)
|
|
267
|
+
objects.each_with_index.reject { |_, i| baseline_fingerprints.include?(fingerprints[i]) }.map(&:first)
|
|
268
|
+
end
|
|
269
|
+
|
|
181
270
|
# The "one audit command" summary — a single scan's worth of every
|
|
182
271
|
# category Scryer covers (security, performance, duplicate/smelly code,
|
|
183
272
|
# dependencies), the same categories usually split across RuboCop +
|
|
184
273
|
# Brakeman + bundler-audit + Reek, side by side in one box.
|
|
185
|
-
def print_summary(result:, dependency_findings:, ran_deps:, paths:)
|
|
274
|
+
def print_summary(result:, dependency_findings:, ran_deps:, paths:, renderer:, fixed_count: 0, baseline_path: nil)
|
|
186
275
|
# "Code Quality" is the umbrella label for both duplicate-code groups
|
|
187
276
|
# and rule-based style findings (e.g. frozen_string_literal) — two
|
|
188
277
|
# different detectors, same broad concern, one row in the box.
|
|
@@ -198,14 +287,25 @@ module ScryerTasks
|
|
|
198
287
|
]
|
|
199
288
|
|
|
200
289
|
divider = "─" * 32
|
|
290
|
+
score = renderer.security_score
|
|
201
291
|
puts ""
|
|
202
292
|
puts "Scryer Audit — #{result.files_scanned} files scanned"
|
|
203
293
|
puts divider
|
|
204
294
|
puts ""
|
|
295
|
+
if baseline_path
|
|
296
|
+
puts "Baseline: #{baseline_path} — showing new findings only (#{fixed_count} fixed since baseline)."
|
|
297
|
+
puts ""
|
|
298
|
+
end
|
|
299
|
+
clean_rate = renderer.rules_clean_rate
|
|
300
|
+
puts "Security Score: #{score["score"]}/100 (#{score["grade"]})"
|
|
301
|
+
puts "Checks: #{clean_rate["clean"]}/#{clean_rate["total"]} rules clean (#{clean_rate["percent"]}%)"
|
|
302
|
+
puts ""
|
|
205
303
|
rows.each { |label, count| puts summary_row(label, count) }
|
|
206
304
|
puts divider
|
|
207
305
|
puts summary_row("Total", total)
|
|
208
306
|
puts ""
|
|
307
|
+
print_top_priorities(renderer.top_risks)
|
|
308
|
+
print_owasp_coverage(renderer.owasp_coverage)
|
|
209
309
|
paths.each { |format, path| puts "#{format.upcase} report: #{path}" }
|
|
210
310
|
end
|
|
211
311
|
|
|
@@ -213,4 +313,29 @@ module ScryerTasks
|
|
|
213
313
|
value = count.nil? ? "skipped (nodeps)" : "#{count} finding#{"s" unless count == 1}"
|
|
214
314
|
"#{label.ljust(14)}#{value.rjust(20)}"
|
|
215
315
|
end
|
|
316
|
+
|
|
317
|
+
# The categories above are counted separately, but nothing else ranks
|
|
318
|
+
# across them — this is what actually backs "tells you what to fix
|
|
319
|
+
# first" rather than just splitting findings into four buckets. Same
|
|
320
|
+
# data ReportRenderer#top_risks already sorts for the HTML report.
|
|
321
|
+
def print_top_priorities(risks)
|
|
322
|
+
return if risks.empty?
|
|
323
|
+
|
|
324
|
+
puts "Top priorities:"
|
|
325
|
+
risks.each_with_index do |r, i|
|
|
326
|
+
puts " #{i + 1}. [#{r[:severity]}] #{r[:category]} — #{r[:label]} (#{r[:location]})"
|
|
327
|
+
end
|
|
328
|
+
puts ""
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Byproduct of every security rule carrying an owasp_category — see
|
|
332
|
+
# ReportRenderer#owasp_coverage. Scryer's own best-effort tagging, not an
|
|
333
|
+
# OWASP-audited mapping (documented in full in the README).
|
|
334
|
+
def print_owasp_coverage(coverage)
|
|
335
|
+
return if coverage.empty?
|
|
336
|
+
|
|
337
|
+
puts "OWASP Top 10 (2021) coverage:"
|
|
338
|
+
coverage.each { |category, count| puts " #{category}: #{count} finding#{"s" unless count == 1}" }
|
|
339
|
+
puts ""
|
|
340
|
+
end
|
|
216
341
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scryer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ram Laxman Yadav
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -25,18 +25,21 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '13.0'
|
|
27
27
|
description: |
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
doesn't
|
|
28
|
+
Scryer scans a Ruby/Rails codebase for security vulnerabilities, performance problems,
|
|
29
|
+
dependency risk, and code-quality issues, then ranks everything it finds by severity across
|
|
30
|
+
all of those categories — so a scan ends with one answer to "what's most worth fixing," not
|
|
31
|
+
four separate reports to reconcile by hand. (Style/lint is RuboCop's job — Scryer doesn't
|
|
32
|
+
touch that, except one narrow check.)
|
|
32
33
|
|
|
33
|
-
Detects SQL injection, mass assignment,
|
|
34
|
-
|
|
35
|
-
known-vulnerable gems via a live
|
|
34
|
+
Detects SQL injection, mass assignment, SSRF, path traversal, IDOR, insecure JWT/CORS/session
|
|
35
|
+
config, hardcoded secrets, XSS, weak crypto, and more; N+1 queries, missing pagination, and
|
|
36
|
+
other performance heuristics; near-duplicate code; and known-vulnerable gems via a live
|
|
37
|
+
OSV.dev dependency audit — on by default, every run.
|
|
36
38
|
|
|
37
39
|
Every finding includes a human-reviewable suggested fix — never auto-applied, optionally
|
|
38
40
|
rewritten against your actual code by any LLM you configure. Reports in JSON, self-contained
|
|
39
|
-
HTML, or
|
|
41
|
+
HTML, CSV, or SARIF (for GitHub Code Scanning). Zero runtime dependencies beyond Ruby's own
|
|
42
|
+
stdlib.
|
|
40
43
|
email:
|
|
41
44
|
executables:
|
|
42
45
|
- scryer
|
|
@@ -54,12 +57,16 @@ files:
|
|
|
54
57
|
- lib/scryer/ai_client.rb
|
|
55
58
|
- lib/scryer/ai_fix_suggester.rb
|
|
56
59
|
- lib/scryer/ast.rb
|
|
60
|
+
- lib/scryer/authorization_watcher.rb
|
|
61
|
+
- lib/scryer/baseline.rb
|
|
57
62
|
- lib/scryer/cache_extractor.rb
|
|
58
63
|
- lib/scryer/cli.rb
|
|
59
64
|
- lib/scryer/dependency_audit.rb
|
|
60
65
|
- lib/scryer/duplicate_detector.rb
|
|
61
66
|
- lib/scryer/finding.rb
|
|
67
|
+
- lib/scryer/fix_verifier.rb
|
|
62
68
|
- lib/scryer/method_extractor.rb
|
|
69
|
+
- lib/scryer/minitest.rb
|
|
63
70
|
- lib/scryer/performance_rules/inefficient_save_loop_rule.rb
|
|
64
71
|
- lib/scryer/performance_rules/missing_pagination_rule.rb
|
|
65
72
|
- lib/scryer/performance_rules/n_plus_one_query_rule.rb
|
|
@@ -68,16 +75,39 @@ files:
|
|
|
68
75
|
- lib/scryer/query_watcher.rb
|
|
69
76
|
- lib/scryer/railtie.rb
|
|
70
77
|
- lib/scryer/report_renderer.rb
|
|
78
|
+
- lib/scryer/rspec.rb
|
|
71
79
|
- lib/scryer/rule.rb
|
|
72
80
|
- lib/scryer/rule_set.rb
|
|
81
|
+
- lib/scryer/rules/action_cable_forgery_protection_rule.rb
|
|
82
|
+
- lib/scryer/rules/active_storage_inline_disposition_rule.rb
|
|
83
|
+
- lib/scryer/rules/active_storage_missing_content_type_validation_rule.rb
|
|
84
|
+
- lib/scryer/rules/authentication_bypass_rule.rb
|
|
73
85
|
- lib/scryer/rules/command_injection_rule.rb
|
|
86
|
+
- lib/scryer/rules/consider_all_requests_local_rule.rb
|
|
87
|
+
- lib/scryer/rules/cors_misconfiguration_rule.rb
|
|
74
88
|
- lib/scryer/rules/csrf_protection_rule.rb
|
|
89
|
+
- lib/scryer/rules/force_ssl_rule.rb
|
|
90
|
+
- lib/scryer/rules/graphql_missing_query_limits_rule.rb
|
|
91
|
+
- lib/scryer/rules/hardcoded_basic_auth_rule.rb
|
|
92
|
+
- lib/scryer/rules/hardcoded_secret_key_base_rule.rb
|
|
75
93
|
- lib/scryer/rules/hardcoded_secret_rule.rb
|
|
94
|
+
- lib/scryer/rules/host_authorization_disabled_rule.rb
|
|
95
|
+
- lib/scryer/rules/idor_rule.rb
|
|
96
|
+
- lib/scryer/rules/insecure_cookie_serializer_rule.rb
|
|
97
|
+
- lib/scryer/rules/job_raw_params_rule.rb
|
|
98
|
+
- lib/scryer/rules/jwt_insecure_rule.rb
|
|
76
99
|
- lib/scryer/rules/mass_assignment_rule.rb
|
|
100
|
+
- lib/scryer/rules/missing_authorization_rule.rb
|
|
101
|
+
- lib/scryer/rules/missing_policy_scope_rule.rb
|
|
77
102
|
- lib/scryer/rules/open_redirect_rule.rb
|
|
103
|
+
- lib/scryer/rules/path_traversal_rule.rb
|
|
104
|
+
- lib/scryer/rules/security_headers_rule.rb
|
|
78
105
|
- lib/scryer/rules/sql_injection_rule.rb
|
|
106
|
+
- lib/scryer/rules/ssrf_rule.rb
|
|
79
107
|
- lib/scryer/rules/unsafe_deserialization_rule.rb
|
|
108
|
+
- lib/scryer/rules/verbose_production_log_level_rule.rb
|
|
80
109
|
- lib/scryer/rules/weak_crypto_rule.rb
|
|
110
|
+
- lib/scryer/rules/weak_session_cookie_rule.rb
|
|
81
111
|
- lib/scryer/rules/xss_unsafe_html_rule.rb
|
|
82
112
|
- lib/scryer/scanner.rb
|
|
83
113
|
- lib/scryer/style_rules/frozen_string_literal_rule.rb
|
|
@@ -110,6 +140,5 @@ requirements: []
|
|
|
110
140
|
rubygems_version: 3.5.11
|
|
111
141
|
signing_key:
|
|
112
142
|
specification_version: 4
|
|
113
|
-
summary: Ruby/Rails security &
|
|
114
|
-
bundler-audit + Reek.
|
|
143
|
+
summary: Ruby/Rails application security & risk auditor — tells you what to fix first.
|
|
115
144
|
test_files: []
|