Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/scripts/comment_on_pr.py
Original file line number Diff line number Diff line change
@@ -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)
60 changes: 60 additions & 0 deletions .github/scripts/send_to_gemini.py
Original file line number Diff line number Diff line change
@@ -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)
46 changes: 46 additions & 0 deletions .github/workflows/ai-sec-scam.yaml
Original file line number Diff line number Diff line change
@@ -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 }}
29 changes: 20 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"net/http"
)

const port string = ":8080"
const port string = ":8282"

func main() {
http.HandleFunc("/blue", blueHandler)
Expand Down