diff --git a/.github/workflows/gemini-code-analysis.yml b/.github/workflows/gemini-code-analysis.yml new file mode 100644 index 0000000000..3cc8286362 --- /dev/null +++ b/.github/workflows/gemini-code-analysis.yml @@ -0,0 +1,66 @@ +name: Gemini Code Analysis + +on: + workflow_dispatch: + inputs: + file_path: + description: 'Path to the file to analyze' + required: true + type: string + pull_request: + types: [opened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: '18' + + - name: Run Gemini Analysis (Manual) + if: github.event_name == 'workflow_dispatch' + env: + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + run: | + if [ -z "$GEMINI_API_KEY" ]; then + echo "Warning: GEMINI_API_KEY secret is not set. Skipping analysis." + exit 0 + fi + node scripts/gemini_agent.js "${{ github.event.inputs.file_path }}" --api-key="$GEMINI_API_KEY" + + - name: Run Gemini Analysis (PR) + if: github.event_name == 'pull_request' + env: + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + run: | + if [ -z "$GEMINI_API_KEY" ]; then + echo "Warning: GEMINI_API_KEY secret is not set. Skipping analysis." + exit 0 + fi + + # Get list of changed files in the PR + CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.(go|js|ts|sol)$' || true) + + if [ -z "$CHANGED_FILES" ]; then + echo "No relevant files changed in this PR." + exit 0 + fi + + # Analyze each changed file + echo "$CHANGED_FILES" | while read -r file; do + if [ -f "$file" ]; then + echo "Analyzing $file..." + node scripts/gemini_agent.js "$file" --api-key="$GEMINI_API_KEY" || true + fi + done diff --git a/scripts/GEMINI_AGENT_README.md b/scripts/GEMINI_AGENT_README.md new file mode 100644 index 0000000000..2179b74540 --- /dev/null +++ b/scripts/GEMINI_AGENT_README.md @@ -0,0 +1,83 @@ +# Gemini Code Analysis Agent + +This script uses Google's Gemini AI model to analyze code for potential vulnerabilities, best practice deviations, and mathematical instability. + +## Features + +- Analyzes code files using the Gemini 2.5 Flash Preview model +- Provides a Protocol Stability Score (1-10) +- Identifies potential flaws and security issues +- Suggests repaired code when issues are found + +## Prerequisites + +- Node.js 18+ (which includes built-in fetch support) +- A Google Gemini API key + +## Usage + +### Command Line + +```bash +node scripts/gemini_agent.js --api-key= +``` + +Example: +```bash +node scripts/gemini_agent.js ./pkg/model/model.go --api-key=your_gemini_api_key +``` + +### GitHub Actions + +The script can be run automatically via GitHub Actions: + +1. **Manual Trigger**: Go to Actions → "Gemini Code Analysis" → Run workflow, and specify the file path +2. **Automatic PR Analysis**: The workflow will automatically analyze changed files in pull requests (if GEMINI_API_KEY secret is configured) + +## Setting up the API Key + +### For Local Development + +```bash +node scripts/gemini_agent.js path/to/file.go --api-key=YOUR_API_KEY +``` + +### For GitHub Actions + +Add `GEMINI_API_KEY` as a repository secret: + +1. Go to your repository settings +2. Navigate to Secrets and variables → Actions +3. Add a new secret named `GEMINI_API_KEY` +4. Paste your Google Gemini API key + +## Getting a Gemini API Key + +1. Visit [Google AI Studio](https://makersuite.google.com/app/apikey) +2. Sign in with your Google account +3. Create a new API key +4. Copy the key for use with this script + +## Output + +The script will output: +- Protocol Stability Score (1-10) +- Summary of potential flaws +- Repaired code block (if issues are found) +- "NO REPAIR NEEDED" (if code is perfect) + +## Error Handling + +The script includes comprehensive error handling: +- Missing API key: Shows usage instructions +- Missing file: Shows file read error +- API failures: Shows detailed error message +- Network issues: Gracefully handles fetch failures + +## Note + +This is a conceptual implementation designed for protocol analysis. The script can be extended to: +- Write repaired code back to files +- Comment on GitHub PRs with analysis results +- Support batch analysis of multiple files +- Integrate with CI/CD pipelines diff --git a/scripts/gemini_agent.js b/scripts/gemini_agent.js new file mode 100644 index 0000000000..26e5bae932 --- /dev/null +++ b/scripts/gemini_agent.js @@ -0,0 +1,108 @@ +// --- Conceptual Gemini Agent Script (Node.js) --- + +const fs = require('fs'); +const path = require('path'); + +// NOTE: In a real Node.js environment, you would use an external library like +// 'node-fetch' for making HTTP requests, and potentially 'dotenv' for keys. +// For this example, we assume basic fetch is available or polyfilled. + +const GEMINI_MODEL = 'gemini-2.5-flash-preview-09-2025'; + +// Use a simple prompt designed for code repair/analysis +const AGENT_SYSTEM_PROMPT = `Act as an elite protocol engineer specializing in ZK-Circuits and DAO stability. Analyze the provided code block for vulnerabilities, deviations from best practices, and mathematical instability. +1. Assign a **Protocol Stability Score (1-10)**. +2. Provide a brief summary of **Potential Flaws**. +3. If flaws exist, provide the **REPAIRED CODE BLOCK** only. Do not provide any conversational text before the repaired code. If the code is perfect, output 'NO REPAIR NEEDED'.`; + +/** + * Executes the Gemini API call to analyze the given code snippet. + * @param {string} codeContent - The content of the file to analyze. + * @param {string} filePath - The name of the file being analyzed. + * @param {string} apiKey - The Gemini API key. + */ +async function runAnalysis(codeContent, filePath, apiKey) { + if (!apiKey) { + console.error("Error: GEMINI_API_KEY is missing. Check GitHub Secrets configuration."); + return; + } + + const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${apiKey}`; + + // The user query includes the file content to be analyzed + const userQuery = `Analyze the protocol code for ${filePath}:\n\n\`\`\`\n${codeContent}\n\`\`\``; + + const payload = { + contents: [{ parts: [{ text: userQuery }] }], + systemInstruction: { parts: [{ text: AGENT_SYSTEM_PROMPT }] }, + // For code analysis, grounding is usually not necessary unless you need real-time data + // tools: [{ "google_search": {} }], + }; + + let response; + try { + // Simple fetch example (replace with node-fetch in a real project) + response = await fetch(apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const result = await response.json(); + const analysisText = result.candidates?.[0]?.content?.parts?.[0]?.text || "Agent failed to generate response."; + + console.log(`\n### Protocol Analysis for ${filePath} ###`); + console.log(analysisText); + + // --- DEEP THINK REPAIR LOGIC --- + // A real agent would look for the 'REPAIRED CODE BLOCK' and attempt to + // write it back to the file system or comment on the PR using the GitHub Token. + const hasRepairDecision = analysisText.includes('REPAIRED CODE BLOCK') || analysisText.includes('NO REPAIR NEEDED'); + if (hasRepairDecision) { + console.log("Analysis Complete. Check output for repair instructions."); + } + + } catch (error) { + console.error(`\n--- FAILED ANALYSIS for ${filePath} ---`); + console.error(`Gemini Agent Error: ${error.message}`); + } +} + +/** + * Main execution function to handle command-line arguments. + */ +async function main() { + const filePath = process.argv[2]; + const apiKeyArg = process.argv.find(arg => arg.startsWith('--api-key=')); + + if (!filePath || !apiKeyArg) { + console.error("Usage: node gemini_agent.js --api-key="); + return; + } + + const apiKey = apiKeyArg.split('=')[1]; + + try { + const codeContent = fs.readFileSync(path.resolve(filePath), 'utf8'); + await runAnalysis(codeContent, filePath, apiKey); + } catch (error) { + console.error(`Error reading file ${filePath}: ${error.message}`); + } +} + +// Ensure fetch is available in Node.js environment +if (typeof fetch === 'undefined') { + try { + global.fetch = require('node-fetch'); // NOTE: This requires 'npm install node-fetch' in a real setup + } catch (err) { + console.error('Error: fetch is not available and node-fetch is not installed.'); + console.error('Please use Node.js 18+ which has built-in fetch support, or install node-fetch.'); + process.exit(1); + } +} + +main();