whoosh 1.2.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 133af39d011ac77fc6e0773ea19652cb990f5c8d129d40b7f301796062e23e1f
4
- data.tar.gz: 5145a7c3177f2ddef7667f8faa6a6c2681b38fd279351c95ceda93ce69999c2a
3
+ metadata.gz: 336c26ea284a871dafa4b1d26f173293947e30470000539dbf3e0da799063bea
4
+ data.tar.gz: 6acf7d5007d008070aaddb543a42de5bddf3b3aa2de838e1be5ccba5d18b9442
5
5
  SHA512:
6
- metadata.gz: 4e99f75634ea05e7e2673164f6bdd8b71ea704e6ee02023370b8b77207666bee6291a02d7423d8d036c4014651ba17673c3f23639e64a2a68b5038799b1dca99
7
- data.tar.gz: 4427cce1a58e9d35841a372ca782f831d6aa3ef513e2309f14e4f6b284a4d12461b102fe5a963768e1a01af2e98db7fc82f7084e970f1a150ef7092f2033c8bf
6
+ metadata.gz: 86aebc850e904960fe87d08aa7c6e8d6aba82c5e411e66e0e9ae65fb64d5510b8ddae4125099554fecac71907c163ce854d1adc416bd8e84ee5f6f3376556809
7
+ data.tar.gz: 99c067d27463fff53a3cb5818836a11e90e0e86d1f886d211770a6407725b6ca0ba72cd3e52c94bd4b204d57e5d282ff89d102863c9410c545c63e3d60bcf332
@@ -224,6 +224,141 @@ module Whoosh
224
224
  end
225
225
  }
226
226
 
227
+ desc "ci", "Run full CI pipeline (lint + security + audit + tests + coverage)"
228
+ def ci
229
+ puts "=> Whoosh CI Pipeline"
230
+ puts "=" * 50
231
+ puts ""
232
+
233
+ steps = []
234
+ skipped = []
235
+
236
+ # Step 1: Rubocop (lint)
237
+ if system("bundle exec rubocop --version > /dev/null 2>&1")
238
+ steps << { name: "Rubocop (lint)", cmd: "bundle exec rubocop --format simple" }
239
+ else
240
+ skipped << "Rubocop (add rubocop to Gemfile)"
241
+ end
242
+
243
+ # Step 2: Brakeman (security scan)
244
+ if system("bundle exec brakeman --version > /dev/null 2>&1")
245
+ steps << { name: "Brakeman (security)", cmd: "bundle exec brakeman -q --no-pager" }
246
+ else
247
+ skipped << "Brakeman (add brakeman to Gemfile)"
248
+ end
249
+
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)
263
+ if system("bundle exec rspec --version > /dev/null 2>&1")
264
+ steps << { name: "RSpec (tests)", cmd: "bundle exec rspec --format progress" }
265
+ else
266
+ skipped << "RSpec (add rspec to Gemfile)"
267
+ end
268
+
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?
274
+
275
+ failed = []
276
+ steps.each_with_index do |step, i|
277
+ puts "--- [#{i + 1}/#{steps.length}] #{step[:name]} ---"
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
+
288
+ if success
289
+ puts " ✓ #{step[:name]} passed"
290
+ else
291
+ puts " ✗ #{step[:name]} FAILED"
292
+ failed << step[:name]
293
+ end
294
+ puts ""
295
+ end
296
+
297
+ puts "=" * 50
298
+ if failed.empty?
299
+ puts "=> All #{steps.length} checks passed! ✓"
300
+ exit 0
301
+ else
302
+ puts "=> FAILED: #{failed.join(', ')}"
303
+ exit 1
304
+ end
305
+ end
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
+
227
362
  desc "new NAME", "Create a new Whoosh project"
228
363
  option :minimal, type: :boolean, default: false
229
364
  option :full, type: :boolean, default: false
@@ -31,6 +31,7 @@ module Whoosh
31
31
  write(dir, ".rspec", rspec_config)
32
32
  write(dir, "Dockerfile", dockerfile)
33
33
  write(dir, ".dockerignore", dockerignore)
34
+ write(dir, ".rubocop.yml", rubocop_config)
34
35
  write(dir, "README.md", readme(name))
35
36
 
36
37
  # Create empty SQLite DB directory
@@ -55,6 +56,8 @@ module Whoosh
55
56
  puts " http://localhost:9292/docs # Swagger UI"
56
57
  puts " http://localhost:9292/metrics # Prometheus metrics"
57
58
  puts ""
59
+ puts " whoosh ci # run lint + security + tests"
60
+ puts ""
58
61
  end
59
62
 
60
63
  class << self
@@ -145,6 +148,10 @@ module Whoosh
145
148
  group :development, :test do
146
149
  gem "rspec"
147
150
  gem "rack-test"
151
+ gem "rubocop", require: false
152
+ gem "brakeman", require: false
153
+ gem "bundler-audit", require: false
154
+ gem "simplecov", require: false
148
155
  end
149
156
  GEM
150
157
 
@@ -251,6 +258,13 @@ module Whoosh
251
258
  <<~RUBY
252
259
  # frozen_string_literal: true
253
260
 
261
+ require "simplecov"
262
+ SimpleCov.start do
263
+ add_filter "/test/"
264
+ add_filter "/spec/"
265
+ minimum_coverage 80
266
+ end
267
+
254
268
  require "whoosh/test"
255
269
  require_relative "../app"
256
270
 
@@ -349,6 +363,35 @@ module Whoosh
349
363
  DOCKERFILE
350
364
  end
351
365
 
366
+ def rubocop_config
367
+ <<~YAML
368
+ AllCops:
369
+ TargetRubyVersion: 3.4
370
+ NewCops: enable
371
+ SuggestExtensions: false
372
+ Exclude:
373
+ - db/migrations/**/*
374
+ - vendor/**/*
375
+
376
+ Style/FrozenStringLiteralComment:
377
+ Enabled: true
378
+
379
+ Style/StringLiterals:
380
+ EnforcedStyle: double_quotes
381
+
382
+ Layout/LineLength:
383
+ Max: 120
384
+
385
+ Metrics/MethodLength:
386
+ Max: 25
387
+
388
+ Metrics/BlockLength:
389
+ Exclude:
390
+ - spec/**/*
391
+ - test/**/*
392
+ YAML
393
+ end
394
+
352
395
  def dockerignore
353
396
  <<~IGNORE
354
397
  .git
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Whoosh
4
- VERSION = "1.2.0"
4
+ VERSION = "1.2.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whoosh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes Dwi Cahyo