whoosh 1.2.1 → 1.2.2
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/lib/whoosh/cli/main.rb +90 -13
- data/lib/whoosh/cli/project_generator.rb +9 -0
- data/lib/whoosh/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 336c26ea284a871dafa4b1d26f173293947e30470000539dbf3e0da799063bea
|
|
4
|
+
data.tar.gz: 6acf7d5007d008070aaddb543a42de5bddf3b3aa2de838e1be5ccba5d18b9442
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86aebc850e904960fe87d08aa7c6e8d6aba82c5e411e66e0e9ae65fb64d5510b8ddae4125099554fecac71907c163ce854d1adc416bd8e84ee5f6f3376556809
|
|
7
|
+
data.tar.gz: 99c067d27463fff53a3cb5818836a11e90e0e86d1f886d211770a6407725b6ca0ba72cd3e52c94bd4b204d57e5d282ff89d102863c9410c545c63e3d60bcf332
|
data/lib/whoosh/cli/main.rb
CHANGED
|
@@ -224,45 +224,67 @@ module Whoosh
|
|
|
224
224
|
end
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
desc "ci", "Run full CI pipeline (lint + security + tests)"
|
|
227
|
+
desc "ci", "Run full CI pipeline (lint + security + audit + tests + coverage)"
|
|
228
228
|
def ci
|
|
229
229
|
puts "=> Whoosh CI Pipeline"
|
|
230
230
|
puts "=" * 50
|
|
231
231
|
puts ""
|
|
232
232
|
|
|
233
233
|
steps = []
|
|
234
|
+
skipped = []
|
|
234
235
|
|
|
235
236
|
# Step 1: Rubocop (lint)
|
|
236
237
|
if system("bundle exec rubocop --version > /dev/null 2>&1")
|
|
237
238
|
steps << { name: "Rubocop (lint)", cmd: "bundle exec rubocop --format simple" }
|
|
238
239
|
else
|
|
239
|
-
|
|
240
|
+
skipped << "Rubocop (add rubocop to Gemfile)"
|
|
240
241
|
end
|
|
241
242
|
|
|
242
|
-
# Step 2: Brakeman (security)
|
|
243
|
+
# Step 2: Brakeman (security scan)
|
|
243
244
|
if system("bundle exec brakeman --version > /dev/null 2>&1")
|
|
244
245
|
steps << { name: "Brakeman (security)", cmd: "bundle exec brakeman -q --no-pager" }
|
|
245
246
|
else
|
|
246
|
-
|
|
247
|
+
skipped << "Brakeman (add brakeman to Gemfile)"
|
|
247
248
|
end
|
|
248
249
|
|
|
249
|
-
# Step 3:
|
|
250
|
+
# Step 3: Bundle audit (CVE check)
|
|
251
|
+
if system("bundle exec bundle-audit version > /dev/null 2>&1")
|
|
252
|
+
steps << { name: "Bundle Audit (CVE)", cmd: "bundle exec bundle-audit check --update" }
|
|
253
|
+
elsif system("bundle audit --help > /dev/null 2>&1")
|
|
254
|
+
steps << { name: "Bundle Audit (CVE)", cmd: "bundle audit" }
|
|
255
|
+
else
|
|
256
|
+
skipped << "Bundle Audit (add bundler-audit to Gemfile)"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Step 4: Secret leak scan (built-in, no gem needed)
|
|
260
|
+
steps << { name: "Secret Scan", type: :secret_scan }
|
|
261
|
+
|
|
262
|
+
# Step 5: RSpec (tests)
|
|
250
263
|
if system("bundle exec rspec --version > /dev/null 2>&1")
|
|
251
264
|
steps << { name: "RSpec (tests)", cmd: "bundle exec rspec --format progress" }
|
|
252
265
|
else
|
|
253
|
-
|
|
266
|
+
skipped << "RSpec (add rspec to Gemfile)"
|
|
254
267
|
end
|
|
255
268
|
|
|
256
|
-
# Step
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
269
|
+
# Step 6: Coverage check (built-in)
|
|
270
|
+
steps << { name: "Coverage Check", type: :coverage_check }
|
|
271
|
+
|
|
272
|
+
skipped.each { |s| puts " [skip] #{s}" }
|
|
273
|
+
puts "" unless skipped.empty?
|
|
261
274
|
|
|
262
275
|
failed = []
|
|
263
276
|
steps.each_with_index do |step, i|
|
|
264
277
|
puts "--- [#{i + 1}/#{steps.length}] #{step[:name]} ---"
|
|
265
|
-
|
|
278
|
+
|
|
279
|
+
success = case step[:type]
|
|
280
|
+
when :secret_scan
|
|
281
|
+
run_secret_scan
|
|
282
|
+
when :coverage_check
|
|
283
|
+
run_coverage_check
|
|
284
|
+
else
|
|
285
|
+
system(step[:cmd])
|
|
286
|
+
end
|
|
287
|
+
|
|
266
288
|
if success
|
|
267
289
|
puts " ✓ #{step[:name]} passed"
|
|
268
290
|
else
|
|
@@ -274,7 +296,7 @@ module Whoosh
|
|
|
274
296
|
|
|
275
297
|
puts "=" * 50
|
|
276
298
|
if failed.empty?
|
|
277
|
-
puts "=> All checks passed! ✓"
|
|
299
|
+
puts "=> All #{steps.length} checks passed! ✓"
|
|
278
300
|
exit 0
|
|
279
301
|
else
|
|
280
302
|
puts "=> FAILED: #{failed.join(', ')}"
|
|
@@ -282,6 +304,61 @@ module Whoosh
|
|
|
282
304
|
end
|
|
283
305
|
end
|
|
284
306
|
|
|
307
|
+
private
|
|
308
|
+
|
|
309
|
+
def run_secret_scan
|
|
310
|
+
patterns = [
|
|
311
|
+
/(?:api[_-]?key|secret|password|token)\s*[:=]\s*["'][A-Za-z0-9+\/=]{8,}["']/i,
|
|
312
|
+
/(?:sk-|pk-|rk-)[a-zA-Z0-9]{20,}/,
|
|
313
|
+
/-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/,
|
|
314
|
+
/AKIA[0-9A-Z]{16}/, # AWS access key
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
leaked = []
|
|
318
|
+
Dir.glob("{app.rb,lib/**/*.rb,endpoints/**/*.rb,config/**/*.rb}").each do |file|
|
|
319
|
+
next if file.include?("spec/") || file.include?("test/")
|
|
320
|
+
content = File.read(file) rescue next
|
|
321
|
+
patterns.each do |pattern|
|
|
322
|
+
content.each_line.with_index do |line, i|
|
|
323
|
+
if line.match?(pattern) && !line.include?("ENV[") && !line.include?("ENV.fetch")
|
|
324
|
+
leaked << "#{file}:#{i + 1}: #{line.strip[0..80]}"
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
if leaked.empty?
|
|
331
|
+
true
|
|
332
|
+
else
|
|
333
|
+
puts " Potential secrets found:"
|
|
334
|
+
leaked.each { |l| puts " #{l}" }
|
|
335
|
+
false
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def run_coverage_check
|
|
340
|
+
coverage_file = File.join(Dir.pwd, "coverage", ".last_run.json")
|
|
341
|
+
unless File.exist?(coverage_file)
|
|
342
|
+
puts " [info] No coverage data found (add simplecov to test_helper for tracking)"
|
|
343
|
+
true # Don't fail if SimpleCov not set up
|
|
344
|
+
else
|
|
345
|
+
require "json"
|
|
346
|
+
data = JSON.parse(File.read(coverage_file))
|
|
347
|
+
coverage = data.dig("result", "line") || data.dig("result", "covered_percent") || 0
|
|
348
|
+
threshold = 80
|
|
349
|
+
|
|
350
|
+
if coverage >= threshold
|
|
351
|
+
puts " Coverage: #{coverage.round(1)}% (threshold: #{threshold}%)"
|
|
352
|
+
true
|
|
353
|
+
else
|
|
354
|
+
puts " Coverage: #{coverage.round(1)}% — below #{threshold}% threshold"
|
|
355
|
+
false
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
public
|
|
361
|
+
|
|
285
362
|
desc "new NAME", "Create a new Whoosh project"
|
|
286
363
|
option :minimal, type: :boolean, default: false
|
|
287
364
|
option :full, type: :boolean, default: false
|
|
@@ -150,6 +150,8 @@ module Whoosh
|
|
|
150
150
|
gem "rack-test"
|
|
151
151
|
gem "rubocop", require: false
|
|
152
152
|
gem "brakeman", require: false
|
|
153
|
+
gem "bundler-audit", require: false
|
|
154
|
+
gem "simplecov", require: false
|
|
153
155
|
end
|
|
154
156
|
GEM
|
|
155
157
|
|
|
@@ -256,6 +258,13 @@ module Whoosh
|
|
|
256
258
|
<<~RUBY
|
|
257
259
|
# frozen_string_literal: true
|
|
258
260
|
|
|
261
|
+
require "simplecov"
|
|
262
|
+
SimpleCov.start do
|
|
263
|
+
add_filter "/test/"
|
|
264
|
+
add_filter "/spec/"
|
|
265
|
+
minimum_coverage 80
|
|
266
|
+
end
|
|
267
|
+
|
|
259
268
|
require "whoosh/test"
|
|
260
269
|
require_relative "../app"
|
|
261
270
|
|
data/lib/whoosh/version.rb
CHANGED