omamori 0.1.0

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.
@@ -0,0 +1,104 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Omamori Security Report</title>
5
+ <style>
6
+ body { font-family: sans-serif; line-height: 1.6; margin: 20px; }
7
+ h1 { color: #333; }
8
+ .risk { border: 1px solid #ccc; padding: 15px; margin-bottom: 15px; border-radius: 5px; }
9
+ .risk h2 { margin-top: 0; }
10
+ .severity-critical { color: red; font-weight: bold; }
11
+ .severity-high { color: red; font-weight: bold; }
12
+ .severity-medium { color: orange; }
13
+ .severity-low { color: blue; }
14
+ .severity-info { color: green; }
15
+ pre { background-color: #f4f4f4; padding: 10px; overflow-x: auto; }
16
+ </style>
17
+ </head>
18
+ <body>
19
+ <h1>Omamori Security Report</h1>
20
+
21
+ <h2>AI Analysis Results</h2>
22
+ <% if @ai_risks.empty? %>
23
+ <p>No AI-detected security risks.</p>
24
+ <% else %>
25
+ <% @ai_risks.each do |risk| %>
26
+ <div class="risk">
27
+ <h3 class="severity-<%= risk['severity'].downcase %>"><%= risk['type'] %></h3>
28
+ <p><strong>Severity:</strong> <span class="severity-<%= risk['severity'].downcase %>"><%= risk['severity'] %></span></p>
29
+ <p><strong>Location:</strong> <%= risk['location'] %></p>
30
+ <p><strong>Details:</strong> <%= risk['details'] %></p>
31
+ <p><strong>Code Snippet:</strong></p>
32
+ <pre><%= risk['code_snippet'] %></pre>
33
+ </div>
34
+ <% end %>
35
+ <% end %>
36
+
37
+ <h2>Static Analysis Results</h2>
38
+ <% if @static_results.empty? %>
39
+ <p>No static analysis results available.</p>
40
+ <% else %>
41
+ <h3>Brakeman</h3>
42
+ <% brakeman_result = @static_results['brakeman'] %>
43
+ <% if brakeman_result && brakeman_result['warnings'] && !brakeman_result['warnings'].empty? %>
44
+ <% brakeman_result['warnings'].each do |warning| %>
45
+ <div class="risk">
46
+ <h4 class="severity-<%= warning['confidence'].downcase %>">Brakeman Warning: <%= warning['warning_type'] %></h4>
47
+ <p><strong>Confidence:</strong> <span class="severity-<%= warning['confidence'].downcase %>"><%= warning['confidence'] %></span></p>
48
+ <p><strong>Message:</strong> <%= warning['message'] %></p>
49
+ <p><strong>File:</strong> <%= warning['file'] %></p>
50
+ <p><strong>Line:</strong> <%= warning['line'] %></p>
51
+ <p><strong>Code:</strong> <%= warning['code'] %></p>
52
+ <p><strong>Link:</strong> <a href="<%= warning['link'] %>" target="_blank"><%= warning['link'] %></a></p>
53
+ </div>
54
+ <% end %>
55
+ <% else %>
56
+ <p>No Brakeman warnings found.</p>
57
+ <% end %>
58
+
59
+ <h3>Bundler-Audit</h3>
60
+ <% bundler_audit_result = @static_results['bundler_audit'] %>
61
+ <% if bundler_audit_result && bundler_audit_result['scan'] %>
62
+ <% scan_results = bundler_audit_result['scan'] %>
63
+ <% if scan_results['vulnerabilities'] && !scan_results['vulnerabilities'].empty? %>
64
+ <h4>Vulnerabilities</h4>
65
+ <ul>
66
+ <% scan_results['vulnerabilities'].each do |vulnerability| %>
67
+ <li>
68
+ <strong>ID:</strong> <span class="severity-<%= vulnerability['criticality'].downcase %>"><%= vulnerability['id'] %></span><br>
69
+ <strong>Gem:</strong> <%= vulnerability['gem'] %><br>
70
+ <strong>Title:</strong> <%= vulnerability['title'] %><br>
71
+ <strong>URL:</strong> <a href="<%= vulnerability['url'] %>" target="_blank"><%= vulnerability['url'] %></a><br>
72
+ <strong>Criticality:</strong> <span class="severity-<%= vulnerability['criticality'].downcase %>"><%= vulnerability['criticality'] %></span><br>
73
+ <strong>Description:</strong> <%= vulnerability['description'] %><br>
74
+ <strong>Introduced In:</strong> <%= vulnerability['introduced_in'] %><br>
75
+ <strong>Patched Versions:</strong> <%= vulnerability['patched_versions'].join(', ') %><br>
76
+ <strong>Advisory Date:</strong> <%= vulnerability['advisory_date'] %>
77
+ </li>
78
+ <% end %>
79
+ </ul>
80
+ <% else %>
81
+ <p>No vulnerabilities found.</p>
82
+ <% end %>
83
+
84
+ <% if scan_results['unpatched_gems'] && !scan_results['unpatched_gems'].empty? %>
85
+ <h4>Unpatched Gems</h4>
86
+ <ul>
87
+ <% scan_results['unpatched_gems'].each do |gem| %>
88
+ <li>
89
+ <strong>Name:</strong> <%= gem['name'] %><br>
90
+ <strong>Version:</strong> <%= gem['version'] %>
91
+ </li>
92
+ <% end %>
93
+ </ul>
94
+ <% else %>
95
+ <p>No unpatched gems found.</p>
96
+ <% end %>
97
+
98
+ <% else %>
99
+ <p>Bundler-Audit results not available or in unexpected format.</p>
100
+ <% end %>
101
+ <% end %>
102
+
103
+ </body>
104
+ </html>
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omamori
4
+ module StaticAnalysers
5
+ class BrakemanRunner
6
+ def initialize(options = {})
7
+ @options = options
8
+ end
9
+
10
+ def run
11
+ puts "Running Brakeman..."
12
+ # Determine Brakeman command based on options
13
+ # Use --force to run scan even if it's not a Rails application
14
+ # Use -f json for JSON output
15
+ # Include options passed during initialization
16
+ # Convert options hash to command line arguments string
17
+ options_string = @options.map do |key, value|
18
+ if value.is_a?(TrueClass)
19
+ key.to_s
20
+ elsif value.is_a?(FalseClass)
21
+ "" # Don't include false flags
22
+ else
23
+ "#{key} #{value}"
24
+ end
25
+ end.join(" ").strip
26
+
27
+ brakeman_command = "brakeman -f json . --force #{options_string}".strip # strip again in case options_string is empty
28
+
29
+ begin
30
+ # Execute the Brakeman command and capture output
31
+ brakeman_output = `#{brakeman_command}`
32
+
33
+ # Parse the JSON output
34
+ # Note: JSON.parse is called here. If the test expects it to be called only once,
35
+ # the test setup might be causing it to be called multiple times or the mock is misconfigured.
36
+ JSON.parse(brakeman_output)
37
+ rescue Errno::ENOENT
38
+ puts "Error: Brakeman command not found. Is Brakeman installed?"
39
+ nil
40
+ rescue JSON::ParserError
41
+ puts "Error: Failed to parse Brakeman JSON output."
42
+ puts "Raw output:\n#{brakeman_output}"
43
+ nil
44
+ rescue => e
45
+ puts "An error occurred during Brakeman execution: #{e.message}"
46
+ nil
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json' # Bundler-Audit can output JSON
4
+
5
+ module Omamori
6
+ module StaticAnalysers
7
+ class BundlerAuditRunner
8
+ def initialize(options = {})
9
+ @options = options
10
+ end
11
+
12
+ def run
13
+ # TODO: Determine Bundler-Audit command based on options
14
+ # Example: bundle audit --format json
15
+ # Include options passed during initialization
16
+ # Build options string from the options hash
17
+ options_string = @options.map { |key, value| "--#{key.to_s.gsub('_', '-')}" + (value == true ? "" : " #{value}") }.join(" ")
18
+ bundler_audit_command = "bundle audit --format json#{options_string.empty? ? '' : " #{options_string}"}"
19
+
20
+ begin
21
+ # Execute the Bundler-Audit command and capture output
22
+ # Note: bundle audit exits with non-zero status if vulnerabilities are found
23
+ # We need to capture stdout and stderr regardless of exit status
24
+ bundler_audit_output = `#{bundler_audit_command} 2>&1`
25
+
26
+ # Parse the JSON output
27
+ # Bundler-Audit JSON output structure might vary, need to confirm
28
+ # Assuming it returns a JSON object with vulnerability information
29
+ parsed_output = JSON.parse(bundler_audit_output)
30
+ # Validate the parsed output structure
31
+ if parsed_output.is_a?(Hash) && parsed_output.key?('results')
32
+ # Return the entire parsed output hash
33
+ parsed_output
34
+ else
35
+ puts "Error: Unexpected Bundler-Audit JSON output structure."
36
+ puts "Raw output:\n#{bundler_audit_output}"
37
+ nil # Return nil if the structure is unexpected
38
+ end
39
+ rescue Errno::ENOENT
40
+ puts "Error: bundle command not found. Is Bundler installed?"
41
+ nil
42
+ rescue JSON::ParserError
43
+ puts "Error: Failed to parse Bundler-Audit JSON output."
44
+ puts "Raw output:\n#{bundler_audit_output}"
45
+ nil
46
+ rescue => e
47
+ puts "An error occurred during Bundler-Audit execution: #{e.message}"
48
+ nil
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omamori
4
+ VERSION = "0.1.0"
5
+ end
data/lib/omamori.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "omamori/version"
4
+ require_relative "omamori/core_runner"
5
+ require_relative "omamori/ai_analysis_engine/gemini_client"
6
+ require_relative "omamori/ai_analysis_engine/prompt_manager"
7
+ require_relative "omamori/ai_analysis_engine/diff_splitter"
8
+ require_relative "omamori/report_generator/console_formatter"
9
+ require_relative "omamori/report_generator/html_formatter"
10
+ require_relative "omamori/report_generator/json_formatter"
11
+ require_relative "omamori/static_analysers/brakeman_runner"
12
+ require_relative "omamori/static_analysers/bundler_audit_runner"
13
+
14
+ module Omamori
15
+ # Your code goes here...
16
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omamori
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - rira100000000
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-04-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby-gemini-api
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.1.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.1.0
111
+ description: omamori scans Ruby code and diffs using AI (Google Gemini) to detect
112
+ security vulnerabilities often missed by traditional tools.
113
+ email:
114
+ - 101010hayakawa@gmail
115
+ executables:
116
+ - omamori
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - LICENSE
123
+ - README.md
124
+ - README_ja.md
125
+ - demo/ai_analysis_vulnerability.rb
126
+ - demo/csrf_vulnerability.rb
127
+ - demo/eval_vulnerability.rb
128
+ - demo/idor_vulnerability.rb
129
+ - demo/insecure_cookie_vulnerability.rb
130
+ - demo/open_redirect_vulnerability.rb
131
+ - demo/static_analysis_vulnerability.rb
132
+ - demo/xss_vulnerability.rb
133
+ - exe/omamori
134
+ - lib/omamori.rb
135
+ - lib/omamori/ai_analysis_engine/diff_splitter.rb
136
+ - lib/omamori/ai_analysis_engine/gemini_client.rb
137
+ - lib/omamori/ai_analysis_engine/prompt_manager.rb
138
+ - lib/omamori/config.rb
139
+ - lib/omamori/core_runner.rb
140
+ - lib/omamori/report_generator/console_formatter.rb
141
+ - lib/omamori/report_generator/html_formatter.rb
142
+ - lib/omamori/report_generator/json_formatter.rb
143
+ - lib/omamori/report_generator/report_template.erb
144
+ - lib/omamori/static_analysers/brakeman_runner.rb
145
+ - lib/omamori/static_analysers/bundler_audit_runner.rb
146
+ - lib/omamori/version.rb
147
+ homepage: https://github.com/rira100000000/omamori
148
+ licenses: []
149
+ metadata:
150
+ homepage_uri: https://github.com/rira100000000/omamori
151
+ source_code_uri: https://github.com/rira100000000/omamori
152
+ changelog_uri: https://github.com/rira100000000/omamori/blob/main/CHANGELOG.md
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.5.11
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: AI-powered security vulnerability scanner for Ruby projects.
172
+ test_files: []