omamori 0.1.1 → 0.1.4

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: 047332a1b52e201377fafce4a1556aaff4653c6f8982914d35486b0ae6413f48
4
- data.tar.gz: 2ae4023aec70fcd7242c035787787cf5ab0803bcb242ec93d347a8eb98daff70
3
+ metadata.gz: bafa258377208d15c678d88752804be6963159d28b83c13958de28bdd8bf8fa7
4
+ data.tar.gz: 9739ae26075e9e5c0f2f87eafd68f2ed6cce0baee719a4c31c1042e8b1c8abf9
5
5
  SHA512:
6
- metadata.gz: 125dad0b11d11a647b943e4761049e34176f7b628ebb28487f4e30221aed3b967cedaf7f23f3ef547f3f5096c1a9bb38898213fa5e8cd97c641e5ecd26131df7
7
- data.tar.gz: a972855f407359eaafee5e524e2b20d7ae303afc3dd2d8b972d2e385c45ed91ee5d84aa78007edd37c746d9e285c9958ebc205bb5008f575839632be31de07fa
6
+ metadata.gz: 373c41e264bc7548b3b4f37a526ed98fcefdd6a51fc6eaa8571b18d7688e131b4852c7e4ce839c7cdd43e540c3bf83b7466a1a66c29cea7c5d6e03dcd59f5cac
7
+ data.tar.gz: 102078caed02ab830885759ddf21bc8430b15c6a829a5f4ed7c1fcca99360ac707bb938ab19a8f2f9a5ed8ad2ccd86427acfaecc1da6d55a48c27338ae753454
data/Gemfile CHANGED
@@ -4,6 +4,3 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in omamori.gemspec
6
6
  gemspec
7
- gem "brakeman", "~> 7.0"
8
-
9
- gem "bundler-audit", "~> 0.9.2"
data/Gemfile.lock CHANGED
@@ -1,9 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- omamori (0.1.0)
4
+ omamori (0.1.4)
5
+ brakeman (~> 7.0)
6
+ bundler-audit (~> 0.9.2)
5
7
  colorize (~> 0.8)
6
8
  dotenv (~> 2.0)
9
+ ruby-gemini-api (~> 0.1.1)
7
10
 
8
11
  GEM
9
12
  remote: https://rubygems.org/
@@ -15,7 +18,7 @@ GEM
15
18
  bundler (>= 1.2.0, < 3)
16
19
  thor (~> 1.0)
17
20
  colorize (0.8.1)
18
- diff-lcs (1.6.1)
21
+ diff-lcs (1.6.2)
19
22
  dotenv (2.8.1)
20
23
  faraday (2.13.1)
21
24
  faraday-net_http (>= 2.0, < 3.5)
@@ -25,8 +28,8 @@ GEM
25
28
  multipart-post (~> 2.0)
26
29
  faraday-net_http (3.4.0)
27
30
  net-http (>= 0.5.0)
28
- json (2.11.3)
29
- language_server-protocol (3.17.0.4)
31
+ json (2.12.0)
32
+ language_server-protocol (3.17.0.5)
30
33
  lint_roller (1.1.0)
31
34
  logger (1.7.0)
32
35
  multipart-post (2.4.1)
@@ -47,14 +50,14 @@ GEM
47
50
  rspec-mocks (~> 3.13.0)
48
51
  rspec-core (3.13.3)
49
52
  rspec-support (~> 3.13.0)
50
- rspec-expectations (3.13.3)
53
+ rspec-expectations (3.13.4)
51
54
  diff-lcs (>= 1.2.0, < 2.0)
52
55
  rspec-support (~> 3.13.0)
53
- rspec-mocks (3.13.2)
56
+ rspec-mocks (3.13.4)
54
57
  diff-lcs (>= 1.2.0, < 2.0)
55
58
  rspec-support (~> 3.13.0)
56
- rspec-support (3.13.2)
57
- rubocop (1.75.3)
59
+ rspec-support (3.13.3)
60
+ rubocop (1.75.6)
58
61
  json (~> 2.3)
59
62
  language_server-protocol (~> 3.17.0.2)
60
63
  lint_roller (~> 1.1.0)
@@ -68,7 +71,7 @@ GEM
68
71
  rubocop-ast (1.44.1)
69
72
  parser (>= 3.3.7.2)
70
73
  prism (~> 1.4)
71
- ruby-gemini-api (0.1.0)
74
+ ruby-gemini-api (0.1.1)
72
75
  faraday (~> 2.0)
73
76
  faraday-multipart (~> 1.0)
74
77
  json (~> 2.0)
@@ -84,14 +87,11 @@ PLATFORMS
84
87
  x86_64-linux
85
88
 
86
89
  DEPENDENCIES
87
- brakeman (~> 7.0)
88
90
  bundler (~> 2.0)
89
- bundler-audit (~> 0.9.2)
90
91
  omamori!
91
92
  rake (~> 13.0)
92
93
  rspec (~> 3.0)
93
94
  rubocop (~> 1.0)
94
- ruby-gemini-api (~> 0.1.0)
95
95
 
96
96
  BUNDLED WITH
97
97
  2.5.17
data/README.md CHANGED
@@ -15,11 +15,12 @@ Running the analysis multiple times may help reduce false negatives.
15
15
 
16
16
  ## Features
17
17
 
18
- - Scan staged changes (`git diff --staged`) or the entire codebase for security risks.
18
+ - Scan staged changes (`git diff --staged`), the entire codebase, or specified files and directories for security risks.
19
19
  - Integrates with static analysis tools like Brakeman and Bundler-Audit.
20
20
  - Utilizes the Gemini API for advanced code analysis to detect vulnerabilities.
21
21
  - Supports multiple report formats (console, HTML, JSON).
22
22
  - Configurable via a `.omamorirc` file.
23
+ - Exclusion of files and directories via a `.omamoriignore` file (except in `diff` mode).
23
24
 
24
25
  ## Installation
25
26
 
@@ -51,7 +52,7 @@ To generate an initial configuration file (`.omamorirc`), run:
51
52
  omamori init
52
53
  ```
53
54
 
54
- Edit the generated `.omamorirc` file to configure your Gemini API key, preferred model, checks to perform, and other settings.
55
+ Edit the generated `.omamorirc` and `.omamoriignore` files to configure your Gemini API key, preferred model, checks to perform, and files/directories to exclude from scanning, and other settings.
55
56
 
56
57
  ### Scanning
57
58
 
@@ -66,6 +67,7 @@ Scan the entire codebase:
66
67
  ```bash
67
68
  omamori scan --all
68
69
  ```
70
+ This mode respects the `.omamoriignore` file.
69
71
 
70
72
  Specify output format (console, html, json):
71
73
 
@@ -74,6 +76,22 @@ bundle exec omamori scan --format html
74
76
  bundle exec omamori scan --all --format json
75
77
  ```
76
78
 
79
+ ### Scan Specific Files/Directories
80
+
81
+ You can specify particular files or directories to scan:
82
+
83
+ ```bash
84
+ omamori scan <file_path1> <file_path2> ... <directory_path1> ...
85
+ ```
86
+
87
+ Example:
88
+
89
+ ```bash
90
+ omamori scan app/controllers/users_controller.rb app/models/user.rb config/routes.rb lib/
91
+ ```
92
+
93
+ This mode respects the `.omamoriignore` file.
94
+
77
95
  ### AI Analysis Only
78
96
 
79
97
  To perform only AI analysis without running static analysis tools, use the `--ai` option:
@@ -96,7 +114,7 @@ Here's a detailed breakdown of the configuration options:
96
114
  # You can also set this via the GEMINI_API_KEY environment variable
97
115
  api_key: YOUR_GEMINI_API_KEY # Replace with your actual API key
98
116
 
99
- # Gemini Model to use (optional, default: gemini-1.5-pro-latest)
117
+ # Gemini Model to use (optional, default: gemini-2.5-flash-preview-04-17)
100
118
  model: gemini-2.5-flash-preview-04-17
101
119
 
102
120
  # Security checks to enable (optional, default: all implemented checks)
@@ -128,7 +146,7 @@ model: gemini-2.5-flash-preview-04-17
128
146
  ```
129
147
 
130
148
  * `api_key`: Your API key for accessing the Gemini API. Can also be set via the `GEMINI_API_KEY` environment variable.
131
- * `model`: The Gemini model to use for AI analysis. Defaults to `gemini-1.5-pro-latest`.
149
+ * `model`: The Gemini model to use for AI analysis. Defaults to `gemini-2.5-flash-preview-04-17`.
132
150
  * `checks`: Configure which types of security checks to enable. By default, all implemented checks are enabled. You can selectively enable/disable checks here (e.g., `xss: true`, `csrf: false`).
133
151
  * `prompt_templates`: Define custom prompt templates for AI analysis.
134
152
  * `report`: Configure report output settings.
@@ -139,6 +157,16 @@ model: gemini-2.5-flash-preview-04-17
139
157
  * `bundler_audit`: Additional command-line options for Bundler-Audit.
140
158
  * `language`: Language setting for the details provided in AI analysis reports. Defaults to English (`en`).
141
159
 
160
+ ## .omamoriignore File
161
+
162
+ The `.omamoriignore` file allows you to exclude specific files and directories from the scan target. Its behavior is similar to a `.gitignore` file, but with the following considerations:
163
+
164
+ * **Effective Modes:** It is only effective in `--all` mode or when scanning specified files/directories.
165
+ * **Ineffective Mode:** In `diff` mode (i.e., `omamori scan` without arguments), the `.omamoriignore` file is ignored. This is because `diff` mode only targets changes retrieved by `git diff`.
166
+ * **Format:** Each line specifies one pattern. Lines starting with `#` are treated as comments. It is recommended to append a `/` to directory patterns (e.g., `vendor/`). Patterns are evaluated using simple prefix matching (e.g., `config/initializers` matches `config/initializers/devise.rb`). Wildcards (`*`) are not currently supported.
167
+
168
+ When you run the `omamori init` command, a `.omamoriignore` file pre-filled with patterns for common files and directories to ignore in a Rails project will be generated. You can edit this file as needed.
169
+
142
170
  ## Demo Files
143
171
 
144
172
  The `demo` directory contains example files with known vulnerabilities that can be used to demonstrate Omamori's capabilities.
data/README_ja.md CHANGED
@@ -13,11 +13,12 @@ AI解析は静的解析で診断できない脆弱性を発見することがで
13
13
 
14
14
  ## 特徴
15
15
 
16
- - ステージされた変更(`git diff --staged`)またはコードベース全体をスキャンしてセキュリティリスクを検出
16
+ - ステージされた変更(`git diff --staged`)、コードベース全体、または指定されたファイルやディレクトリをスキャンしてセキュリティリスクを検出
17
17
  - BrakemanやBundler-Auditなどの静的解析ツールと連携
18
18
  - Gemini APIを活用し、AIによる高度なコード脆弱性検出
19
19
  - 複数のレポート形式に対応(コンソール、HTML、JSON)
20
20
  - `.omamorirc`ファイルによる柔軟な設定が可能
21
+ - `.omamoriignore`ファイルによるスキャン対象からの除外機能(`diff`モードを除く)
21
22
 
22
23
  ## インストール
23
24
 
@@ -49,7 +50,7 @@ gem install omamori
49
50
  omamori init
50
51
  ```
51
52
 
52
- 生成された`.omamorirc`ファイルを編集して、Gemini APIキー、使用するモデル、実行するチェック項目などを設定します。
53
+ 生成された`.omamorirc`ファイルと`.omamoriignore`ファイルを編集して、Gemini APIキー、使用するモデル、実行するチェック項目、スキャン対象から除外するファイル/ディレクトリなどを設定します。
53
54
 
54
55
  ### スキャン
55
56
 
@@ -64,6 +65,7 @@ omamori scan
64
65
  ```bash
65
66
  omamori scan --all
66
67
  ```
68
+ このモードでは`.omamoriignore`ファイルが有効になります。
67
69
 
68
70
  出力形式を指定(コンソール、HTML、JSON):
69
71
 
@@ -72,6 +74,22 @@ bundle exec omamori scan --format html
72
74
  bundle exec omamori scan --all --format json
73
75
  ```
74
76
 
77
+ ### ファイル/ディレクトリ指定スキャン
78
+
79
+ 特定のファイルやディレクトリを指定してスキャンを実行します。
80
+
81
+ ```bash
82
+ omamori scan <ファイルパス1> <ファイルパス2> ... <ディレクトリパス1> ...
83
+ ```
84
+
85
+ 例:
86
+
87
+ ```bash
88
+ omamori scan app/controllers/users_controller.rb app/models/user.rb config/routes.rb lib/
89
+ ```
90
+
91
+ このモードでは`.omamoriignore`ファイルが有効になります。
92
+
75
93
  ### AI解析のみ実施
76
94
 
77
95
  静的解析ツールを使わず、AI解析のみを実行するには、`--ai`オプションを使用します:
@@ -94,7 +112,7 @@ omamori scan --ai
94
112
  # 環境変数GEMINI_API_KEYで設定することも可能
95
113
  api_key: YOUR_GEMINI_API_KEY # 実際のAPIキーに置き換えてください
96
114
 
97
- # 使用するGeminiモデル(任意、デフォルト: gemini-1.5-pro-latest
115
+ # 使用するGeminiモデル(任意、デフォルト: gemini-2.5-flash-preview-04-17
98
116
  model: gemini-2.5-flash-preview-04-17
99
117
 
100
118
  # 有効化するセキュリティチェック(任意、デフォルトは全チェック)
@@ -126,7 +144,7 @@ model: gemini-2.5-flash-preview-04-17
126
144
  ```
127
145
 
128
146
  - `api_key`: Gemini APIへのアクセスキー。環境変数`GEMINI_API_KEY`でも設定可能。
129
- - `model`: AI解析に使用するGeminiモデル。デフォルトは`gemini-1.5-pro-latest`。
147
+ - `model`: AI解析に使用するGeminiモデル。デフォルトは`gemini-2.5-flash-preview-04-17`。
130
148
  - `checks`: 実行するセキュリティチェックの設定。特定のチェックを有効/無効にできます(例:`xss: true`, `csrf: false`)。
131
149
  - `prompt_templates`: AI解析用のカスタムプロンプトテンプレートを設定。
132
150
  - `report`: レポート出力に関する設定。
@@ -135,6 +153,16 @@ model: gemini-2.5-flash-preview-04-17
135
153
  - `static_analysers`: 静的解析ツール(Brakeman、Bundler-Auditなど)の追加オプション設定。
136
154
  - `language`: AI解析結果の詳細説明文の言語設定。デフォルトは英語(`en`)。
137
155
 
156
+ ## .omamoriignore ファイル
157
+
158
+ `.omamoriignore`ファイルを使用すると、特定のファイルやディレクトリをスキャン対象から除外できます。これは`.gitignore`ファイルと似たような働きをしますが、以下の点に注意してください。
159
+
160
+ * **有効なモード:** `--all` モード、またはファイル/ディレクトリを指定してスキャンする場合にのみ有効です。
161
+ * **無効なモード:** `diff` モード(引数なしの `omamori scan`)では、`.omamoriignore` ファイルは無視されます。これは、`git diff` で取得された変更点のみを対象とするためです。
162
+ * **書式:** 1行に1つのパターンを記述します。`#` で始まる行はコメントとして扱われます。ディレクトリを指定する場合は、末尾に `/` を付けることを推奨します (例: `vendor/`)。単純な前方一致で評価されます。 (例: `config/initializers` は `config/initializers/devise.rb` にマッチします)ワイルドカード (`*`) は現時点ではサポートされていません。
163
+
164
+ `omamori init` コマンドを実行すると、一般的なRailsプロジェクトで無視すべきファイルやディレクトリのパターンが記述された`.omamoriignore`ファイルが生成されます。必要に応じてこのファイルを編集してください。
165
+
138
166
  ## デモファイル
139
167
 
140
168
  `demo`ディレクトリには、Omamoriの機能をデモンストレーションするための既知の脆弱性を含むサンプルファイルが置かれています。
@@ -1,12 +1,8 @@
1
- # frozen_string_literal: true
1
+ # lib/omamori/ai_analysis_engine/diff_splitter.rb
2
2
 
3
3
  module Omamori
4
4
  module AIAnalysisEngine
5
5
  class DiffSplitter
6
- # TODO: Determine appropriate chunk size based on token limits
7
- # Gemini 1.5 Pro has a large context window (1 million tokens),
8
- # but splitting might still be necessary for very large inputs
9
- # or to manage cost/latency.
10
6
  DEFAULT_CHUNK_SIZE = 8000 # Characters as a proxy for tokens
11
7
 
12
8
  def initialize(chunk_size: DEFAULT_CHUNK_SIZE)
@@ -17,8 +13,8 @@ module Omamori
17
13
  chunks = []
18
14
  current_chunk = ""
19
15
  content.each_line do |line|
20
- if (current_chunk.length + line.length) > @chunk_size
21
- chunks << current_chunk unless current_chunk.empty?
16
+ if (current_chunk.length + line.length) > @chunk_size && !current_chunk.empty?
17
+ chunks << current_chunk
22
18
  current_chunk = line
23
19
  else
24
20
  current_chunk += line
@@ -28,30 +24,29 @@ module Omamori
28
24
  chunks
29
25
  end
30
26
 
31
- def process_in_chunks(content, gemini_client, json_schema, prompt_manager, risks_to_check, model: "gemini-1.5-pro-latest")
27
+ # Updated to accept file_path keyword argument
28
+ def process_in_chunks(content, gemini_client, json_schema, prompt_manager, risks_to_check, model: "gemini-2.5-flash-preview-04-17", file_path: nil)
32
29
  all_results = []
33
30
  chunks = split(content)
34
31
 
35
- puts "Splitting content into #{chunks.size} chunks..."
32
+ puts "[DEBUG Omamori DiffSplitter] Splitting content into #{chunks.size} chunks for file: #{file_path || 'N/A'}"
36
33
 
37
34
  chunks.each_with_index do |chunk, index|
38
- puts "Processing chunk #{index + 1}/#{chunks.size}..."
39
- prompt = prompt_manager.build_prompt(chunk, risks_to_check, json_schema)
40
- result = gemini_client.analyze(prompt, json_schema, model: model)
35
+ puts "[DEBUG Omamori DiffSplitter] Processing chunk #{index + 1}/#{chunks.size} for file: #{file_path || 'N/A'}"
36
+ # Pass file_path (potentially modified for chunks) to build_prompt
37
+ chunk_file_path_info = if file_path
38
+ chunks.size > 1 ? "#{file_path} (chunk #{index + 1}/#{chunks.size})" : file_path
39
+ end
40
+ prompt = prompt_manager.build_prompt(chunk, risks_to_check, json_schema, file_path: chunk_file_path_info)
41
+ result = gemini_client.analyze(prompt, json_schema, model: model) # This call to analyze is correct
41
42
  all_results << result
42
- # TODO: Handle potential rate limits or errors between chunks
43
43
  end
44
-
45
- # TODO: Combine results from all chunks
46
44
  combine_results(all_results)
47
45
  end
48
46
 
49
47
  private
50
48
 
51
49
  def combine_results(results)
52
- # This is a placeholder. Combining results from multiple AI responses
53
- # requires careful consideration of overlapping findings, context, etc.
54
- # For now, just flatten the list of security risks.
55
50
  combined_risks = results.flat_map do |result|
56
51
  result && result["security_risks"] ? result["security_risks"] : []
57
52
  end
@@ -59,4 +54,4 @@ module Omamori
59
54
  end
60
55
  end
61
56
  end
62
- end
57
+ end
@@ -10,15 +10,16 @@ module Omamori
10
10
  @client = nil # Initialize client later
11
11
  end
12
12
 
13
- def analyze(prompt, json_schema, model: "gemini-1.5-pro-latest")
13
+ def analyze(prompt, json_schema, model: "gemini-2.5-flash-preview-04-17")
14
14
  # Ensure the client is initialized
15
15
  client
16
16
 
17
17
  begin
18
- response = @client.generate_content(
18
+ response = client.generate_content(
19
19
  prompt,
20
20
  model: model,
21
- response_schema: json_schema # Use response_schema for Structured Output
21
+ response_schema: json_schema, # Use response_schema for Structured Output
22
+ temperature: 0.0
22
23
  )
23
24
 
24
25
  # Debug: Inspect the response object
@@ -1,60 +1,93 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Omamori
4
2
  module AIAnalysisEngine
5
3
  class PromptManager
6
4
  # TODO: Load prompt templates from config file
7
5
  DEFAULT_PROMPT_TEMPLATE = <<~TEXT
8
- You are a security expert specializing in Ruby. Analyze the following code and detect any potential security risks.
6
+ You are a security expert specializing in Ruby. Analyze the following code and detect any potential security risks. Think step by step.
9
7
  Focus particularly on identifying the following types of vulnerabilities: %{risk_list}
10
8
  Report any detected risks in the format specified by the following JSON Schema:
11
9
  %{json_schema}
12
10
  If no risks are found, output an empty list for the "security_risks" array.
13
11
  Please provide your response in %{language}.
12
+ #{"File context (if available): %{file_path}" if ENV['OMAMORI_DEBUG_PROMPT']}
14
13
 
15
14
  【Code to Analyze】:
16
15
  %{code_content}
17
16
  TEXT
18
17
 
18
+ # dangerous_eval の説明、脆弱なRubyコード例、検出ステップ(導入文付き)を定義する文字列
19
+ dangerous_eval_prompt = <<~PROMPT
20
+ Dangerous Code Execution (eval, exec): Dynamic code execution using untrusted input, allowing arbitrary code injection.
21
+
22
+ **Vulnerable Ruby Code Examples:**
23
+ ```ruby
24
+ # Direct eval of user input (e.g., from HTTP parameters like params[:user_code])
25
+ result = eval(params[:user_code])
26
+
27
+ # User input embedded in evaluated string (String interpolation)
28
+ log_message = "User action: \#{params[:action]}"
29
+ # Even if log_message seems harmless, injecting code like "'); malicious_code; # " might be possible
30
+ eval("log('\#{log_message}')") # Note: Interpolation inside eval string needs care with escaping
31
+
32
+ # OS Command injection via system() or backticks (`) using user input
33
+ # Assumes params[:directory] or params[:filename] comes directly from user input
34
+ output = `ls \#{params[:directory]}` # User input determines command executed
35
+ system("process_file.sh \#{params[:filename]}") # User input determines command argument
36
+
37
+ # Dynamic method invocation using send() or public_send() with user-controlled method names or arguments
38
+ # Assumes params[:method_name] or params[:argument] comes from user input
39
+ target_object = SomeClass.new
40
+ target_object.send(params[:method_name], params[:argument]) # User can potentially call dangerous methods
41
+
42
+ # Using instance_eval or class_eval with user-provided code strings
43
+ user_script = params[:custom_script]
44
+ some_object.instance_eval(user_script) # Executes arbitrary Ruby code in the object's context
45
+ To detect code vulnerable to Dangerous Code Execution like the examples provided above, perform the following detection steps:
46
+
47
+ Search for methods enabling dynamic code execution in Ruby code (e.g., eval, instance_eval, class_eval, send, public_send, system, exec, backticks `).
48
+ Check if arguments passed to these methods originate from or are directly influenced by external untrusted input (e.g., HTTP request parameters params, data from files, network responses). Look for patterns similar to the vulnerable Ruby examples shown above.
49
+ Verify if user input is rigorously sanitized or validated specifically to prevent code injection vectors before being used in these methods. Standard escaping for HTML (like XSS prevention) is not sufficient here. Check if execution is restricted only to a predefined, absolutely safe allowlist of commands or methods if dynamic execution cannot be avoided.
50
+ Assess if safer alternatives exist that can achieve the same functionality without dynamic code execution. Examples include using Hash lookups for dispatching actions, case statements based on input values, leveraging safe templating engines, or using specific library functions designed for the task instead of generic execution methods.
51
+ PROMPT
19
52
 
20
53
  RISK_PROMPTS = {
21
- xss: "Cross-Site Scripting (XSS): A vulnerability where user input is not properly escaped and is embedded into HTML or JavaScript, leading to arbitrary script execution in the victims browser. Look for unsanitized input and missing output encoding.",
22
- csrf: "Cross-Site Request Forgery (CSRF): An attack that forces an authenticated user to perform unwanted actions via forged requests. Detect missing CSRF tokens or absence of referer/origin validation.",
23
- idor: "Insecure Direct Object Reference (IDOR): Occurs when object identifiers (e.g., IDs) are exposed and access control is missing, allowing unauthorized access to other users data.",
24
- open_redirect: "Open Redirect: Redirecting users to external URLs based on user-supplied input without proper validation. Check for lack of domain or whitelist restrictions.",
25
- ssrf: "Server-Side Request Forgery (SSRF): The server makes HTTP requests to an arbitrary destination supplied by the user, potentially exposing internal resources or metadata.",
26
- session_fixation: "Session Fixation: The server accepts a pre-supplied session ID, allowing an attacker to hijack the session after authentication. Look for missing session ID regeneration after login.",
27
- inappropriate_cookie_attributes: "Insecure Cookie Attributes: Missing HttpOnly, Secure, or SameSite flags, which may lead to session theft or CSRF.",
28
- insufficient_encryption: "Insufficient Encryption: Use of weak algorithms (e.g., MD5, SHA1) or lack of encryption for sensitive data. Check for insecure hash functions or plain-text handling.",
29
- insecure_deserialization_rce: "Insecure Deserialization leading to RCE: Deserializing untrusted data can lead to arbitrary code execution. Detect unsafe use of deserialization functions without validation.",
30
- directory_traversal: "Directory Traversal: Allows attackers to access files outside the intended directory using ../ patterns. Check for path manipulation and missing canonicalization.",
31
- dangerous_eval: "Dangerous Code Execution (eval, exec): Dynamic code execution using untrusted input, allowing arbitrary code injection.",
32
- inappropriate_file_permissions: "Insecure File Permissions: Files or directories with overly permissive modes (e.g., 777), allowing unauthorized read/write/execute access.",
33
- temporary_backup_file_leak: "Temporary or Backup File Exposure: Sensitive files like .bak, .tmp, or ~ versions are publicly accessible due to poor file handling.",
34
- overly_detailed_errors: "Excessive Error Information Disclosure: Stack traces or internal error messages exposed to users, leaking implementation details.",
35
- csp_not_set: "Missing Content Security Policy (CSP): Absence of CSP headers increases risk of XSS. Look for missing Content-Security-Policy header.",
36
- mime_sniffing_vulnerability: "MIME Sniffing Vulnerability: Missing X-Content-Type-Options: nosniff header can allow browsers to misinterpret content types.",
37
- clickjacking_vulnerability: "Clickjacking Protection Missing: Absence of X-Frame-Options or frame-ancestors directive allows malicious framing of pages.",
38
- auto_index_exposure: "Auto Indexing Enabled: Directory listing is active, exposing files and internal structure to users.",
39
- inappropriate_password_policy: "Weak Password Policy: Inadequate rules such as short length, lack of complexity, or missing brute-force protections.",
40
- two_factor_auth_missing: "Missing Two-Factor Authentication (2FA): Lack of secondary authentication factor for sensitive operations.",
41
- race_condition: "Race Condition: Concurrent access without proper locking can lead to inconsistent states or privilege escalation.",
42
- server_error_information_exposure: "Server Error Information Exposure: Internal errors (e.g., 500) reveal stack traces or server information in responses.",
43
- dependency_trojan_package: "Dependency Trojan Package Risk: Installation of malicious or typosquatted packages from untrusted sources.",
44
- api_overexposure: "Excessive API Exposure: Public APIs exposed without authentication, leading to data leakage or unauthorized access.",
45
- security_middleware_disabled: "Security Middleware Disabled: Important protections (e.g., CSRF tokens, input sanitization) are turned off or removed.",
46
- security_header_inconsistency: "Security Header Inconsistency: Inconsistent or missing security headers across environments or routes.",
47
- excessive_login_attempts: "Excessive Login Attempts Allowed: Lack of rate limiting allows brute-force login attempts.",
48
- inappropriate_cache_settings: "Insecure Cache Settings: Sensitive pages are cached publicly (e.g., with Cache-Control: public), risking data leakage.",
49
- secret_key_committed: "Secret Key Committed to Repository: Credentials, JWT secrets, or API keys are hardcoded or pushed to version control.",
50
- third_party_script_validation_missing: "Missing Validation for Third-Party Scripts: External scripts are loaded without integrity checks (e.g., Subresource Integrity).",
51
- over_logging: "Over-Logging: Logging sensitive information such as passwords, tokens, or personal data.",
52
- fail_open_design: "Fail-Open Design: On error or exception, access is granted instead of safely denied.",
53
- environment_differences: "Uncontrolled Environment Differences: Security settings differ between development and production without strict controls.",
54
- audit_log_missing: "Missing Audit Logging: Lack of logging for critical actions or authorization checks prevents accountability.",
55
- time_based_side_channel: "Time-Based Side Channel: Execution time differences can leak secrets (e.g., timing attacks in string comparison)."
54
+ xss: "Cross-Site Scripting (XSS): A vulnerability where user input is not properly escaped and is embedded into HTML or JavaScript, leading to arbitrary script execution in the victim's browser. Detection steps: 1) Identify where user input is output to HTML/JS context. 2) Check if proper encoding/escaping is applied (e.g., html_safe, raw, sanitize, escape_javascript). 3) Look for unsafe methods that bypass default Rails escaping (html_safe, raw, <%==). 4) Examine JavaScript that incorporates user input via template interpolation. 5) Check for improper content-type headers that might enable XSS. 6) Verify if user input is passed to eval(), setTimeout(), document.write() or DOM manipulation functions. 7) Look for attribute injection possibilities where user input sets HTML attributes.",
55
+ csrf: "Cross-Site Request Forgery (CSRF): An attack that forces an authenticated user to perform unwanted actions via forged requests. Detection steps: 1) Check if CSRF protection is disabled globally or for specific controllers/actions (skip_before_action :verify_authenticity_token). 2) Look for APIs or endpoints that handle state-changing operations (POST, PUT, DELETE methods). 3) Verify if authenticity tokens are properly validated for forms and AJAX requests. 4) Check if the application relies solely on cookies for authentication without additional CSRF protection. 5) Look for custom CSRF protection implementations that might be incomplete. 6) Verify if SameSite cookie attributes are properly set. 7) Check if the application validates the Origin or Referer header for cross-origin requests.",
56
+ idor: "Insecure Direct Object Reference (IDOR): Occurs when object identifiers (e.g., IDs) are exposed and access control is missing, allowing unauthorized access to other users' data. Detection steps: 1) Identify endpoints that access data using user-supplied identifiers (e.g., params[:id]). 2) Check if proper authorization checks exist before accessing the data (e.g., current_user.orders vs Order.find). 3) Look for functions retrieving data without verifying the current user's ownership or access rights. 4) Check for sequential or predictable IDs that can be enumerated. 5) Verify if sensitive operations verify resource ownership before modifications. 6) Look for authorization checks that can be bypassed through parameter manipulation. 7) Examine APIs that return data based on user-supplied identifiers.",
57
+ open_redirect: "Open Redirect: Redirecting users to external URLs based on user-supplied input without proper validation. Detection steps: 1) Identify redirect methods or functions (redirect_to, headers['Location'], response.redirect, etc.). 2) Check if the redirect URL or destination can be controlled by user input. 3) Verify if there is proper validation of the redirect URL to prevent external redirects. 4) Look for validation patterns that only check for URL prefixes that could be bypassed. 5) Check if the code restricts redirects to only allowed domains or uses relative paths. 6) Watch for URL manipulation techniques that might bypass validation (using //, additional domains in path, URL encoding).",
58
+ ssrf: "Server-Side Request Forgery (SSRF): The server makes HTTP requests to an arbitrary destination supplied by the user, potentially exposing internal resources or metadata. Detection steps: 1) Identify code that makes network requests (HTTP, TCP, etc.). 2) Check if the URL or destination can be influenced by user input. 3) Verify if there is proper validation of user-supplied URLs or IPs to prevent access to internal resources. 4) Look for use of libraries like Net::HTTP, open-uri, rest-client, faraday, or HTTP clients where the URL is constructed dynamically. 5) Check if the code restricts requests to only allowed domains or IP ranges.",
59
+ session_fixation: "Session Fixation: The server accepts a pre-supplied session ID, allowing an attacker to hijack the session after authentication. Detection steps: 1) Check if the application regenerates session IDs upon authentication (reset_session, new session creation). 2) Look for login methods that don't rotate session identifiers. 3) Examine session management code for proper session invalidation after login/logout. 4) Verify if the application accepts externally provided session identifiers. 5) Check if cookie settings include proper security flags (HttpOnly, Secure, SameSite). 6) Examine how session state is maintained across privilege changes (e.g., becoming admin). 7) Look for custom session handling that bypasses Rails' built-in protection mechanisms.",
60
+ inappropriate_cookie_attributes: "Insecure Cookie Attributes: Missing HttpOnly, Secure, or SameSite flags, which may lead to session theft or CSRF. Detection steps: 1) Examine cookie configuration in session store settings. 2) Check for explicit cookie setting in controllers with cookies[:name] assignments. 3) Verify if sensitive cookies have the HttpOnly flag to prevent JavaScript access. 4) Check if cookies transmitting sensitive data have the Secure flag to prevent transmission over HTTP. 5) Verify if cookies have appropriate SameSite attribute (Strict, Lax, or None with Secure) to prevent CSRF and information leakage. 6) Look for custom session management that might not set proper cookie attributes. 7) Check if cookie expiration times are appropriate for the sensitivity of the data they contain.",
61
+ insufficient_encryption: "Insufficient Encryption: Use of weak algorithms (e.g., MD5, SHA1) or lack of encryption for sensitive data. Check for insecure hash functions or plain-text handling. Detection steps: 1) Identify code handling sensitive data (passwords, API keys, PII). 2) Check if data at rest (database) or in transit (network) is encrypted. 3) Identify algorithms used for hashing/encryption (e.g., Digest::MD5, Digest::SHA1). 4) Verify if algorithms meet current security standards (e.g., bcrypt, scrypt, SHA-256+ for hashing; AES for encryption). 5) Check secure management of encryption keys.",
62
+ insecure_deserialization_rce: "Insecure Deserialization leading to RCE: Deserializing untrusted data can lead to arbitrary code execution. Detect unsafe use of deserialization functions without validation. Detection steps: 1) Locate code performing deserialization (e.g., Marshal.load, YAML.load, JSON.parse). 2) Determine if the input data comes from untrusted sources (user input, network). 3) Verify if the data is validated or sanitized before deserialization. 4) Check if safe alternatives are used (e.g., YAML.safe_load, JSON.parse with appropriate options). 5) Analyze custom deserializers for vulnerabilities.",
63
+ directory_traversal: "Directory Traversal: Allows attackers to access files outside the intended directory using ../ patterns. Check for path manipulation and missing canonicalization. Detection steps: 1) Identify code accessing the file system using paths derived from user input. 2) Check if user input influencing file paths is sanitized (e.g., removing '../'). 3) Verify if path canonicalization functions (e.g., File.expand_path, Pathname#cleanpath) are used correctly. 4) Ensure the final path is validated to be within the intended base directory before access.",
64
+ dangerous_eval: "Dangerous Code Execution (eval, exec): Dynamic code execution using untrusted input, allowing arbitrary code injection. Detection steps: 1) Search for methods enabling dynamic code execution (eval, instance_eval, class_eval, send, public_send, system, exec, ` ``). 2) Check if arguments passed to these methods originate from or are influenced by user input. 3) Verify if user input is rigorously sanitized or validated before use, or if execution is restricted to safe, predefined commands/methods. 4) Assess if safer alternatives can replace dynamic execution.",
65
+ inappropriate_file_permissions: "Insecure File Permissions: Files or directories with overly permissive modes (e.g., 777), allowing unauthorized read/write/execute access. Detection steps: 1) Find code that creates files/directories or changes permissions (e.g., FileUtils.chmod, File.chmod, Dir.mkdir with mode). 2) Examine the permission modes being set (e.g., 0777, 0666). 3) Evaluate if permissions follow the principle of least privilege, especially avoiding world-writable (o+w) or world-readable (o+r) for sensitive files. 4) Check permissions of configuration files, log files, and uploaded files.",
66
+ temporary_backup_file_leak: "Temporary or Backup File Exposure: Sensitive files like .bak, .tmp, or ~ versions are publicly accessible due to poor file handling. Detection steps: 1) Identify logic creating temporary or backup files. 2) Check if common backup extensions (.bak, .tmp, ~, .old) are used. 3) Verify these files are not created within web-accessible directories. 4) Ensure temporary/backup files are securely deleted after use. 5) Check if .gitignore excludes these file patterns.",
67
+ overly_detailed_errors: "Excessive Error Information Disclosure: Stack traces or internal error messages exposed to users, leaking implementation details. Detection steps: 1) Examine error handling code (rescue blocks, error page rendering). 2) Check error messages displayed to users in the production environment. 3) Verify that stack traces, internal paths, database queries, or configuration details are not included in user-facing errors. 4) Confirm framework settings disable detailed errors in production (e.g., Rails `config.consider_all_requests_local = false`). 5) Ensure generic errors are shown to users, while details are logged server-side.",
68
+ csp_not_set: "Missing Content Security Policy (CSP): Absence of CSP headers increases risk of XSS. Look for missing Content-Security-Policy header. Detection steps: 1) Identify code setting HTTP response headers (middleware, controllers). 2) Check for the presence of the `Content-Security-Policy` header. 3) If missing or policy is overly permissive (e.g., includes 'unsafe-inline', 'unsafe-eval', '*'), report as risk. 4) Check framework CSP configuration mechanisms (e.g., Rails `config.content_security_policy`).",
69
+ mime_sniffing_vulnerability: "MIME Sniffing Vulnerability: Missing X-Content-Type-Options: nosniff header can allow browsers to misinterpret content types. Detection steps: 1) Identify code setting HTTP response headers. 2) Check for the presence of the `X-Content-Type-Options` header. 3) If the header is missing or its value is not exactly `nosniff`, report as risk. 4) Check framework defaults or security middleware for automatic inclusion.",
70
+ clickjacking_vulnerability: "Clickjacking Protection Missing: Absence of X-Frame-Options or frame-ancestors directive allows malicious framing of pages. Detection steps: 1) Identify code setting HTTP response headers. 2) Check for the `X-Frame-Options` header (e.g., `DENY`, `SAMEORIGIN`). 3) Alternatively, check for the `frame-ancestors` directive in the `Content-Security-Policy` header (e.g., `'none'`, `'self'`). 4) If neither is present or configured securely, report as risk. 5) Check framework defaults or security middleware.",
71
+ auto_index_exposure: "Auto Indexing Enabled: Directory listing is active, exposing files and internal structure to users. Detection steps: 1) Review web server configuration files (Nginx, Apache). 2) Look for directives enabling directory listing (e.g., Apache `Options +Indexes`, Nginx `autoindex on`). 3) Check if directory listing is unintentionally enabled for specific locations. 4) If the application framework serves static files, ensure its directory listing feature is disabled.",
72
+ inappropriate_password_policy: "Weak Password Policy: Inadequate rules such as short length, lack of complexity, or missing brute-force protections. Detection steps: 1) Locate code related to password setting/changing. 2) Check validation logic for minimum length, complexity requirements (character types). 3) Verify if checks against common weak passwords (dictionaries, patterns) exist. 4) Look for enforcement of password history (reuse prevention) and expiration. 5) Check for related brute-force protection (see `excessive_login_attempts`).",
73
+ two_factor_auth_missing: "Missing Two-Factor Authentication (2FA): Lack of secondary authentication factor for sensitive operations. Detection steps: 1) Identify login process and code for sensitive operations (e.g., profile change, payment). 2) Check if a second factor (SMS, TOTP, key) is required beyond the password. 3) Look for 2FA setup and management features. 4) Determine if 2FA is mandatory or optional for users.",
74
+ race_condition: "Race Condition: Concurrent access without proper locking can lead to inconsistent states or privilege escalation. Detection steps: 1) Identify code accessing shared resources (database records, files, cache). 2) Find sections where multiple threads/processes might read/write concurrently. 3) Look for non-atomic check-then-act patterns. 4) Verify use of proper locking mechanisms (database transactions, Mutex, file locks). 5) Focus on critical operations like balance updates, inventory control.",
75
+ server_error_information_exposure: "Server Error Information Exposure: Internal errors (e.g., 500) reveal stack traces or server information in responses. Detection steps: 1) Examine error handling for server-side errors (e.g., HTTP 500). 2) Check the content of error responses sent to the client in production. 3) Verify that server-specific information (software type/version, OS details) is not included. 4) Check server configuration to suppress revealing headers (e.g., `Server` header; Nginx `server_tokens off;`). 5) Ensure detailed errors are logged only, with generic messages shown to users. (Similar to `overly_detailed_errors` but focusing on server info).",
76
+ dependency_trojan_package: "Dependency Trojan Package Risk: Installation of malicious or typosquatted packages from untrusted sources. Detection steps: 1) Review dependency files (`Gemfile`, `Gemfile.lock`). 2) Scan the list of Gems for typosquatting or unfamiliar names. 3) Check Gem sources (avoid untrusted Git repos if possible). 4) Investigate reputation and maintenance status of less-known Gems. 5) Ensure `Gemfile.lock` is committed to version control. 6) Check if dependency scanning tools (e.g., `bundler-audit`) are used.",
77
+ api_overexposure: "Excessive API Exposure: Public APIs exposed without authentication, leading to data leakage or unauthorized access. Detection steps: 1) Identify all API endpoint definitions. 2) Verify that appropriate authentication and authorization checks are applied to each endpoint. 3) Check if rate limiting or access controls are in place, even for public APIs. 4) Ensure sensitive data or internal-only information is not returned by unauthenticated endpoints. 5) Review API documentation for unintended exposure.",
78
+ security_middleware_disabled: "Security Middleware Disabled: Important protections (e.g., CSRF tokens, input sanitization) are turned off or removed. Detection steps: 1) Review framework initialization and configuration files. 2) Look for intentional disabling or removal of standard security middleware (e.g., CSRF protection, secure session handling). 3) Check for route-specific or controller-specific disabling of security features (e.g., `skip_before_action :verify_authenticity_token`) and evaluate the justification.",
79
+ security_header_inconsistency: "Security Header Inconsistency: Inconsistent or missing security headers across environments or routes. Detection steps: 1) Locate code setting security headers (CSP, X-Frame-Options, HSTS, etc.). 2) Compare header settings across different environments (dev, staging, prod), ensuring production is not weaker. 3) Verify consistent application of headers across different routes/pages within the application. 4) Check for conflicts if headers are set in multiple places (middleware, reverse proxy).",
80
+ excessive_login_attempts: "Excessive Login Attempts Allowed: Lack of rate limiting allows brute-force login attempts. Detection steps: 1) Identify the login authentication code. 2) Check for logic that counts and limits login attempts per account and/or IP address within a time window. 3) Verify that countermeasures (account lockout, CAPTCHA, delay) are triggered upon exceeding the limit. 4) Check configuration of rate-limiting libraries (e.g., `rack-attack`). 5) Ensure similar limits exist for password reset functions.",
81
+ inappropriate_cache_settings: "Insecure Cache Settings: Sensitive pages are cached publicly (e.g., with Cache-Control: public), risking data leakage. Detection steps: 1) Identify code setting `Cache-Control` or `Pragma` headers. 2) Locate code generating pages containing user-specific or sensitive data. 3) Ensure these pages have restrictive cache directives (`private`, `no-store`, `no-cache`). 4) Look for inappropriate use of `public` or long `max-age`. 5) Review framework caching (page, action, fragment) usage for sensitive content. 6) Consider cache settings in reverse proxies/CDNs.",
82
+ secret_key_committed: "Secret Key Committed to Repository: Credentials, JWT secrets, or API keys are hardcoded or pushed to version control. Detection steps: 1) Scan codebase for hardcoded secrets (passwords, API keys, tokens). 2) Review configuration files (`database.yml`, `secrets.yml`, `.env`) for secrets and ensure they are gitignored if present. 3) Verify secrets are loaded from environment variables or dedicated secret management systems. 4) Scan version control history for accidentally committed secrets (and rotate if found). 5) Consider using secret scanning tools (e.g., `truffleHog`, `gitleaks`).",
83
+ third_party_script_validation_missing: 'Missing Validation for Third-Party Scripts: External scripts are loaded without integrity checks (e.g., Subresource Integrity). Detection steps: 1) Find HTML templates loading external JS/CSS (`<script src="...">`, `<link href="...">`). 2) Check if these tags include the `integrity` attribute (for SRI). 3) Report as risk if `integrity` attribute is missing or empty. 4) Verify the `crossorigin="anonymous"` attribute is also present when using SRI. 5) Check dynamically loaded scripts for similar integrity validation mechanisms.',
84
+ over_logging: "Over-Logging: Logging sensitive information such as passwords, tokens, or personal data. Detection steps: 1) Identify all logging statements (`Rails.logger.*`, `puts`, etc.). 2) Examine the data being logged. 3) Check specifically for sensitive data like passwords, tokens, API keys, PII, credit card numbers. 4) Pay attention to logging of entire request parameters or exception objects. 5) Verify framework parameter filtering (e.g., Rails `config.filter_parameters`) is configured correctly to mask sensitive fields.",
85
+ fail_open_design: "Fail-Open Design: On error or exception, access is granted instead of safely denied. Detection steps: 1) Identify security check code (authentication, authorization, access control). 2) Examine behavior within exception handling blocks (`rescue`). 3) Verify that exceptions during security checks default to denying access (fail-close/fail-safe), not granting it. 4) Look for checks where an error state might be misinterpreted as permissive. 5) Ensure critical operations use transactions and roll back safely on error.",
86
+ environment_differences: "Uncontrolled Environment Differences: Security settings differ between development and production without strict controls. Detection steps: 1) Compare configuration files across environments (`environments/development.rb` vs `environments/production.rb`). 2) Identify differences in security settings (error reporting, SSL, headers, auth). 3) Evaluate if differences weaken security in production. 4) Check for a process to manage and review environment-specific configurations. 5) Consider potential infrastructure differences (firewalls, server settings).",
87
+ audit_log_missing: "Missing Audit Logging: Lack of logging for critical actions or authorization checks prevents accountability. Detection steps: 1) Identify code performing critical actions (login, permission change, sensitive data access/modification, config change). 2) Verify these actions generate logs including who (user), when (timestamp), what (action/resource), result (success/fail), and where (IP address). 3) Check if authentication successes/failures and authorization failures are logged. 4) Assess if logs are stored securely and retained appropriately. 5) Ensure log format is consistent and useful for monitoring.",
88
+ time_based_side_channel: "Time-Based Side Channel: Execution time differences can leak secrets (e.g., timing attacks in string comparison). Detection steps: 1) Locate code comparing secret values (passwords, tokens, API keys). 2) Check if standard comparison operators (`==`) are used for secrets. 3) Verify use of constant-time comparison functions (e.g., `ActiveSupport::SecurityUtils.secure_compare`, `Rack::Utils.secure_compare`). 4) Analyze cryptographic operations for potential timing leaks (may depend on library implementation). 5) Consider if database query times varying based on input could leak information."
56
89
  }.freeze
57
-
90
+
58
91
 
59
92
  def initialize(config = {})
60
93
  # Load custom templates and language from config, merge with default
@@ -64,12 +97,30 @@ module Omamori
64
97
  @language = config.get("language", "en") # Get language from config, default to 'en'
65
98
  end
66
99
 
67
- def build_prompt(code_content, risks_to_check, json_schema, template_key: :default)
68
- # Use the template from @prompt_templates, defaulting to :default if template_key is not found
100
+ # Updated to accept file_path keyword argument
101
+ def build_prompt(code_content, risks_to_check, json_schema, template_key: :default, file_path: nil)
69
102
  template = @prompt_templates.fetch(template_key, @prompt_templates[:default])
70
103
  risk_list = risks_to_check.map { |risk_key| @risk_prompts[risk_key] }.compact.join(", ")
71
104
 
72
- template % { risk_list: risk_list, code_content: code_content, json_schema: json_schema.to_json, language: @language}
105
+ prompt_variables = {
106
+ risk_list: risk_list,
107
+ code_content: code_content,
108
+ json_schema: json_schema.to_json,
109
+ language: @language
110
+ }
111
+ # Add file_path to variables if provided and template expects it
112
+ # Ensure your template string (DEFAULT_PROMPT_TEMPLATE or custom ones)
113
+ # actually uses %{file_path} if you want to include it.
114
+ prompt_variables[:file_path] = file_path if file_path && template.include?("%{file_path}")
115
+
116
+ # Handle cases where a key in prompt_variables might not be in the template string
117
+ # by selecting only keys present in the template.
118
+ final_variables = {}
119
+ template.scan(/%\{(\w+)\}/).flatten.uniq.each do |key_in_template|
120
+ final_variables[key_in_template.to_sym] = prompt_variables[key_in_template.to_sym]
121
+ end
122
+
123
+ template % final_variables
73
124
  end
74
125
  end
75
126
  end
@@ -5,10 +5,14 @@ require 'yaml'
5
5
  module Omamori
6
6
  class Config
7
7
  DEFAULT_CONFIG_PATH = ".omamorirc"
8
+ DEFAULT_IGNORE_PATH = ".omamoriignore"
9
+
10
+ attr_reader :ignore_patterns
8
11
 
9
12
  def initialize(config_path = DEFAULT_CONFIG_PATH)
10
13
  @config_path = config_path
11
14
  @config = load_config
15
+ @ignore_patterns = load_ignore_patterns # Load ignore patterns
12
16
  validate_config # Add validation after loading
13
17
  end
14
18
 
@@ -128,6 +132,23 @@ module Omamori
128
132
  end
129
133
  end
130
134
 
135
+ # Load .omamoriignore file and return an array of ignore patterns
136
+ def load_ignore_patterns
137
+ ignore_path = DEFAULT_IGNORE_PATH
138
+ if File.exist?(ignore_path)
139
+ begin
140
+ File.readlines(ignore_path, chomp: true).reject do |line|
141
+ line.strip.empty? || line.strip.start_with?('#')
142
+ end
143
+ rescue => e
144
+ puts "Warning: Error reading .omamoriignore file #{ignore_path}: #{e.message}"
145
+ [] # Return empty array if reading fails
146
+ end
147
+ else
148
+ [] # Return empty array if file does not exist
149
+ end
150
+ end
151
+
131
152
  def load_config
132
153
  if File.exist?(@config_path)
133
154
  begin