Skip to content
Merged
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
356 changes: 244 additions & 112 deletions README.md

Large diffs are not rendered by default.

258 changes: 258 additions & 0 deletions docs/api_reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# API Reference

Base URL: `http://localhost:8003` (local) or your deployed URL.

## `GET /`

Root endpoint with application info and configuration.

**Response**:
```json
{
"app": "CodeSecAudit AI API",
"version": "0.6.0",
"description": "RAG-powered security code review engine",
"uptime": "0h 12m 34s",
"uptime_seconds": 754,
"start_time_iso": "2026-06-22T12:00:00Z",
"configuration": {
"rag_index_path": "data/final/rag_index",
"top_k_default": 3,
"database": "data/app/reviews.db",
"review_rules": 7,
"rag_index_loaded": true
}
}
```

---

## `GET /health`

Health check with RAG index status.

**Response**:
```json
{
"status": "ok",
"engine_version": "0.6.0",
"collection": "owasp_rag",
"documents": 2833,
"uptime_seconds": 754
}
```

---

## `POST /review`

Review source code without saving to history.

**Request**:
```json
{
"code": "eval(user_input)",
"file_path": "demo.py",
"top_k": 3,
"use_rag": true
}
```

| Field | Type | Default | Description |
|---|---|---|---|
| `code` | string | — | Source code to analyze (required, min 1 char) |
| `file_path` | string | `null` | Source file path (for display) |
| `top_k` | integer | `3` | Number of RAG results (1–20) |
| `use_rag` | boolean | `true` | Enable RAG retrieval |

**Response**:
```json
{
"summary": "Found 1 issue(s): CWE-94. Risk score: 35/100. Verdict: WARNING.",
"risk_score": 35,
"verdict": "WARNING",
"issues": [
{
"cwe_id": "CWE-94",
"severity": "critical",
"message": "Code injection via eval()",
"line": 1,
"snippet": "eval(user_input)",
"file_path": "demo.py",
"suggested_fix": "Avoid using eval() with untrusted input. Use ast.literal_eval() or a safe parser instead."
}
],
"metadata": {
"engine_version": "0.6.0",
"rag_used": true,
"rag_error": null,
"total_issues_found": 1,
"total_issues_reported": 1,
"deduplication_skipped": 0,
"limit_capped_by_rule": 0,
"limit_capped_total": false
}
}
```

---

## `POST /review/code`

Review source code and save the result to the review history database.

**Request**:
```json
{
"code": "eval(user_input)",
"file_path": "demo.py",
"source": "api",
"repo": "owner/repo",
"pr_number": 12,
"commit_sha": "abc123def456",
"top_k": 3,
"use_rag": false
}
```

| Field | Type | Default | Description |
|---|---|---|---|
| `code` | string | — | Source code to analyze (required) |
| `file_path` | string | `null` | Source file path |
| `source` | string | `"api"` | Origin (`api`, `cli`, `github-action`) |
| `repo` | string | `null` | GitHub `owner/repo` |
| `pr_number` | integer | `null` | Pull request number |
| `commit_sha` | string | `null` | Commit SHA |
| `top_k` | integer | `3` | Number of RAG results (1–20) |
| `use_rag` | boolean | `true` | Enable RAG retrieval |

**Response**:
```json
{
"review_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"summary": "Found 1 issue(s): CWE-94. Risk score: 35/100. Verdict: WARNING.",
"risk_score": 35,
"verdict": "WARNING",
"issues": [...],
"metadata": {...},
"created_at": "2026-06-22T12:34:56Z"
}
```

---

## `GET /reviews`

List past reviews, newest first.

**Query Parameters**:

| Parameter | Default | Max | Description |
|---|---|---|---|
| `limit` | 50 | 200 | Number of reviews to return |
| `offset` | 0 | — | Pagination offset |

**Request**:
```bash
curl "http://localhost:8003/reviews?limit=10&offset=0"
```

**Response**:
```json
{
"reviews": [
{
"review_id": "a1b2c3d4-...",
"source": "api",
"repo": "owner/repo",
"pr_number": 12,
"file_path": "demo.py",
"risk_score": 35,
"verdict": "WARNING",
"summary": "Found 1 issue(s): CWE-94...",
"created_at": "2026-06-22T12:34:56Z"
}
],
"total": 42,
"limit": 10,
"offset": 0
}
```

---

## `GET /reviews/{review_id}`

Get a single review with full issue details.

**Request**:
```bash
curl "http://localhost:8003/reviews/a1b2c3d4-..."
```

**Response**:
```json
{
"review_id": "a1b2c3d4-...",
"source": "api",
"repo": "owner/repo",
"pr_number": 12,
"commit_sha": "abc123",
"file_path": "demo.py",
"risk_score": 35,
"verdict": "WARNING",
"summary": "Found 1 issue(s): CWE-94...",
"issues": [
{
"cwe_id": "CWE-94",
"severity": "critical",
"message": "Code injection via eval()",
"line": 1,
"snippet": "eval(user_input)",
"file_path": "demo.py",
"suggested_fix": "Avoid using eval() with untrusted input..."
}
],
"metadata": {
"engine_version": "0.6.0",
"rag_used": false,
"total_issues_found": 1,
"total_issues_reported": 1
},
"created_at": "2026-06-22T12:34:56Z"
}
```

Returns `404` if review not found.

---

## `GET /stats`

Aggregated analytics from the review history database.

**Response**:
```json
{
"total_reviews": 42,
"verdict_counts": {
"APPROVE": 15,
"WARNING": 20,
"REQUEST_CHANGES": 7
},
"average_risk_score": 28.5,
"high_risk_reviews": 5,
"total_issues": 63
}
```

---

## Error Responses

| Status | Description |
|---|---|
| `400` | Invalid request body (e.g., empty code) |
| `404` | Review not found |
| `422` | Validation error (e.g., `top_k` out of range) |
| `500` | Internal server error |
124 changes: 124 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Architecture

## High-Level System Diagram

```mermaid
flowchart TD
A[GitHub Pull Request] --> B[GitHub Action / Future GitHub App]
B --> C[Changed Files + Diff Parser]
C --> D[review_engine Critic]
D --> E[Remote RAG Service on Hugging Face]
E --> F[OWASP Secure Coding Guidance]
D --> G[Fixer + Risk Scoring]
F --> G
G --> H[PR Summary Comment]
G --> I[Inline PR Comments]
G --> J[FastAPI Review History API]
J --> K[SQLite MVP / MongoDB SaaS]
K --> L[Streamlit Dashboard]
K --> M[Analytics API]
L --> M
```

## Component Overview

| Component | Language | Role |
|---|---|---|
| `review_engine` | Python | Core: critic, fixer, retriever, risk scorer, pipeline |
| `rag_service` | Python | Standalone FastAPI microservice for RAG (HF Space) |
| `review_store` | Python | SQLite persistence with repository pattern |
| `api` | Python | FastAPI application exposing review + history endpoints |
| `ui` (review) | Python | Streamlit interface for submitting code reviews |
| `ui` (dashboard) | Python | Streamlit interface for analytics and history |
| `scripts/` | Python | CLI, evaluation, deploy, smoke test helpers |
| `.github/workflows/` | YAML | GitHub Action definition |

## Review Pipeline

```mermaid
sequenceDiagram
participant PR as Pull Request
participant GA as GitHub Action
participant RE as review_engine
participant RS as RAG Service
participant DB as Review Store
participant UI as Dashboard

PR->>GA: opened / synchronize
GA->>RE: review_code(code, use_rag)
RE->>RE: critic.scan() → list of issues
alt RAG mode = remote
RE->>RS: POST /rag/search (query)
RS-->>RE: OWASP guidance chunks
else RAG mode = local
RE->>RE: RAGRetriever.search()
end
RE->>RE: fixer.generate_fixes(issues, guidance)
RE->>RE: risk_score.compute(issues) → score + verdict
RE-->>GA: ReviewResult
GA->>GA: post summary comment
GA->>GA: post inline comments (max 10)
GA->>DB: save review record
DB-->>UI: analytics data
```

## RAG Service Architecture

```mermaid
flowchart LR
A[Client] --> B[FastAPI /rag/search]
B --> C{API Key Check}
C -->|Missing / Invalid| D[401 Unauthorized]
C -->|Optional / Matching| E[RagIndex]
E --> F[Corpus JSONL from HF Dataset]
E --> G[all-MiniLM-L6-v2 Embeddings]
E --> H[Numpy Cosine Similarity Search]
H --> I[Top-K Results]
I --> B
```

The RAG service:
- Loads the corpus from Hugging Face Dataset (`OMCHOKSI108/CodeSecAudit-RAG`) on startup
- Embeds all chunks using `sentence-transformers/all-MiniLM-L6-v2` (384-dim)
- Searches via numpy cosine similarity (no heavy DB driver)
- Supports optional `X-CodeSec-RAG-Key` auth header (production: required)
- Returns up to `top_k` results with rank, score, title, CWE ID, and content

### Why a separate service?

RAG dependencies (sentence-transformers, PyTorch) add ~7 GB to the Docker image. By deploying the RAG service as a **separate Hugging Face Space**, the main API and dashboard stay lightweight (~500 MB) and call RAG over HTTP when needed.

## SaaS Future Architecture

```mermaid
flowchart TD
A[GitHub App Webhook] --> B[API Server - Render]
B --> C[MongoDB Atlas]
B --> D[Resend Email]
B --> E[RAG Service - HF Space]
C --> F[Users Collection]
C --> G[Installations Collection]
C --> H[Reviews Collection]
C --> I[Usage Events Collection]
C --> J[Plans Collection]
C --> K[Email Events Collection]
F --> L[Dashboard - Streamlit]
L --> M[GitHub OAuth Login]
L --> N[Usage Stats + Analytics]
D --> O[Welcome Email]
D --> P[Limit Reached Email]
D --> Q[Usage Guide Email]
```

See [docs/deployment_strategy.md](deployment_strategy.md) and [docs/saas_data_model.md](saas_data_model.md) for full details.

## Key Design Decisions

| Decision | Rationale |
|---|---|
| Rule-based detection (no LLM API) | Zero cost per review, deterministic, no API keys needed |
| Remote RAG via HTTP | Keeps main image ~500 MB; RAG deps live only on HF Space |
| Numpy cosine similarity over ChromaDB | Simpler, no heavy DB driver, 2,833 chunks fit in memory |
| SQLite MVP → MongoDB SaaS | SQLite is zero-config for development; MongoDB for production scale |
| `use_rag=False` in CI | Avoids downloading embedding model on every workflow run |
| Non-blocking CI (exit 0) | Prevents broken builds from false positives |
Loading
Loading