diff --git a/.github/scripts/comment_on_pr.py b/.github/scripts/comment_on_pr.py new file mode 100644 index 0000000..c19c8ea --- /dev/null +++ b/.github/scripts/comment_on_pr.py @@ -0,0 +1,29 @@ +import os +import requests + +GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") +REPO = os.getenv("GITHUB_REPOSITORY") # e.g., bashizip/opsGo +PR_NUMBER = os.getenv("GITHUB_PR_NUMBER") +COMMENT_FILE = "gemini-response.txt" + +# Load AI-generated suggestions +with open(COMMENT_FILE, "r") as f: + comment_body = f.read() + +# Prepare GitHub API request +url = f"https://api.github.com/repos/{REPO}/issues/{PR_NUMBER}/comments" +headers = { + "Authorization": f"Bearer {GITHUB_TOKEN}", + "Accept": "application/vnd.github.v3+json" +} + +payload = {"body": f"\ud83e\udde0 **AI Suggestions from Gemini**\n\n{comment_body}"} + +# Post comment to PR +response = requests.post(url, headers=headers, json=payload) + +if response.status_code == 201: + print("Successfully posted AI suggestions to the PR.") +else: + print("Failed to post comment:", response.status_code, response.text) + exit(1) diff --git a/.github/scripts/send_to_gemini.py b/.github/scripts/send_to_gemini.py new file mode 100644 index 0000000..51c2c77 --- /dev/null +++ b/.github/scripts/send_to_gemini.py @@ -0,0 +1,60 @@ +import os +import json +import requests + +TRIVY_FILE = "trivy-results.json" +OUTPUT_FILE = "gemini-response.txt" +API_KEY = os.getenv("GEMINI_API_KEY") +GEMINI_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent" + +if not API_KEY: + raise EnvironmentError("❌ GEMINI_API_KEY environment variable is not set.") + +# Append API key as URL query parameter +url = f"{GEMINI_ENDPOINT}?key={API_KEY}" + +# Load Trivy scan results +with open(TRIVY_FILE, "r") as f: + trivy_data = json.load(f) + +# Build the prompt +prompt_text = f""" +The following is a vulnerability scan of a Docker image using Trivy. +Please analyze the issues and suggest secure fixes for each finding. + +```json +{json.dumps(trivy_data, indent=2)} +``` +""" + +# Prepare the request payload +payload = { + "contents": [ + { + "parts": [{"text": prompt_text}] + } + ] +} + +# Make the POST request +response = requests.post( + url, + headers={"Content-Type": "application/json"}, + json=payload +) + +# Handle the response +if response.status_code == 200: + try: + ai_reply = response.json()["candidates"][0]["content"]["parts"][0]["text"] + with open(OUTPUT_FILE, "w") as out: + out.write(ai_reply) + print("✅ AI suggestions saved to gemini-response.txt") + except (KeyError, IndexError): + print("⚠️ Received unexpected response format:") + print(response.json()) + exit(1) +else: + print("❌ Error from Gemini:", response.status_code) + print(response.text) + exit(1) diff --git a/.github/workflows/ai-sec-scam.yaml b/.github/workflows/ai-sec-scam.yaml new file mode 100644 index 0000000..a387e50 --- /dev/null +++ b/.github/workflows/ai-sec-scam.yaml @@ -0,0 +1,46 @@ +name: AI-Powered Docker Security Scan + +on: + pull_request: + branches: [ "main" ] + types: [opened, synchronize] + +jobs: + ai-sec-docker-scan: + name: Scan Docker Image and Generate AI Suggestions + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Python dependencies + run: pip install requests + + - name: Build Docker image + run: docker build -t opsgo-ai-scan:latest -f Dockerfile . + + - name: Run Trivy scan on Docker image + uses: aquasecurity/trivy-action@0.13.0 + with: + scan-type: 'image' + image-ref: 'opsgo-ai-scan:latest' + format: 'json' + output: 'trivy-results.json' + + - name: Analyze results with Gemini + run: python .github/scripts/send_to_gemini.py + env: + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + + - name: Post AI suggestions to PR + run: python .github/scripts/comment_on_pr.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/Dockerfile b/Dockerfile index 8e9c066..c7f808b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,15 +14,26 @@ # # Modified by Patrick Bashizi in March 2025 for educational purposes -FROM golang:1.19.2 as builder -WORKDIR /app -RUN go mod init opsgo -COPY *.go ./ -RUN CGO_ENABLED=0 GOOS=linux go build -o /opsgo +FROM debian:11.10 -FROM gcr.io/distroless/base-debian11 -WORKDIR / -COPY --from=builder /opsgo /opsgo -ENV PORT 8080 +# Update package lists and install necessary dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + libc6=2.31-13+deb11u12 \ + libssl1.1=1.1.1w-0+deb11u2 \ + openssl=1.1.1w-0+deb11u2 \ + tzdata=2025b-0+deb11u1 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Copy application files +COPY /opsgo /opsgo + +# Set environment variables +ENV PORT=8080 + +# Create a non-root user +RUN groupadd -r nonroot && useradd -r -g nonroot nonroot USER nonroot:nonroot + +# Command to run the application CMD ["/opsgo"] \ No newline at end of file diff --git a/main.go b/main.go index 3bc6b17..ba49098 100644 --- a/main.go +++ b/main.go @@ -25,7 +25,7 @@ import ( "net/http" ) -const port string = ":8080" +const port string = ":8282" func main() { http.HandleFunc("/blue", blueHandler)