Observed since 20 Oct, 18:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
acrqa
AI-powered code review with RAG-grounded explanations, 10 static analysers, and ECDSA-signed provenance
10 static analysis tools. One canonical schema. RAG-enhanced AI explanations. $0 recurring cost.
ACR-QA is a provenance-first, AI-augmented code review platform built as a graduation thesis at KSIU. It solves three real problems that frustrate every developer using static analysis tools:
| Problem | What ACR-QA does |
|---|---|
| Alert fatigue — 7 tools dump raw JSON in incompatible schemas, full of duplicates | Normalises all output into one canonical schema, deduplicates cross-tool, ranks by severity |
| LLM hallucination — AI assistants give confident but wrong security advice | RAG: the LLM can only explain rules it can cite from a curated 66-rule knowledge base; semantic entropy (3× runs) detects contradictions |
| Invisible test gaps — code coverage % doesn't tell you which complex functions have no test | AST-based Test Gap Analyzer ranks untested symbols by cyclomatic complexity |
Key numbers: 97.1% precision · 9/10 OWASP Top 10 · 2,339 tests (2,274 Python + 65 TypeScript) · 36 async API endpoints · $0 recurring cost
C4Container
title ACR-QA — System Overview
Person(dev, "Developer")
Container_Boundary(sys, "ACR-QA") {
Container(cli, "CLI / GitHub Action", "Python", "Entry point. Detects language, routes to adapter.")
Container(core, "Analysis Engine", "Python 3.11", "10 tools → normalise → score → dedup → AI explain → quality gate")
Container(api, "Async REST API", "FastAPI :8000", "36 /v1/ endpoints · JWT + API key auth · Swagger at /docs")
Container(worker, "Background Worker", "Celery + Redis", "Async scan execution — POST /v1/scans returns 202 + job_id")
ContainerDb(pg, "PostgreSQL 15", "", "Provenance: runs · findings · LLM calls · feedback · users · api_keys")
ContainerDb(redis, "Redis 5.2", "", "Rate limiting · explanation cache · Celery broker + result backend")
}
Container_Ext(groq, "Groq API", "LLM", "Llama 3.3-70b explanations · Llama 3.1-8b feasibility · free tier")
Container_Ext(gh, "GitHub / GitLab", "CI", "PR comments · SARIF upload · merge blocking")
Rel(dev, cli, "runs analysis")
Rel(cli, core, "invokes pipeline")
Rel(core, pg, "stores provenance")
Rel(core, redis, "rate limit / cache")
Rel(core, groq, "RAG explanations")
Rel(core, gh, "PR comments + SARIF")
Full C4 diagrams: C1 Context · C2 Containers · C3 Components · C4 Code
git clone https://github.com/ahmed-145/acr-qa.git && cd acr-qa
cp .env.example .env # add your GROQ_API_KEY_1..4
make up
| Service | URL |
|---|---|
| FastAPI | http://localhost:8000 |
| Grafana | http://localhost:3005 (admin/admin) |
| Prometheus | http://localhost:9091 |
pip install -r requirements.txt
createdb acrqa && psql -d acrqa -f DATABASE/schema.sql
cp .env.example .env && source .env
uvicorn FRONTEND.api.main:app --port 8000 # → http://localhost:8000/docs
# Python project
python3 CORE/main.py --target-dir ./myproject --rich
# JavaScript / TypeScript project
python3 CORE/main.py --target-dir ./my-express-app --lang javascript --no-ai
# Go project
python3 CORE/main.py --target-dir ./my-go-api --lang go
# JSON output for CI pipelines
python3 CORE/main.py --target-dir . --json --no-ai > findings.json
| Feature | CodeRabbit | SonarQube | ACR-QA |
|---|---|---|---|
| Multi-tool normalisation | ✅ | ✅ | ✅ 10 tools |
| AI explanations | ✅ | ✅ | ✅ RAG + entropy |
| Hallucination detection | ❌ | ❌ | ✅ semantic entropy (3×) |
| Test gap analysis | ❌ | ❌ | ✅ AST-based |
| Confidence per finding | ❌ | ❌ | ✅ 0–100 score |
| Feedback-driven tuning | ❌ | ❌ | ✅ auto suppression |
| Cost-benefit analysis | ❌ | ❌ | ✅ ROI per finding |
| Call-graph reachability | ❌ | ❌ | ✅ AST-based, 0% FP rate |
| Path feasibility (FP reduction) | ❌ | ❌ | ✅ LLM4PFA approach |
| Cross-language vuln chains | ❌ | ❌ | ✅ CHARON-inspired |
| CBoM (quantum-safety) | ❌ | ❌ | ✅ NIST FIPS 203/204 |
| Quality gates (CI blocking) | ✅ | ✅ | ✅ configurable |
| SARIF export | ✅ | ✅ | ✅ v2.1.0 |
| OWASP compliance report | ✅ | ✅ | ✅ 9/10 + CWE IDs |
| Recurring cost | $$$ | $$$ | $0 |
10 tools run in parallel, all output normalised into one CanonicalFinding schema:
| Tool | Language | What It Catches |
|---|---|---|
| Ruff | Python | Style, imports, unused code, PEP8 |
| Bandit | Python | Security anti-patterns (33 rules) |
| Semgrep | Python / JS / Go | OWASP Top 10 patterns, custom rules |
| Vulture | Python | Dead code, unreachable branches |
| Radon | Python | Cyclomatic complexity, maintainability |
| Secrets Detector | All | API keys, passwords, JWTs, tokens |
| SCA Scanner | Python | Known-vulnerable dependency versions |
| ESLint | JS / TS | Security plugin — 20 rules |
| gosec | Go | Go security vulnerabilities |
| staticcheck | Go | Go static analysis and bug detection |
config/rules.yml) — every rule has description, rationale, remediation, and code examples# .acrqa.yml
quality_gate:
mode: block # block = fail CI + prevent merge | warn = comment only
max_high: 0 # zero tolerance for HIGH severity
max_medium: 5
max_security: 0
Fails CI with exit code 1. GitHub Action posts severity table as PR comment.
.acrqa.yml)rules:
disabled_rules: [IMPORT-001, STYLE-007]
severity_overrides: {COMPLEXITY-001: low}
analysis:
ignore_paths: [.venv, migrations/, node_modules]
ai:
max_explanations: 50
model: llama-3.1-8b-instant
result = eval(user_input) # acr-qa:ignore
password = "secret123" # acrqa:disable SECURITY-005
python3 CORE/main.py [options]
--target-dir DIR Directory to analyse (default: samples/realistic-issues)
--repo-name NAME Repository name for provenance tracking
--pr-number N PR number (enables GitHub PR comment posting)
--limit N Max findings to AI-explain (default: 50)
--diff-only Analyse only files changed in git diff
--diff-base BRANCH Base branch for diff (default: main)
--auto-fix Generate auto-fix suggestions for fixable rules
--rich Rich terminal output with colour-coded tables
--lang LANG auto (default) | python | javascript | typescript | go
--no-ai Skip AI explanation step (faster, no API key needed)
--json Output findings as JSON to stdout (pipe-friendly)
--version Print version and exit
Ruff · Bandit · Semgrep · Vulture · Radon · Secrets · SCA · CBoM
python3 CORE/main.py --target-dir ./my-react-app # auto-detect
python3 CORE/main.py --target-dir ./my-express-api --lang javascript
ESLint (security plugin) · Semgrep JS rules · npm audit 56 rule mappings · 15 HIGH-severity security rules covered
python3 CORE/main.py --target-dir ./my-go-api --lang go
Prerequisites: go install github.com/securego/gosec/v2/cmd/gosec@latest && go install honnef.co/go/tools/cmd/staticcheck@latest
gosec · staticcheck · Semgrep Go rules · 45+ rule mappings
# .github/workflows/acr-qa.yml (already in repo)
# Triggers on every PR:
# 1. Runs all 10 tools on changed files (--diff-only)
# 2. Normalises, scores, generates AI explanations
# 3. Posts severity-sorted PR comment with code suggestions
# 4. Uploads findings.sarif to GitHub Security Tab
# 5. Fails merge if quality gate violated (exit code 1)
Required secrets: GROQ_API_KEY_1..4 · GITHUB_TOKEN (auto-provided)
Comment on any PR:
acr-qa review
.gitlab-ci.yml included. Set GROQ_API_KEY_1 and GITLAB_TOKEN in CI/CD Variables.
Prometheus scrapes /metrics every 15 s. Grafana dashboard at http://localhost:3005 (admin/admin):
| Panel | Metric |
|---|---|
| Request Rate | rate(acrqa_http_requests_total[5m]) |
| P95 Latency | histogram_quantile(0.95, ...) |
| HTTP Success Rate | 2xx / total * 100 |
| LLM Latency | avg(explain endpoint duration) |
| Error Rate | rate(5xx[1m]) |
make test-all # 2,339 tests (full suite)
make test # acceptance tests only
make run # pipeline on sample files
| Test File | Tests | Coverage |
|---|---|---|
test_acceptance.py | 4 | Pipeline E2E with mocked LLM |
test_api.py | 9 | FastAPI endpoints |
test_normalizer.py | 7 | Ruff / Bandit / Semgrep normalisation |
test_new_engines.py | 117 | Secrets, SCA, CBoM, autofix, quality gate, KeyPool |
test_deep_coverage.py | 100 | 12-module deep coverage |
test_god_mode.py | 96 | All features + regression + edge cases |
test_js_adapter.py | 63 | JS/TS adapter, E2E pipeline, CLI routing |
test_reachability.py | 74 | Call-graph engine, fixtures, enrich_findings |
test_taint_analyzer.py | 65+ | Inter-procedural taint, sanitizer recognition |
test_supply_chain.py | 62 | Lockfile parsers, OSV CVE, risk scoring, SBOM |
test_attestation.py | 60 | AttestationEngine, ECDSA-P256, Dilithium3 PQ |
test_exploit_verifier.py | 59 | Docker sandbox, 3-tier verdict |
test_fastapi_app.py | 32 | FastAPI TestClient — all v1 endpoints |
test_chaos.py | 13 | Postgres/Redis failure injection |
test_week1_completion.py | 42 | Fuzz/snapshot/perf-gate/mutation-killing |
| (+ 31 more files) | 1,536 | Additional coverage |
| TypeScript (Vitest) | 65 | Button, Badge, Card, ScanCard, FindingsTable… |
| RQ | Implementation | Metric |
|---|---|---|
| RQ1 Can RAG reduce LLM hallucination? | 66-rule KB + evidence-grounded prompts + entropy | consistency_score (0–1) |
| RQ2 How to ensure provenance? | Full PostgreSQL audit trail per LLM call | llm_explanations table |
| RQ3 What confidence scoring works? | score = severity × category × tool × rule × fix_validated | confidence_score (0–100) |
| RQ4 Does it match industry tools? | 10-tool pipeline vs CodeRabbit / SonarQube | Feature parity table above |
| Repository | Findings | Precision | Security Precision | Recall |
|---|---|---|---|---|
| DVPWA | 44 | 81.8% | 100% | 50% |
| Pygoat | 440 | 96.4% | 100% | 100% |
| VulPy | 293 | 100% | 100% | 100% |
| DSVW | 59 | 100% | 100% | 100% |
| Overall | 836 | 97.1% | 100% | — |
DVPWA recall 50%: 3 of 6 known vulns detected; CSRF (runtime-only), hardcoded debug mode, and one abstracted cred require DAST — documented limitation, not a bug.
Key design decisions are documented in docs/adr/:
| ADR | Decision |
|---|---|
| 0001 | Scope: self-hosted thesis tool, not SaaS |
| 0002 | LanguageAdapter pattern for multi-language support |
| 0003 | RAG + semantic entropy over generic LLM prompts |
| 0004 | Groq free tier with 4-key rotation pool |
| 0005 | PostgreSQL for provenance storage |
| Layer | Technology |
|---|---|
| Language | Python 3.11+ |
| Web Framework | FastAPI 0.115 (async) |
| Frontend | React 18 + TypeScript + Vite 5 + shadcn/ui |
| Database | PostgreSQL 15 |
| Cache / Rate Limiting | Redis 7 |
| AI Model | Groq Llama 3.3-70b (explanations) · Llama 3.1-8b (feasibility) |
| Static Analysis | Ruff, Semgrep, Bandit, Vulture, Radon, gosec, staticcheck, ESLint |
| Terminal UI | Rich |
| Schema Validation | Pydantic v2 |
| Containerisation | Docker + Docker Compose |
| Monitoring | Prometheus + Grafana |
| CI/CD | GitHub Actions + GitLab CI |
| Export Formats | SARIF v2.1.0, Markdown, JSON |
Run these Marimo notebooks locally or view the exported HTML:
| Notebook | Description | HTML Preview |
|---|---|---|
notebooks/walkthrough.py | 12-cell full pipeline walkthrough | walkthrough.html |
notebooks/engine_demos/taint.py | Taint analyzer — source→sink data-flow | demo_taint.html |
notebooks/engine_demos/exploit.py | Exploit verifier — DAST-in-Docker | demo_exploit.html |
notebooks/engine_demos/attestation.py | Attestation + post-quantum hybrid signatures | demo_attestation.html |
notebooks/engine_demos/offline.py | Zero-egress / Ollama mode proof | demo_offline.html |
# Run interactively (edit cells live)
pip install marimo
marimo run notebooks/walkthrough.py
# Or open in edit mode for defense demo
marimo edit notebooks/walkthrough.py
| Document | Description |
|---|---|
| C1–C4 Architecture | Full C4 model: context, containers, components, code flow |
| ADRs | Architecture decision records — why each major choice was made |
| API Reference | All 32 REST endpoints |
| Policy Engine | .acrqa.yml full reference |
| Evaluation Report | Precision/recall, OWASP coverage, competitive analysis |
| Per-Tool Evaluation | Per-engine accuracy across benchmark repos |
| User Study Protocol | 20-minute structured study protocol |
| Cloud Deployment | AWS / GCP / Railway deployment guide |
| Changelog | Full version history |
| Contributing | Development setup and contribution guide |
| Student | Ahmed Mahmoud Abbas |
| Supervisor | Dr. Samy AbdelNabi |
| Institution | King Salman International University (KSIU) |
| Timeline | October 2025 – June 2026 |
| Status | v4.6.0 · Distribution release · Evaluation complete · Cloud-deployed · 39/39 tasks done |
docs/evaluation/USER_STUDY_PROTOCOL.mdMIT — see LICENSE
Built with ❤️ at King Salman International University · ⭐ Star this repo
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
fastapiEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | fastapi>=0.115.0 | runtime |
uvicornEnvironment{
"extras": "standard",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | uvicorn[standard]>=0.30.6 | runtime |
pydanticEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pydantic>=2.12.5 | runtime |
pydantic-settingsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pydantic-settings>=2.3.4 | runtime |
groqEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | groq>=1.2.0 | runtime |
httpxEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | httpx>=0.28.1 | runtime |
PyYAMLEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | PyYAML>=6.0.1 | runtime |
python-dotenvEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | python-dotenv>=1.0.0 | runtime |
passlibEnvironment{
"extras": "bcrypt",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | passlib[bcrypt]>=1.7.4 | runtime |
python-joseEnvironment{
"extras": "cryptography",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | python-jose[cryptography]>=3.3.0 | runtime |
psycopg2-binaryEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | psycopg2-binary>=2.9.9 | runtime |
redisEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | redis>=5.2.1 | runtime |
celeryEnvironment{
"extras": "redis",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | celery[redis]>=5.4.0 | runtime |
alembicEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | alembic>=1.13.1 | runtime |
richEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | rich>=13.7.0 | runtime |
clickEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | click>=8.1.7 | runtime |
sentence-transformersEnvironment{
"extras": "",
"marker": "extra == \"ai\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | sentence-transformers>=2.7.0; extra == "ai" | runtime |
torchEnvironment{
"extras": "",
"marker": "extra == \"ai\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | torch>=2.2.0; extra == "ai" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest>=8.2.0; extra == "dev" | runtime |
ruffEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | ruff>=0.6.0; extra == "dev" | runtime |
mypyEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | mypy>=1.10.0; extra == "dev" | runtime |
bdist_wheel · 173.94 KB · Python py3
sdist · 214.05 KB · Python source
Observed since 20 Oct, 18:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:a42dea79e40f89031ba457dedffc9e8544372b44156abdfd95ae7bd7de27a793