11import os
2+ import argparse
23import google .generativeai as genai
34from pathlib import Path
45
5- # Configure Gemini
6- API_KEY = os .getenv ("GEMINI_API_KEY" )
7- if not API_KEY :
8- raise ValueError ("GEMINI_API_KEY environment variable not set" )
6+ # --- CONFIGURATION ---
7+ # Set default values, but allow them to be overridden by command-line arguments.
8+ # This makes the script more flexible for different use cases.
99
10- genai .configure (api_key = API_KEY )
10+ # The generative model to use for analysis. Using a powerful model like 1.5 Pro
11+ # is recommended for its large context window and strong reasoning capabilities.
12+ MODEL_NAME = "gemini-2.5-flash"
1113
12- # Configuration
13- MODEL_NAME = "gemini-1.5-pro-latest" # Using 1.5 Pro for large context window
14- ROOT_DIR = "."
15- OUTPUT_FILE = "SECURITY_REPORT.md"
14+ # The root directory of the codebase to be analyzed.
15+ # We'll scan this directory recursively.
16+ ROOT_DIR = ".." # Changed to parent directory to scan the whole project
1617
17- # Extensions to scan
18+ # The directory where the security analysis report will be saved.
19+ # This helps keep the project's root directory clean.
20+ OUTPUT_DIR = "../temp/analysis"
21+ OUTPUT_FILE_NAME = "SECURITY_REPORT.md"
22+
23+ # File extensions to include in the scan. This helps focus the analysis on
24+ # relevant source code and configuration files.
1825INCLUDED_EXTENSIONS = {".java" , ".gradle" , ".xml" , ".sh" , ".properties" }
19- EXCLUDED_DIRS = {".git" , ".gradle" , "build" , "target" , ".idea" , "wrapper" }
26+
27+ # Directories to exclude from the scan. This is crucial for avoiding noise
28+ # from dependencies, build artifacts, and version control metadata.
29+ EXCLUDED_DIRS = {".git" , ".gradle" , "build" , "target" , ".idea" , "wrapper" , "scripts" }
30+
2031
2132def get_code_context (root_dir ):
33+ """
34+ Recursively scans the specified root directory, aggregates the content of
35+ files with allowed extensions, and returns it as a single string.
36+
37+ This function is the core of the data collection phase. It creates a "context"
38+ of the entire codebase that can be sent to the generative model for analysis.
39+ """
2240 code_content = ""
2341 file_count = 0
2442
43+ print (f"Starting code scan in: { Path (root_dir ).resolve ()} " )
44+
2545 for root , dirs , files in os .walk (root_dir ):
26- # Filter directories
46+ # Dynamically filter out excluded directories to prune the search space.
2747 dirs [:] = [d for d in dirs if d not in EXCLUDED_DIRS ]
2848
2949 for file in files :
@@ -32,56 +52,106 @@ def get_code_context(root_dir):
3252 try :
3353 with open (file_path , "r" , encoding = "utf-8" ) as f :
3454 content = f .read ()
35- code_content += f"\n --- START FILE: { file_path } ---\n "
55+ # Add file content with clear separators for the model.
56+ code_content += f"\\ n--- START FILE: { file_path } ---\\ n"
3657 code_content += content
37- code_content += f"\n --- END FILE: { file_path } ---\n "
58+ code_content += f"\\ n--- END FILE: { file_path } ---\ \ n"
3859 file_count += 1
3960 except Exception as e :
61+ # Log errors for files that can't be read, but continue the scan.
4062 print (f"Skipping file { file_path } : { e } " )
4163
4264 print (f"Scanned { file_count } files." )
4365 return code_content
4466
67+
4568def analyze_code (code_context ):
69+ """
70+ Sends the collected code context to the Gemini model for a security analysis.
71+
72+ The prompt is engineered to instruct the model to act as a security expert
73+ and provide a structured, actionable report.
74+ """
4675 model = genai .GenerativeModel (MODEL_NAME )
4776
4877 prompt = f"""
4978 You are an expert Static Application Security Testing (SAST) tool and Senior Software Engineer.
50- Analyze the following codebase for:
51- 1. Security Vulnerabilities (OWASP Top 10, Injection, XSS, etc.)
52- 2. Code Smells & Anti-patterns
53- 3. Performance Issues
54- 4. Dependency checks (based on build.gradle)
55-
56- Format your response as a professional Markdown report with the following sections:
57- - **Executive Summary**: High-level overview of health.
58- - **Critical Vulnerabilities**: Immediate security threats.
59- - **Code Quality Issues**: Maintainability and logic suggestions.
60- - **Recommendations**: Specific code fixes.
61-
62- Here is the codebase:
79+ Your task is to analyze the provided codebase for potential issues.
80+
81+ Please review the following aspects:
82+ 1. **Security Vulnerabilities**: Identify critical security flaws such as those listed in the
83+ OWASP Top 10 (e.g., Injection, Broken Authentication, XSS, Insecure Deserialization).
84+ 2. **Code Smells & Anti-patterns**: Look for poor programming practices, design flaws,
85+ or code structures that are hard to maintain.
86+ 3. **Performance Issues**: Highlight any code that may lead to performance bottlenecks,
87+ such as inefficient loops, memory leaks, or suboptimal queries.
88+ 4. **Dependency Checks**: Based on the `build.gradle` file, check for any dependencies
89+ with known vulnerabilities or that are outdated.
90+
91+ Structure your findings into a professional Markdown report with these sections:
92+ - **Executive Summary**: A high-level overview of the codebase's health and key findings.
93+ - **Critical Vulnerabilities**: A list of immediate security threats that must be addressed.
94+ - **Code Quality Issues**: Suggestions for improving maintainability, readability, and logic.
95+ - **Recommendations**: Specific, actionable advice for fixing the identified issues,
96+ including code snippets where possible.
97+
98+ Here is the codebase to analyze:
6399 { code_context }
64100 """
65101
66- # Generate content
67- # Set safety settings to block none to ensure we get the full critique even if code is "unsafe"
102+ print ("Sending code to Gemini for analysis. This may take a few moments..." )
103+
104+ # Configure safety settings to ensure the model returns a complete analysis,
105+ # even if it encounters code that might be flagged as "unsafe."
68106 response = model .generate_content (
69107 prompt ,
70108 generation_config = {"temperature" : 0.2 }
71109 )
72110
73111 return response .text
74112
113+
75114def main ():
76- print ("Gathering code..." )
115+ """
116+ Main function to orchestrate the security analysis workflow.
117+ 1. Parses command-line arguments for the API key.
118+ 2. Configures the Gemini client.
119+ 3. Gathers code context.
120+ 4. Triggers the analysis.
121+ 5. Saves the report to a file.
122+ """
123+ # Set up argument parser for command-line execution.
124+ parser = argparse .ArgumentParser (description = "Perform a security analysis of a codebase using Gemini." )
125+ parser .add_argument ("--api-key" , required = True , help = "Your Gemini API key." )
126+ args = parser .parse_args ()
127+
128+ # Configure the Gemini client with the provided API key.
129+ try :
130+ genai .configure (api_key = args .api_key )
131+ except Exception as e :
132+ print (f"Error configuring Gemini: { e } " )
133+ return
134+
135+ print ("Gathering code context..." )
77136 code_context = get_code_context (ROOT_DIR )
78137
79- print ("Sending to Gemini for analysis..." )
138+ if not code_context :
139+ print ("No code found to analyze. Please check your configuration." )
140+ return
141+
80142 report = analyze_code (code_context )
81143
82- with open (OUTPUT_FILE , "w" , encoding = "utf-8" ) as f :
144+ # Ensure the output directory exists.
145+ output_path = Path (OUTPUT_DIR )
146+ output_path .mkdir (parents = True , exist_ok = True )
147+
148+ # Write the report to the specified output file.
149+ report_file = output_path / OUTPUT_FILE_NAME
150+ with open (report_file , "w" , encoding = "utf-8" ) as f :
83151 f .write (report )
84- print (f"Report generated: { OUTPUT_FILE } " )
152+
153+ print (f"Security report successfully generated at: { report_file .resolve ()} " )
154+
85155
86156if __name__ == "__main__" :
87- main ()
157+ main ()
0 commit comments