gem_guard 0.1.6 → 0.1.7

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: '073099f4fd844fee5ffd2b5466fbee6df36a8c5b9d640039efb0cbdb4db89b97'
4
- data.tar.gz: 21ba615adb70721d4f9ede82e3a43361a92e72e683c53530504913250ccd7309
3
+ metadata.gz: 747dee6cd137e68fae4e5086d37a40bc5fabb67672f67d06a901627ac47c00cd
4
+ data.tar.gz: 75c793fc063db05b04635f2c12fa7abf7169f815f57bd6c64f8da0da2d3ea03a
5
5
  SHA512:
6
- metadata.gz: d1bc314331a645c4b2d9791f41d852620fc7a977fc7eaf90ea927743f297057f4af93c40da2788422c8c468b11fbb1ad4d80d59f16cb4a0c9c063f37ebed809c
7
- data.tar.gz: 1dc4f927542ae0983fb73a0d285c66f61c93960f1128bde659a313bbda24a7e6625d41acfdc48fcadeb8600f78bdb2f6de2b052e072a553aa78a937ad841b7dc
6
+ metadata.gz: cb271a7619b956d0b6271d3fc20c9cee8d75709951b7e8984c051de4e261ba3fdba76ea450fbd2871ece6ec0acc89bb68263e514bb1af9e53dc66e4bdc277d88
7
+ data.tar.gz: 5ebc3d1e492ea6d273ed740b67b61db1ea729e19eebfc1107b4511112d31641c1347ed2af90c7dd7939350d151826b18432d91279cedcf5873ff8b1a2809fd6a
data/lib/gem_guard/cli.rb CHANGED
@@ -1,25 +1,65 @@
1
1
  require "thor"
2
+ require "stringio"
2
3
 
3
4
  module GemGuard
4
5
  class CLI < Thor
6
+ # Exit codes for CI/CD integration
7
+ EXIT_SUCCESS = 0
8
+ EXIT_VULNERABILITIES_FOUND = 1
9
+ EXIT_ERROR = 2
10
+
5
11
  desc "scan", "Scan dependencies for known vulnerabilities"
6
- option :format, type: :string, default: "table", desc: "Output format (table, json)"
7
- option :lockfile, type: :string, default: "Gemfile.lock", desc: "Path to Gemfile.lock"
12
+ option :format, type: :string, desc: "Output format (table, json)"
13
+ option :lockfile, type: :string, desc: "Path to Gemfile.lock"
14
+ option :config, type: :string, default: ".gemguard.yml", desc: "Path to config file"
15
+ option :fail_on_vulnerabilities, type: :boolean, desc: "Exit with code 1 if vulnerabilities found"
16
+ option :severity_threshold, type: :string, desc: "Minimum severity level (low, medium, high, critical)"
17
+ option :output, type: :string, desc: "Output file path"
8
18
  def scan
9
- lockfile_path = options[:lockfile]
19
+ config = Config.new(options[:config])
20
+
21
+ # Override config with CLI options
22
+ lockfile_path = options[:lockfile] || config.lockfile_path
23
+ format = options[:format] || config.output_format
24
+ fail_on_vulns = options[:fail_on_vulnerabilities].nil? ? config.fail_on_vulnerabilities? : options[:fail_on_vulnerabilities]
25
+ severity_threshold = options[:severity_threshold] || config.severity_threshold
26
+ output_file = options[:output] || config.output_file
10
27
 
11
28
  unless File.exist?(lockfile_path)
12
29
  puts "Error: #{lockfile_path} not found"
13
- exit 1
30
+ exit EXIT_ERROR
14
31
  end
15
32
 
16
- dependencies = Parser.new.parse(lockfile_path)
17
- vulnerabilities = VulnerabilityFetcher.new.fetch_for(dependencies)
18
- analysis = Analyzer.new.analyze(dependencies, vulnerabilities)
33
+ begin
34
+ dependencies = Parser.new.parse(lockfile_path)
35
+ vulnerabilities = VulnerabilityFetcher.new.fetch_for(dependencies)
36
+
37
+ # Filter vulnerabilities based on config
38
+ filtered_vulnerabilities = filter_vulnerabilities(vulnerabilities, config)
39
+
40
+ analysis = Analyzer.new.analyze(dependencies, filtered_vulnerabilities)
41
+
42
+ # Filter analysis based on severity threshold
43
+ filtered_analysis = filter_analysis_by_severity(analysis, severity_threshold, config)
19
44
 
20
- Reporter.new.report(analysis, format: options[:format])
45
+ if output_file
46
+ output_content = capture_report_output(filtered_analysis, format)
47
+ File.write(output_file, output_content)
48
+ puts "Report written to #{output_file}"
49
+ else
50
+ Reporter.new.report(filtered_analysis, format: format)
51
+ end
21
52
 
22
- exit 1 if analysis.has_vulnerabilities?
53
+ # Exit with appropriate code for CI/CD
54
+ if filtered_analysis.has_vulnerabilities? && fail_on_vulns
55
+ exit EXIT_VULNERABILITIES_FOUND
56
+ else
57
+ exit EXIT_SUCCESS
58
+ end
59
+ rescue => e
60
+ puts "Error: #{e.message}"
61
+ exit EXIT_ERROR
62
+ end
23
63
  end
24
64
 
25
65
  desc "sbom", "Generate Software Bill of Materials (SBOM)"
@@ -58,9 +98,107 @@ module GemGuard
58
98
  end
59
99
  end
60
100
 
101
+ desc "config", "Manage configuration"
102
+ option :init, type: :boolean, desc: "Initialize a new .gemguard.yml config file"
103
+ option :show, type: :boolean, desc: "Show current configuration"
104
+ option :path, type: :string, default: ".gemguard.yml", desc: "Config file path"
105
+ def config
106
+ config_file = Config.new(options[:path])
107
+
108
+ if options[:init]
109
+ if File.exist?(options[:path])
110
+ puts "Config file #{options[:path]} already exists"
111
+ exit EXIT_ERROR
112
+ end
113
+
114
+ # Create default config file
115
+ default_config = {
116
+ "lockfile" => "Gemfile.lock",
117
+ "format" => "table",
118
+ "fail_on_vulnerabilities" => true,
119
+ "severity_threshold" => "low",
120
+ "ignore_vulnerabilities" => [],
121
+ "ignore_gems" => [],
122
+ "output_file" => nil,
123
+ "project_name" => config_file.send(:detect_project_name),
124
+ "sbom" => {
125
+ "format" => "spdx",
126
+ "include_dev_dependencies" => false
127
+ },
128
+ "scan" => {
129
+ "sources" => ["osv", "ruby_advisory_db"],
130
+ "timeout" => 30
131
+ }
132
+ }
133
+
134
+ File.write(options[:path], YAML.dump(default_config))
135
+ puts "Created #{options[:path]} with default configuration"
136
+ elsif options[:show]
137
+ if config_file.exists?
138
+ puts File.read(options[:path])
139
+ else
140
+ puts "No config file found at #{options[:path]}"
141
+ puts "Run 'gem_guard config --init' to create one"
142
+ end
143
+ else
144
+ puts "Usage: gem_guard config [--init|--show] [--path PATH]"
145
+ puts " --init Create a new .gemguard.yml config file"
146
+ puts " --show Display current configuration"
147
+ puts " --path Specify config file path (default: .gemguard.yml)"
148
+ end
149
+ end
150
+
61
151
  desc "version", "Show gem_guard version"
62
152
  def version
63
153
  puts GemGuard::VERSION
64
154
  end
155
+
156
+ private
157
+
158
+ def filter_vulnerabilities(vulnerabilities, config)
159
+ vulnerabilities.reject do |vuln|
160
+ config.should_ignore_vulnerability?(vuln.id)
161
+ end
162
+ end
163
+
164
+ def filter_analysis_by_severity(analysis, severity_threshold, config)
165
+ return analysis unless severity_threshold
166
+
167
+ filtered_vulnerable_deps = analysis.vulnerable_dependencies.select do |vuln_dep|
168
+ vuln_dep.vulnerabilities.any? do |vuln|
169
+ config.meets_severity_threshold?(extract_severity_level(vuln.severity))
170
+ end
171
+ end
172
+
173
+ # Create new analysis with filtered vulnerabilities
174
+ GemGuard::Analysis.new(filtered_vulnerable_deps)
175
+ end
176
+
177
+ def extract_severity_level(severity_string)
178
+ return "unknown" if severity_string.nil? || severity_string.empty?
179
+
180
+ # Extract severity from CVSS string or direct severity
181
+ case severity_string.downcase
182
+ when /critical/
183
+ "critical"
184
+ when /high/
185
+ "high"
186
+ when /medium/
187
+ "medium"
188
+ when /low/
189
+ "low"
190
+ else
191
+ "unknown"
192
+ end
193
+ end
194
+
195
+ def capture_report_output(analysis, format)
196
+ old_stdout = $stdout
197
+ $stdout = StringIO.new
198
+ Reporter.new.report(analysis, format: format)
199
+ $stdout.string
200
+ ensure
201
+ $stdout = old_stdout
202
+ end
65
203
  end
66
204
  end
@@ -0,0 +1,193 @@
1
+ require "yaml"
2
+
3
+ module GemGuard
4
+ class Config
5
+ DEFAULT_CONFIG = {
6
+ "lockfile" => "Gemfile.lock",
7
+ "format" => "table",
8
+ "fail_on_vulnerabilities" => true,
9
+ "severity_threshold" => "low",
10
+ "ignore_vulnerabilities" => [],
11
+ "ignore_gems" => [],
12
+ "output_file" => nil,
13
+ "project_name" => nil,
14
+ "sbom" => {
15
+ "format" => "spdx",
16
+ "include_dev_dependencies" => false
17
+ },
18
+ "scan" => {
19
+ "sources" => ["osv", "ruby_advisory_db"],
20
+ "timeout" => 30
21
+ }
22
+ }.freeze
23
+
24
+ SEVERITY_LEVELS = %w[low medium high critical].freeze
25
+
26
+ def initialize(config_path = ".gemguard.yml")
27
+ @config_path = config_path
28
+ @config = load_config
29
+ end
30
+
31
+ def get(key)
32
+ keys = key.split(".")
33
+ value = @config
34
+
35
+ keys.each do |k|
36
+ value = value[k] if value.is_a?(Hash)
37
+ end
38
+
39
+ value
40
+ end
41
+
42
+ def set(key, value)
43
+ keys = key.split(".")
44
+ target = @config
45
+
46
+ keys[0..-2].each do |k|
47
+ target[k] ||= {}
48
+ target = target[k]
49
+ end
50
+
51
+ target[keys.last] = value
52
+ end
53
+
54
+ def save
55
+ File.write(@config_path, YAML.dump(@config))
56
+ end
57
+
58
+ def exists?
59
+ File.exist?(@config_path)
60
+ end
61
+
62
+ def lockfile_path
63
+ get("lockfile")
64
+ end
65
+
66
+ def output_format
67
+ get("format")
68
+ end
69
+
70
+ def fail_on_vulnerabilities?
71
+ get("fail_on_vulnerabilities")
72
+ end
73
+
74
+ def severity_threshold
75
+ get("severity_threshold")
76
+ end
77
+
78
+ def ignored_vulnerabilities
79
+ get("ignore_vulnerabilities") || []
80
+ end
81
+
82
+ def ignored_gems
83
+ get("ignore_gems") || []
84
+ end
85
+
86
+ def output_file
87
+ get("output_file")
88
+ end
89
+
90
+ def project_name
91
+ get("project_name") || detect_project_name
92
+ end
93
+
94
+ def sbom_format
95
+ get("sbom.format")
96
+ end
97
+
98
+ def include_dev_dependencies?
99
+ get("sbom.include_dev_dependencies")
100
+ end
101
+
102
+ def vulnerability_sources
103
+ get("scan.sources")
104
+ end
105
+
106
+ def scan_timeout
107
+ get("scan.timeout")
108
+ end
109
+
110
+ def should_ignore_vulnerability?(vulnerability_id)
111
+ ignored_vulnerabilities.include?(vulnerability_id)
112
+ end
113
+
114
+ def should_ignore_gem?(gem_name)
115
+ ignored_gems.include?(gem_name)
116
+ end
117
+
118
+ def meets_severity_threshold?(severity)
119
+ return true if severity.nil? || severity.empty?
120
+
121
+ severity_index = SEVERITY_LEVELS.index(severity.downcase)
122
+ threshold_index = SEVERITY_LEVELS.index(severity_threshold.downcase)
123
+
124
+ return true if severity_index.nil? || threshold_index.nil?
125
+
126
+ severity_index >= threshold_index
127
+ end
128
+
129
+ private
130
+
131
+ def load_config
132
+ if File.exist?(@config_path)
133
+ user_config = YAML.load_file(@config_path) || {}
134
+ deep_merge(deep_dup(DEFAULT_CONFIG), user_config)
135
+ else
136
+ deep_dup(DEFAULT_CONFIG)
137
+ end
138
+ rescue Psych::SyntaxError => e
139
+ puts "Warning: Invalid YAML in #{@config_path}: #{e.message}"
140
+ puts "Using default configuration."
141
+ deep_dup(DEFAULT_CONFIG)
142
+ end
143
+
144
+ def deep_dup(obj)
145
+ case obj
146
+ when Hash
147
+ obj.each_with_object({}) { |(key, value), hash| hash[key] = deep_dup(value) }
148
+ when Array
149
+ obj.map { |item| deep_dup(item) }
150
+ else
151
+ begin
152
+ obj.dup
153
+ rescue
154
+ obj
155
+ end
156
+ end
157
+ end
158
+
159
+ def deep_merge(hash1, hash2)
160
+ result = hash1.dup
161
+
162
+ hash2.each do |key, value|
163
+ result[key] = if result[key].is_a?(Hash) && value.is_a?(Hash)
164
+ deep_merge(result[key], value)
165
+ else
166
+ value
167
+ end
168
+ end
169
+
170
+ result
171
+ end
172
+
173
+ def detect_project_name
174
+ # Try to detect project name from various sources
175
+ if File.exist?("Gemfile")
176
+ gemfile_content = File.read("Gemfile")
177
+ if gemfile_content =~ /gem\s+['"]([^'"]+)['"]/
178
+ return $1
179
+ end
180
+ end
181
+
182
+ if File.exist?("*.gemspec")
183
+ gemspec_files = Dir.glob("*.gemspec")
184
+ unless gemspec_files.empty?
185
+ return File.basename(gemspec_files.first, ".gemspec")
186
+ end
187
+ end
188
+
189
+ # Fallback to directory name
190
+ File.basename(Dir.pwd)
191
+ end
192
+ end
193
+ end
@@ -1,3 +1,3 @@
1
1
  module GemGuard
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
data/lib/gem_guard.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "gem_guard/vulnerability_fetcher"
4
4
  require_relative "gem_guard/analyzer"
5
5
  require_relative "gem_guard/reporter"
6
6
  require_relative "gem_guard/sbom_generator"
7
+ require_relative "gem_guard/config"
7
8
  require_relative "gem_guard/cli"
8
9
 
9
10
  module GemGuard
@@ -0,0 +1,107 @@
1
+ # CircleCI configuration for GemGuard security scanning
2
+ # Copy this content to .circleci/config.yml in your repository
3
+
4
+ version: 2.1
5
+
6
+ orbs:
7
+ ruby: circleci/ruby@2.1.0
8
+
9
+ jobs:
10
+ security-scan:
11
+ docker:
12
+ - image: cimg/ruby:3.3
13
+ parameters:
14
+ ruby-version:
15
+ type: string
16
+ default: "3.3"
17
+ steps:
18
+ - checkout
19
+
20
+ - ruby/install-deps:
21
+ bundler-version: "2.4.0"
22
+
23
+ - run:
24
+ name: Install GemGuard
25
+ command: gem install gem_guard
26
+
27
+ - run:
28
+ name: Run vulnerability scan
29
+ command: |
30
+ echo "Running GemGuard security scan..."
31
+ gem_guard scan --format json --output security-report.json
32
+ gem_guard scan --format table
33
+
34
+ - run:
35
+ name: Generate SBOM
36
+ command: |
37
+ echo "Generating Software Bill of Materials..."
38
+ gem_guard sbom --format spdx --output sbom-spdx.json
39
+ gem_guard sbom --format cyclone-dx --output sbom-cyclone.json
40
+
41
+ - store_artifacts:
42
+ path: security-report.json
43
+ destination: security-reports/
44
+
45
+ - store_artifacts:
46
+ path: sbom-spdx.json
47
+ destination: sbom/
48
+
49
+ - store_artifacts:
50
+ path: sbom-cyclone.json
51
+ destination: sbom/
52
+
53
+ - run:
54
+ name: Check for vulnerabilities
55
+ command: |
56
+ if [ -f security-report.json ]; then
57
+ VULN_COUNT=$(ruby -rjson -e "puts JSON.parse(File.read('security-report.json'))['vulnerabilities']&.length || 0")
58
+ echo "Found $VULN_COUNT vulnerabilities"
59
+
60
+ if [ "$VULN_COUNT" -gt 0 ]; then
61
+ echo "⚠️ Vulnerabilities detected! Check the artifacts for details."
62
+ exit 1
63
+ else
64
+ echo "✅ No vulnerabilities found!"
65
+ fi
66
+ fi
67
+
68
+ security-scan-matrix:
69
+ docker:
70
+ - image: cimg/ruby:<< parameters.ruby-version >>
71
+ parameters:
72
+ ruby-version:
73
+ type: string
74
+ steps:
75
+ - checkout
76
+ - ruby/install-deps
77
+ - run:
78
+ name: Install GemGuard
79
+ command: gem install gem_guard
80
+ - run:
81
+ name: Security scan for Ruby << parameters.ruby-version >>
82
+ command: |
83
+ gem_guard scan --format json --output security-report-<< parameters.ruby-version >>.json
84
+ gem_guard scan
85
+ - store_artifacts:
86
+ path: security-report-<< parameters.ruby-version >>.json
87
+
88
+ workflows:
89
+ security-checks:
90
+ jobs:
91
+ - security-scan:
92
+ name: security-scan-main
93
+
94
+ security-matrix:
95
+ jobs:
96
+ - security-scan-matrix:
97
+ matrix:
98
+ parameters:
99
+ ruby-version: ["3.1", "3.2", "3.3"]
100
+ name: security-scan-ruby-<< matrix.ruby-version >>
101
+ triggers:
102
+ - schedule:
103
+ cron: "0 2 * * *" # Daily at 2 AM UTC
104
+ filters:
105
+ branches:
106
+ only:
107
+ - main
@@ -0,0 +1,85 @@
1
+ # GitHub Actions workflow for GemGuard security scanning
2
+ # Copy this file to .github/workflows/gemguard.yml in your repository
3
+
4
+ name: Security Scan with GemGuard
5
+
6
+ on:
7
+ push:
8
+ branches: [ main, develop ]
9
+ pull_request:
10
+ branches: [ main ]
11
+ schedule:
12
+ # Run daily at 2 AM UTC
13
+ - cron: '0 2 * * *'
14
+
15
+ jobs:
16
+ security-scan:
17
+ runs-on: ubuntu-latest
18
+
19
+ strategy:
20
+ matrix:
21
+ ruby-version: ['3.1', '3.2', '3.3']
22
+
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - name: Set up Ruby ${{ matrix.ruby-version }}
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true
31
+
32
+ - name: Install GemGuard
33
+ run: gem install gem_guard
34
+
35
+ - name: Run GemGuard vulnerability scan
36
+ run: |
37
+ gem_guard scan --format json --output security-report.json
38
+ gem_guard scan --format table
39
+
40
+ - name: Generate SBOM
41
+ run: |
42
+ gem_guard sbom --format spdx --output sbom-spdx.json
43
+ gem_guard sbom --format cyclone-dx --output sbom-cyclone.json
44
+
45
+ - name: Upload security artifacts
46
+ uses: actions/upload-artifact@v4
47
+ if: always()
48
+ with:
49
+ name: security-reports-ruby-${{ matrix.ruby-version }}
50
+ path: |
51
+ security-report.json
52
+ sbom-spdx.json
53
+ sbom-cyclone.json
54
+ retention-days: 30
55
+
56
+ - name: Comment PR with security report
57
+ if: github.event_name == 'pull_request'
58
+ uses: actions/github-script@v7
59
+ with:
60
+ script: |
61
+ const fs = require('fs');
62
+ try {
63
+ const report = fs.readFileSync('security-report.json', 'utf8');
64
+ const data = JSON.parse(report);
65
+
66
+ if (data.vulnerabilities && data.vulnerabilities.length > 0) {
67
+ const comment = `## 🚨 Security Vulnerabilities Found
68
+
69
+ GemGuard detected ${data.vulnerabilities.length} vulnerabilities in this PR.
70
+
71
+ Please review the security report artifact for details.
72
+
73
+ **High/Critical vulnerabilities:** ${data.high_severity_count || 0}
74
+ `;
75
+
76
+ github.rest.issues.createComment({
77
+ issue_number: context.issue.number,
78
+ owner: context.repo.owner,
79
+ repo: context.repo.repo,
80
+ body: comment
81
+ });
82
+ }
83
+ } catch (error) {
84
+ console.log('No security report found or error reading report');
85
+ }
@@ -0,0 +1,112 @@
1
+ # GitLab CI configuration for GemGuard security scanning
2
+ # Copy this content to your .gitlab-ci.yml file
3
+
4
+ stages:
5
+ - security
6
+ - report
7
+
8
+ variables:
9
+ BUNDLE_PATH: vendor/bundle
10
+ BUNDLE_JOBS: 4
11
+ BUNDLE_RETRY: 3
12
+
13
+ .ruby_template: &ruby_template
14
+ image: ruby:3.3
15
+ before_script:
16
+ - gem install bundler
17
+ - bundle install --path $BUNDLE_PATH
18
+ - gem install gem_guard
19
+ cache:
20
+ key: gems-$CI_COMMIT_REF_SLUG
21
+ paths:
22
+ - vendor/bundle/
23
+
24
+ security_scan:
25
+ <<: *ruby_template
26
+ stage: security
27
+ script:
28
+ - echo "Running GemGuard security scan..."
29
+ - gem_guard scan --format json --output security-report.json
30
+ - gem_guard scan --format table
31
+ - echo "Generating SBOM..."
32
+ - gem_guard sbom --format spdx --output sbom-spdx.json
33
+ - gem_guard sbom --format cyclone-dx --output sbom-cyclone.json
34
+ artifacts:
35
+ reports:
36
+ # GitLab security report format (if you want to convert)
37
+ dependency_scanning: security-report.json
38
+ paths:
39
+ - security-report.json
40
+ - sbom-spdx.json
41
+ - sbom-cyclone.json
42
+ expire_in: 30 days
43
+ when: always
44
+ allow_failure: false
45
+ only:
46
+ - main
47
+ - develop
48
+ - merge_requests
49
+
50
+ security_scan_ruby_3_1:
51
+ <<: *ruby_template
52
+ image: ruby:3.1
53
+ stage: security
54
+ script:
55
+ - gem_guard scan --format json --output security-report-ruby31.json
56
+ - gem_guard scan
57
+ artifacts:
58
+ paths:
59
+ - security-report-ruby31.json
60
+ expire_in: 7 days
61
+ only:
62
+ - schedules
63
+
64
+ security_scan_ruby_3_2:
65
+ <<: *ruby_template
66
+ image: ruby:3.2
67
+ stage: security
68
+ script:
69
+ - gem_guard scan --format json --output security-report-ruby32.json
70
+ - gem_guard scan
71
+ artifacts:
72
+ paths:
73
+ - security-report-ruby32.json
74
+ expire_in: 7 days
75
+ only:
76
+ - schedules
77
+
78
+ # Optional: Create a summary report
79
+ security_report:
80
+ stage: report
81
+ image: alpine:latest
82
+ before_script:
83
+ - apk add --no-cache jq
84
+ script:
85
+ - |
86
+ echo "## Security Scan Summary" > security-summary.md
87
+ echo "" >> security-summary.md
88
+ if [ -f security-report.json ]; then
89
+ VULN_COUNT=$(jq '.vulnerabilities | length' security-report.json)
90
+ HIGH_COUNT=$(jq '.high_severity_count // 0' security-report.json)
91
+ echo "- **Total vulnerabilities found:** $VULN_COUNT" >> security-summary.md
92
+ echo "- **High/Critical severity:** $HIGH_COUNT" >> security-summary.md
93
+ echo "" >> security-summary.md
94
+
95
+ if [ "$VULN_COUNT" -gt 0 ]; then
96
+ echo "⚠️ **Action required:** Please review and address the identified vulnerabilities." >> security-summary.md
97
+ else
98
+ echo "✅ **No vulnerabilities found!**" >> security-summary.md
99
+ fi
100
+ else
101
+ echo "❌ **Error:** Security report not found." >> security-summary.md
102
+ fi
103
+ cat security-summary.md
104
+ artifacts:
105
+ paths:
106
+ - security-summary.md
107
+ expire_in: 30 days
108
+ dependencies:
109
+ - security_scan
110
+ only:
111
+ - main
112
+ - develop
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_guard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wilbur Suero
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-09 00:00:00.000000000 Z
11
+ date: 2025-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -101,12 +101,16 @@ files:
101
101
  - lib/gem_guard.rb
102
102
  - lib/gem_guard/analyzer.rb
103
103
  - lib/gem_guard/cli.rb
104
+ - lib/gem_guard/config.rb
104
105
  - lib/gem_guard/parser.rb
105
106
  - lib/gem_guard/reporter.rb
106
107
  - lib/gem_guard/sbom_generator.rb
107
108
  - lib/gem_guard/version.rb
108
109
  - lib/gem_guard/vulnerability_fetcher.rb
109
110
  - plan.md
111
+ - templates/circleci-config.yml
112
+ - templates/github-actions.yml
113
+ - templates/gitlab-ci.yml
110
114
  homepage: https://github.com/wilburhimself/gem_guard
111
115
  licenses:
112
116
  - MIT