From bbfcd4ea3940c5671be336eeff20143475507634 Mon Sep 17 00:00:00 2001 From: Tunay Engin Date: Sun, 21 Dec 2025 09:34:09 +0300 Subject: [PATCH 1/2] ! --- .gitignore | 5 + build/lib/openaudit/main.py | 2 +- dist/openaudit-0.1.0-py3-none-any.whl | Bin 9351 -> 0 bytes dist/openaudit-0.1.0.tar.gz | Bin 11057 -> 0 bytes openaudit.egg-info/PKG-INFO | 5 +- openaudit.egg-info/requires.txt | 4 + openaudit/ai/engine.py | 26 ++++ openaudit/features/explain/agent.py | 23 ++- openaudit/features/secrets/agent.py | 23 ++- openaudit/interface/cli/commands.py | 204 +++++++++++++------------- openaudit/interface/cli/ui.py | 62 ++++++++ openaudit/main.py | 2 +- pyproject.toml | 8 +- requirements.txt | 1 + 14 files changed, 256 insertions(+), 109 deletions(-) delete mode 100644 dist/openaudit-0.1.0-py3-none-any.whl delete mode 100644 dist/openaudit-0.1.0.tar.gz create mode 100644 openaudit/interface/cli/ui.py diff --git a/.gitignore b/.gitignore index 60455b1..f7faa0f 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,8 @@ test.env # Misc .DS_Store memory_bank.md +/openaudit.egg-info +/dist +*.whl +/openaudit.egg-info +openaudit.egg-info/PKG-INFO diff --git a/build/lib/openaudit/main.py b/build/lib/openaudit/main.py index 67a93c9..a35b2e0 100644 --- a/build/lib/openaudit/main.py +++ b/build/lib/openaudit/main.py @@ -2,7 +2,7 @@ import sys def main(): - print(f"DEBUG: sys.argv = {sys.argv}") + # Debug print removed app() if __name__ == "__main__": diff --git a/dist/openaudit-0.1.0-py3-none-any.whl b/dist/openaudit-0.1.0-py3-none-any.whl deleted file mode 100644 index b4b3fcc95884f366bb9ec6c847adeaaf434a1423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9351 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 diff --git a/dist/openaudit-0.1.0.tar.gz b/dist/openaudit-0.1.0.tar.gz deleted file mode 100644 index 8ed2dd73161430d3ecd93ea01228be0853aa58fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11057 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 diff --git a/openaudit.egg-info/PKG-INFO b/openaudit.egg-info/PKG-INFO index 8ce9edd..b3dac69 100644 --- a/openaudit.egg-info/PKG-INFO +++ b/openaudit.egg-info/PKG-INFO @@ -2,7 +2,7 @@ Metadata-Version: 2.4 Name: openaudit Version: 0.1.0 Summary: Offline-first security audit tool (secrets & config scanning) for local codebases. -Author-email: OpenAuditKit Team +Author-email: OpenAuditKit Team License: MIT Project-URL: Repository, https://github.com/neuralforgeone/OpenAuditKit Project-URL: Issues, https://github.com/neuralforgeone/OpenAuditKit/issues @@ -18,6 +18,9 @@ Requires-Dist: rich>=13.0.0 Requires-Dist: pydantic>=2.0.0 Requires-Dist: pathspec>=0.11.0 Requires-Dist: openai>=1.0.0 +Provides-Extra: dev +Requires-Dist: pytest>=7.0.0; extra == "dev" +Requires-Dist: pytest-cov>=4.0.0; extra == "dev" Dynamic: license-file # OpenAuditKit diff --git a/openaudit.egg-info/requires.txt b/openaudit.egg-info/requires.txt index 29d10d7..c673d36 100644 --- a/openaudit.egg-info/requires.txt +++ b/openaudit.egg-info/requires.txt @@ -4,3 +4,7 @@ rich>=13.0.0 pydantic>=2.0.0 pathspec>=0.11.0 openai>=1.0.0 + +[dev] +pytest>=7.0.0 +pytest-cov>=4.0.0 diff --git a/openaudit/ai/engine.py b/openaudit/ai/engine.py index 2b0f782..353bddb 100644 --- a/openaudit/ai/engine.py +++ b/openaudit/ai/engine.py @@ -48,3 +48,29 @@ def chat_completion(self, system_prompt: str, user_prompt: str, model: str = "gp # For now, let's log and re-raise to be handled by caller or CLI raise RuntimeError(f"OpenAI API Error: {str(e)}") + def chat_completion_stream(self, system_prompt: str, user_prompt: str, model: str = "gpt-4o"): + """ + Executes a chat completion request with streaming. + Yields chunks of the response content. + """ + if not self.client: + self._initialize_client() + if not self.client: + raise RuntimeError("OpenAI API key not configured. Run 'openaudit config set-key ' or set OPENAI_API_KEY env var.") + + try: + stream = self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt} + ], + temperature=0.2, + stream=True + ) + for chunk in stream: + if chunk.choices[0].delta.content: + yield chunk.choices[0].delta.content + except OpenAIError as e: + raise RuntimeError(f"OpenAI API Error: {str(e)}") + diff --git a/openaudit/features/explain/agent.py b/openaudit/features/explain/agent.py index ab841da..5ec0df0 100644 --- a/openaudit/features/explain/agent.py +++ b/openaudit/features/explain/agent.py @@ -37,10 +37,31 @@ def run(self, context: PromptContext) -> AIResult: is_advisory=True ) except Exception as e: - return AIResult( + return AIResult( analysis=f"Error: {str(e)}", risk_score=0.1, severity=Severity.LOW, confidence=Confidence.LOW, is_advisory=True ) + + def stream(self, context: PromptContext): + """ + Stream the explanation. + Yields chunks of text. + """ + from openaudit.ai.engine import AIEngine + engine = AIEngine() + + if not engine.is_available(): + yield "AI not configured. Please set API key." + return + + system_prompt = "You are a technical expert. Explain the code and identify security risks. Use Markdown." + user_prompt = f"Code:\n{context.code_snippet}\n\nExplain and Analyze." + + try: + for chunk in engine.chat_completion_stream(system_prompt, user_prompt): + yield chunk + except Exception as e: + yield f"\n\nError during streaming: {str(e)}" diff --git a/openaudit/features/secrets/agent.py b/openaudit/features/secrets/agent.py index 74c568f..94606ec 100644 --- a/openaudit/features/secrets/agent.py +++ b/openaudit/features/secrets/agent.py @@ -11,22 +11,33 @@ class SecretConfidenceAgent: def run(self, context: PromptContext) -> AIResult: from openaudit.ai.engine import AIEngine + engine = AIEngine() if not engine.is_available(): # No fallback, return None to indicate no analysis possible return None snippet = context.code_snippet - system_prompt = "You are a secret scanning expert. Analyze the context of a potential secret. Determine if it is a TEST/MOCK secret or a REAL production secret." - user_prompt = f"Code Context:\n{snippet}\n\nIs this a real secret? Answer with JSON: {{'is_test': bool, 'reason': str}}" + system_prompt = "You are a secret scanning expert. Analyze the context of a potential secret. Determine if it is a TEST/MOCK secret or a REAL production secret. Respond ONLY with valid JSON in the format: {\"is_test\": boolean, \"reason\": \"string\"}" + user_prompt = f"Code Context:\n{snippet}\n\nIs this a real secret?" try: + import json response = engine.chat_completion(system_prompt, user_prompt) - # Naive parsing for now - is_test = "true" in response.lower() and "is_test" in response.lower() + + # Clean up potential markdown formatting in response (e.g. ```json ... ```) + cleaned_response = response.strip() + if cleaned_response.startswith("```"): + cleaned_response = cleaned_response.strip("`") + if cleaned_response.startswith("json"): + cleaned_response = cleaned_response[4:] + + data = json.loads(cleaned_response) + is_test = data.get("is_test", False) + reason = data.get("reason", "No reason provided.") if is_test: return AIResult( - analysis="AI identified this as a likely TEST/MOCK secret.", + analysis=f"AI identified this as a likely TEST/MOCK secret. Reason: {reason}", risk_score=0.1, severity=Severity.LOW, confidence=Confidence.HIGH, @@ -35,7 +46,7 @@ def run(self, context: PromptContext) -> AIResult: ) else: return AIResult( - analysis="AI identified this as a likely REAL secret.", + analysis=f"AI identified this as a likely REAL secret. Reason: {reason}", risk_score=0.9, severity=Severity.HIGH, confidence=Confidence.HIGH, diff --git a/openaudit/interface/cli/commands.py b/openaudit/interface/cli/commands.py index 8c812f6..4a708e0 100644 --- a/openaudit/interface/cli/commands.py +++ b/openaudit/interface/cli/commands.py @@ -90,7 +90,6 @@ def scan_command( ConfigScanner(rules=rules) ] - # 4. Run Scan # 4. Run Scan all_findings = [] @@ -100,115 +99,127 @@ def scan_command( for scanner in scanners: all_findings.extend(scanner.scan(context)) else: - with typer.progressbar(scanners, label="Running Scanners") as progress: - for scanner in progress: + from openaudit.interface.cli.ui import UI + with UI.create_progress() as progress: + scan_task = progress.add_task("[green]Scanning...", total=len(scanners)) + for scanner in scanners: all_findings.extend(scanner.scan(context)) + progress.update(scan_task, advance=1) # 4.1 Run AI Agents if enabled if ai: - typer.echo("Running AI Agents...") - # Architecture Agent - arch_scanner = ArchitectureScanner() - structure = arch_scanner.scan(context) - - arch_agent = ArchitectureAgent() - # In a real scenario, we might use a proper AIEngine to look this up - result = arch_agent.run_on_structure(structure) - - if result and result.is_advisory: - # Convert AIResult to Finding - ai_finding = Finding( - rule_id=f"AI-{arch_agent.name.upper()}", - description=f"{result.analysis} Suggested: {result.suggestion}", - file_path="PROJECT_ROOT", - line_number=0, - secret_hash="", - severity=result.severity, - confidence=result.confidence, - category="architecture", - remediation=result.suggestion or "Review architecture.", - is_ai_generated=True - ) - all_findings.append(ai_finding) - - # Cross-File Agent - df_scanner = DataFlowScanner() - df_graph = df_scanner.scan(context, structure) + from openaudit.interface.cli.ui import UI - cross_agent = CrossFileAgent() - df_results = cross_agent.run_on_graph(df_graph) + UI.header("AI Analysis") - for res in df_results: - if res.is_advisory: - df_finding = Finding( - rule_id=f"AI-{cross_agent.name.upper()}", - description=f"{res.analysis} Suggested: {res.suggestion}", + # Architecture Agent + with UI.console.status("[bold blue]Analyzing Architecture...[/bold blue]"): + arch_scanner = ArchitectureScanner() + structure = arch_scanner.scan(context) + + arch_agent = ArchitectureAgent() + result = arch_agent.run_on_structure(structure) + + if result and result.is_advisory: + ai_finding = Finding( + rule_id=f"AI-{arch_agent.name.upper()}", + description=f"{result.analysis} Suggested: {result.suggestion}", file_path="PROJECT_ROOT", line_number=0, secret_hash="", - severity=res.severity, - confidence=res.confidence, + severity=result.severity, + confidence=result.confidence, category="architecture", - remediation=res.suggestion or "Secure data flow.", + remediation=result.suggestion or "Review architecture.", is_ai_generated=True ) - all_findings.append(df_finding) + all_findings.append(ai_finding) + + # Cross-File Agent + with UI.console.status("[bold purple]Analyzing Data Flow...[/bold purple]"): + df_scanner = DataFlowScanner() + df_graph = df_scanner.scan(context, structure) + + cross_agent = CrossFileAgent() + df_results = cross_agent.run_on_graph(df_graph) + + for res in df_results: + if res.is_advisory: + df_finding = Finding( + rule_id=f"AI-{cross_agent.name.upper()}", + description=f"{res.analysis} Suggested: {res.suggestion}", + file_path="PROJECT_ROOT", + line_number=0, + secret_hash="", + severity=res.severity, + confidence=res.confidence, + category="architecture", + remediation=res.suggestion or "Secure data flow.", + is_ai_generated=True + ) + all_findings.append(df_finding) # Threat Modeling Agent - threat_agent = ThreatModelingAgent() - tm_results = threat_agent.run_on_structure(structure) - for res in tm_results: - if res.is_advisory: - tm_finding = Finding( - rule_id=f"AI-THREAT-{res.analysis.split(':')[0]}", # Crude ID generation - description=f"{res.analysis} {res.suggestion}", - file_path="PROJECT_ROOT", - line_number=0, - secret_hash="", - severity=res.severity, - confidence=res.confidence, - category="architecture", - remediation=res.suggestion or "Mitigate threat.", - is_ai_generated=True - ) - all_findings.append(tm_finding) + with UI.console.status("[bold red]Modeling Threats...[/bold red]"): + threat_agent = ThreatModelingAgent() + tm_results = threat_agent.run_on_structure(structure) + for res in tm_results: + if res.is_advisory: + tm_finding = Finding( + rule_id=f"AI-THREAT-{res.analysis.split(':')[0]}", # Crude ID generation + description=f"{res.analysis} {res.suggestion}", + file_path="PROJECT_ROOT", + line_number=0, + secret_hash="", + severity=res.severity, + confidence=res.confidence, + category="architecture", + remediation=res.suggestion or "Mitigate threat.", + is_ai_generated=True + ) + all_findings.append(tm_finding) # Secret Confidence Agent - secret_agent = SecretConfidenceAgent() - for finding in all_findings: - if finding.category == "secret": - # Extract context - code_context = SecretContextExtractor.get_context(finding.file_path, finding.line_number) - if not code_context: - continue - - # Redact - redacted_context = Redactor.redact(code_context) - - # Analyze - ctx = PromptContext( - file_path=finding.file_path, - code_snippet=redacted_context, - line_number=finding.line_number - ) - - ai_result = secret_agent.run(ctx) + secret_findings = [f for f in all_findings if f.category == "secret"] + if secret_findings: + with UI.create_progress() as progress: + secret_task = progress.add_task("[cyan]Verifying Secrets with AI...", total=len(secret_findings)) + secret_agent = SecretConfidenceAgent() - if ai_result: - # Enrich Finding - finding.description += f" [AI: {ai_result.analysis}]" - finding.is_ai_generated = True # Tag enriched findings too + for finding in secret_findings: + # Extract context + code_context = SecretContextExtractor.get_context(finding.file_path, finding.line_number) + if not code_context: + progress.update(secret_task, advance=1) + continue - # If agent is very confident it's a false positive (test), downgrade - if ai_result.confidence == Confidence.LOW and ai_result.severity == Severity.LOW: - finding.confidence = Confidence.LOW - finding.severity = Severity.LOW - finding.description = f"[ADVISORY] {finding.description}" - + # Redact + redacted_context = Redactor.redact(code_context) + + # Analyze + ctx = PromptContext( + file_path=finding.file_path, + code_snippet=redacted_context, + line_number=finding.line_number + ) + + ai_result = secret_agent.run(ctx) + + if ai_result: + # Enrich Finding + finding.description += f" [AI: {ai_result.analysis}]" + finding.is_ai_generated = True # Tag enriched findings too + + # If agent is very confident it's a false positive (test), downgrade + if ai_result.confidence == Confidence.LOW and ai_result.severity == Severity.LOW: + finding.confidence = Confidence.LOW + finding.severity = Severity.LOW + finding.description = f"[ADVISORY] {finding.description}" + + progress.update(secret_task, advance=1) duration = time.time() - start_time - # 5. Report # 5. Report if format == OutputFormat.JSON: reporter = JSONReporter(output_path=output) @@ -241,9 +252,11 @@ def explain_command( """ Explain the code in a specific file using AI. """ + from openaudit.interface.cli.ui import UI + target_path = Path(path).absolute() if not target_path.exists() or not target_path.is_file(): - typer.echo(f"Error: path {path} does not exist or is not a file.") + UI.error(f"Error: path {path} does not exist or is not a file.") raise typer.Exit(code=1) # Check Consent @@ -252,7 +265,7 @@ def explain_command( if confirm: ConsentManager.grant_consent() else: - typer.echo("Consent refused. Exiting.") + UI.warning("Consent refused. Exiting.") raise typer.Exit(code=1) # Read Content @@ -264,14 +277,9 @@ def explain_command( # Run Agent agent = ExplainAgent() context = PromptContext(code_snippet=redacted_content, file_path=str(target_path)) - result = agent.run(context) - # Output - typer.echo("") - typer.echo(f"🔍 Analysis for {target_path.name}") - typer.echo("=========================================") - typer.echo(result.analysis) - typer.echo("=========================================") + # Stream Output + UI.stream_markdown(agent.stream(context), title=f"Analysis for {target_path.name}") # Config Commands diff --git a/openaudit/interface/cli/ui.py b/openaudit/interface/cli/ui.py new file mode 100644 index 0000000..479110f --- /dev/null +++ b/openaudit/interface/cli/ui.py @@ -0,0 +1,62 @@ +from rich.console import Console +from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn +from rich.live import Live +from rich.panel import Panel +from rich.markdown import Markdown +from typing import Generator, Optional +import time + +class UI: + """ + Centralized UI handler using Rich. + """ + console = Console() + + @staticmethod + def print(text: str, style: str = None): + UI.console.print(text, style=style) + + @staticmethod + def header(title: str): + UI.console.rule(f"[bold blue]{title}[/bold blue]") + + @staticmethod + def success(message: str): + UI.console.print(f"[bold green]✓[/bold green] {message}") + + @staticmethod + def error(message: str): + UI.console.print(f"[bold red]✗[/bold red] {message}") + + @staticmethod + def warning(message: str): + UI.console.print(f"[bold yellow]![/bold yellow] {message}") + + @staticmethod + def create_progress(): + return Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + BarColumn(), + TaskProgressColumn(), + console=UI.console + ) + + @staticmethod + def stream_markdown(content_generator: Generator[str, None, None], title: str = "Analysis"): + """ + Streams markdown content nicely. + """ + with Live(console=UI.console, refresh_per_second=10) as live: + accumulated_text = "" + for chunk in content_generator: + accumulated_text += chunk + markdown = Markdown(accumulated_text) + panel = Panel(markdown, title=title, border_style="blue") + live.update(panel) + + # Final render + markdown = Markdown(accumulated_text) + panel = Panel(markdown, title=title, border_style="green") + live.update(panel) + return accumulated_text diff --git a/openaudit/main.py b/openaudit/main.py index 67a93c9..a35b2e0 100644 --- a/openaudit/main.py +++ b/openaudit/main.py @@ -2,7 +2,7 @@ import sys def main(): - print(f"DEBUG: sys.argv = {sys.argv}") + # Debug print removed app() if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 6ba8b99..c60f176 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" requires-python = ">=3.9" license = { text = "MIT" } authors = [ - { name = "OpenAuditKit Team", email = "info@openauditkit.org" } + { name = "OpenAuditKit Team", email = "info@neuralforge.one" } ] urls = { Repository = "https://github.com/neuralforgeone/OpenAuditKit", Issues = "https://github.com/neuralforgeone/OpenAuditKit/issues" } classifiers = [ @@ -27,6 +27,12 @@ dependencies = [ "openai>=1.0.0" ] +[project.optional-dependencies] +dev = [ + "pytest>=7.0.0", + "pytest-cov>=4.0.0" +] + [project.scripts] openaudit = "openaudit.main:main" diff --git a/requirements.txt b/requirements.txt index cb31f29..de77b39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,6 @@ pyyaml>=6.0 rich>=13.0.0 pydantic>=2.0.0 pathspec>=0.11.0 +openai>=1.0.0 pytest>=7.0.0 pytest-cov>=4.0.0 From dd7dac128bc9cfdb2f16fdc75ad225b7b492d19a Mon Sep 17 00:00:00 2001 From: Tunay Engin Date: Sun, 21 Dec 2025 09:40:34 +0300 Subject: [PATCH 2/2] ! --- README.md | 162 ++++++++++++------------- build/lib/openaudit/__init__.py | 1 - build/lib/openaudit/main.py | 9 -- build/lib/openaudit/rules/config.yaml | 67 ---------- build/lib/openaudit/rules/secrets.yaml | 18 --- openaudit.egg-info/PKG-INFO | 162 ++++++++++++------------- 6 files changed, 158 insertions(+), 261 deletions(-) delete mode 100644 build/lib/openaudit/__init__.py delete mode 100644 build/lib/openaudit/main.py delete mode 100644 build/lib/openaudit/rules/config.yaml delete mode 100644 build/lib/openaudit/rules/secrets.yaml diff --git a/README.md b/README.md index 1d8f601..47129bd 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,91 @@ -# OpenAuditKit +
-OpenAuditKit is an open-source CLI security audit tool designed to scan your codebase for secrets and configuration vulnerabilities. It emphasizes offline capability, modular design, and secure handling of sensitive data (secret masking). +OpenAuditKit Logo -## Features -- **Secret Scanning**: Detects API keys and secrets using regex and entropy checks. -- **Config Scanning**: Identifies misconfigurations in deployment files (e.g., .env, Dockerfile). -- **Secure**: Secrets are masked in outputs; offline-first design. -- **Backend Ready**: Feature-based architecture with Pydantic models for easy integration into dashboards or APIs. -- **Customizable**: Add your own rules! See [Rule Documentation](openopenaudit/rules/README.md). +# OpenAuditKit -## 🛡️ Why OpenAuditKit? +[![PyPI version](https://badge.fury.io/py/openaudit.svg)](https://badge.fury.io/py/openaudit) +[![Python Versions](https://img.shields.io/pypi/pyversions/openaudit.svg)](https://pypi.org/project/openaudit/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Powered by NeuralForge](https://img.shields.io/badge/Powered%20by-NeuralForge.one-dark)](https://neuralforge.one) +**Next-Gen Security Audit Tool for Modern Codebases.** +*Powered by AI. Secure by Design. Offline First.* -## 🎥 Usage Demo +[🌐 Website](https://neuralforge.one) • [📚 Documentation](https://github.com/neuralforgeone/OpenAuditKit) • [🐛 Report Bug](https://github.com/neuralforgeone/OpenAuditKit/issues) -![OpenAuditKit Demo](path/to/demo.gif) -*(Replace this with your actual usage GIF)* +
-## Usage +--- -### Basic Scan -```bash -openaudit scan . -``` +## � What is OpenAuditKit? -### 🧠 AI-Powered Analysis -Unlock advanced capabilities by configuring your OpenAI API key: +**OpenAuditKit** is not just another linter. It's an intelligent security companion that lives in your terminal. Unlike traditional tools that drown you in false positives, OpenAuditKit combines robust pattern matching (Regex & Entropy) with **Context-Aware AI Agents** to understand *why* a piece of code might be dangerous. -```bash -# 1. Configure API Key -openaudit config set-key sk-your-key-here +Whether you are a solo developer or part of a large enterprise, OpenAuditKit helps you ship secure code faster. -# 2. Run Scan with AI Agents -openaudit scan . --ai +## ✨ Key Features -# 3. Explain a specific file -openaudit explain openaudit/main.py -``` +| Feature | Description | +| :--- | :--- | +| **🕵️ Secret Scanning** | Detects API keys, tokens, and credentials with high-entropy validation. | +| **⚙️ Config Audit** | Discovers misconfigurations in `Dockerfile`, `.env`, `Kubernetes`, and more. | +| **🧠 AI Advisory** | **(New)** Integrated AI Agents explain vulnerabilities and suggest fixes. | +| **🏗️ Architecture Analysis** | AI agents analyze your project structure for design flaws. | +| **🛡️ Threat Modeling** | auto-generates STRIDE threat models based on your codebase. | +| **🔌 Integrations** | Native support for CI/CD pipelines (GitHub Actions, GitLab CI). | +| **📝 JSON Reporting** | Export findings for easy integration with dashboards like DefectDojo. | + +## 🚀 Installation -**AI Agents:** -- **Architecture Agent**: Reviews modularity and dependencies. -- **Cross-File Agent**: Traces dangerous data flows across modules. -- **Explain Agent**: Provides detailed code explanations. -- **Secret Agent**: Validates if found secrets are likely real or test data. -- **Threat Model Agent**: Generates a STRIDE threat model for your project structure. +Install simply via pip: -### JSON Output ```bash -openaudit scan . --format json --output report.json +pip install openaudit ``` -## 🛠 Features +## ⚡ Quick Start -- **Secret Scanning**: Detects API keys and secrets using regex and entropy checks. -- **Config Scanning**: Identifies misconfigurations in deployment files (e.g., .env, Dockerfile). -- **Secure**: Secrets are masked in outputs; offline-first design (unless AI is enabled). -- **Backend Ready**: Feature-based architecture with Pydantic models for easy integration into dashboards or APIs. -- **Customizable**: Add your own rules! See [Rule Documentation](openaudit/rules/README.md). +### 1. Basic Scan +Run a security scan on your current directory: -## 🛡️ Why OpenAuditKit? +```bash +openaudit scan . +``` -Often, security tools are either too simple (grep) or too complex (enterprise SAST). OpenAuditKit bridges the gap: +### 2. Enable AI Superpowers 🧠 +Unlock the full potential with AI agents that analyze architecture and data flow: -| Feature | OpenAuditKit | Gitleaks | TruffleHog | -| :--- | :---: | :---: | :---: | -| **Secret Scanning** | ✅ | ✅ | ✅ | -| **Config Scanning** | ✅ | ❌ | ❌ | -| **Offline First** | ✅ | ✅ | ❌ (Often requires API) | -| **AI Analysis** | ✅ (Optional) | ❌ | ❌ | -| **Custom Rules** | ✅ (YAML) | ✅ (TOML) | ✅ (Detectors) | -| **Backend Integration** | ✅ (Pydantic Models) | ❌ | ❌ | +```bash +# Set your OpenAI API Key +openaudit config set-key sk-your-api-key -### Security Philosophy -1. **Offline First**: No data leaves your machine unless you explicitly enable AI features. -2. **Confidence > Noise**: We use entropy checks and specific regexes to minimize false positives. -3. **Actionable**: Every finding comes with a remediation step. +# Run an AI-enhanced scan +openaudit scan . --ai +``` -## Installation +### 3. Ask Your Code +Don't understand a complex file? Let the **Explain Agent** break it down: ```bash -# From PyPI -pip install openaudit - -# From Source -git clone https://github.com/neuralforgeone/OpenAuditKit.git -cd OpenAuditKit -pip install . +openaudit explain src/complex_logic.py ``` -## 🚀 CI/CD Integration +## 📊 Comparison -OpenAuditKit is designed to run in CI/CD pipelines. Use the `--ci` flag to enable CI mode (exit code 1 on failure, no interactive elements). +| Feature | OpenAuditKit | Gitleaks | TruffleHog | +| :--- | :---: | :---: | :---: | +| **Finding Secrets** | ✅ | ✅ | ✅ | +| **Config Analysis** | ✅ | ❌ | ❌ | +| **AI Context Analysis** | ✅ | ❌ | ❌ | +| **Architecture Review** | ✅ | ❌ | ❌ | +| **Offline Capabilities** | ✅ | ✅ | ❌* | + +*\*TruffleHog often requires API connectivity for verification.* -### GitHub Actions Example +## 🤖 CI/CD Integration -Create `.github/workflows/audit.yml`: +Secure your pipeline with zero effort. Add this to your `.github/workflows/security.yml`: ```yaml name: Security Audit @@ -104,24 +95,29 @@ jobs: openaudit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - run: pip install openaudit - - run: openaudit scan . --ci --fail-on high + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - run: pip install openaudit + - run: openaudit scan . --ci --fail-on high --ai + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Optional for AI features ``` -### Exit Codes -- `0`: No issues found (or issues below threshold). -- `1`: Issues found matching or exceeding severity threshold. +## 🛡️ Security Philosophy -## 🛠 Development & Testing +At **NeuralForge**, we believe security tools should be: +1. **Silent but Deadly:** Only alert on real issues (Low False Positives). +2. **Educational:** Don't just find bugs, explain them. +3. **Private:** Your code never leaves your machine unless you explicitly opt-in to AI features (which are redacted by default). -Run the test suite with coverage: -```bash -pip install -e .[dev] -pytest tests --cov=openaudit -``` +## 🤝 Contributing + +We love contributions! Please check out our [Contributing Guide](CONTRIBUTING.md) to get started. + +--- -We enforce a 90% test coverage threshold. +
+ Built with ❤️ by the NeuralForge Team. +
diff --git a/build/lib/openaudit/__init__.py b/build/lib/openaudit/__init__.py deleted file mode 100644 index 3dc1f76..0000000 --- a/build/lib/openaudit/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.1.0" diff --git a/build/lib/openaudit/main.py b/build/lib/openaudit/main.py deleted file mode 100644 index a35b2e0..0000000 --- a/build/lib/openaudit/main.py +++ /dev/null @@ -1,9 +0,0 @@ -from openaudit.interface.cli.app import app - -import sys -def main(): - # Debug print removed - app() - -if __name__ == "__main__": - main() diff --git a/build/lib/openaudit/rules/config.yaml b/build/lib/openaudit/rules/config.yaml deleted file mode 100644 index 923eba0..0000000 --- a/build/lib/openaudit/rules/config.yaml +++ /dev/null @@ -1,67 +0,0 @@ -rules: - # .env Rules - - id: "CONF_DEBUG_ENABLED" - description: "Debug mode enabled in configuration" - regex: "(?i)^\\s*DEBUG\\s*=\\s*(true|1|yes)" - severity: "high" - confidence: "high" - category: "config" - remediation: "Set DEBUG=False in production environments." - - - id: "CONF_DATABASE_URL_UNENCRYPTED" - description: "Plaintext database URL detected" - regex: "^\\s*DATABASE_URL\\s*=\\s*(postgres|mysql|mongodb)://" - severity: "high" - confidence: "high" - category: "config" - remediation: "Use encrypted secrets management or mask credentials." - - - id: "CONF_ENV_DEV_IN_PROD" - description: "Development environment setting detected" - regex: "(?i)^\\s*ENV\\s*=\\s*(dev|development)" - severity: "medium" - confidence: "high" - category: "config" - remediation: "Ensure this is not a production environment." - - # Dockerfile Rules - - id: "DOCKER_USER_ROOT" - description: "Container running as root" - regex: "^\\s*USER\\s+root" - severity: "high" - confidence: "high" - category: "infrastructure" - remediation: "Create and switch to a non-root user." - - - id: "DOCKER_EXPOSE_ALL" - description: "Exposing service on all interfaces (0.0.0.0)" - regex: "^\\s*EXPOSE\\s+.*0\\.0\\.0\\.0" - severity: "medium" - confidence: "high" - category: "infrastructure" - remediation: "Bind to specific interfaces if possible." - - - id: "DOCKER_ADD_COPY_ALL" - description: "Broad COPY instruction (COPY . /)" - regex: "^\\s*COPY\\s+\\.\\s+/" - severity: "low" - confidence: "medium" - category: "infrastructure" - remediation: "Use .dockerignore and copy only necessary files." - - # Docker Compose Rules (Regex approximation for simple detection, can be refined with yaml parsing) - - id: "COMPOSE_RESTART_ALWAYS" - description: "Restart policy set to always" - regex: "restart:\\s*always" - severity: "low" - confidence: "high" - category: "infrastructure" - remediation: "Consider 'on-failure' or specific restart policies." - - - id: "COMPOSE_PORT_EXPOSURE" - description: "Port exposed to host (broad range)" - regex: "\\s*-\\s*[\"']?0\\.0\\.0\\.0:" - severity: "medium" - confidence: "high" - category: "infrastructure" - remediation: "Bind ports to localhost (127.0.0.1) if external access is not required." diff --git a/build/lib/openaudit/rules/secrets.yaml b/build/lib/openaudit/rules/secrets.yaml deleted file mode 100644 index e349700..0000000 --- a/build/lib/openaudit/rules/secrets.yaml +++ /dev/null @@ -1,18 +0,0 @@ -rules: - - id: "AWS_ACCESS_KEY_ID" - description: "AWS Access Key ID" - regex: "(?:A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}" - entropy_check: false - severity: "critical" - confidence: "high" - category: "secret" - remediation: "Revoke the key immediately and rotate credentials." - - - id: "GENERIC_API_KEY" - description: "Potential High Entropy Key" - regex: "api_key['\"]?\\s*[:=]\\s*['\"]?([A-Za-z0-9_\\-]{32,})" - entropy_check: true - severity: "high" - confidence: "medium" - category: "secret" - remediation: "Verify if this is a real secret and move to environment variables." diff --git a/openaudit.egg-info/PKG-INFO b/openaudit.egg-info/PKG-INFO index b3dac69..8f0702d 100644 --- a/openaudit.egg-info/PKG-INFO +++ b/openaudit.egg-info/PKG-INFO @@ -23,103 +23,94 @@ Requires-Dist: pytest>=7.0.0; extra == "dev" Requires-Dist: pytest-cov>=4.0.0; extra == "dev" Dynamic: license-file -# OpenAuditKit +
-OpenAuditKit is an open-source CLI security audit tool designed to scan your codebase for secrets and configuration vulnerabilities. It emphasizes offline capability, modular design, and secure handling of sensitive data (secret masking). +OpenAuditKit Logo -## Features -- **Secret Scanning**: Detects API keys and secrets using regex and entropy checks. -- **Config Scanning**: Identifies misconfigurations in deployment files (e.g., .env, Dockerfile). -- **Secure**: Secrets are masked in outputs; offline-first design. -- **Backend Ready**: Feature-based architecture with Pydantic models for easy integration into dashboards or APIs. -- **Customizable**: Add your own rules! See [Rule Documentation](openopenaudit/rules/README.md). +# OpenAuditKit -## 🛡️ Why OpenAuditKit? +[![PyPI version](https://badge.fury.io/py/openaudit.svg)](https://badge.fury.io/py/openaudit) +[![Python Versions](https://img.shields.io/pypi/pyversions/openaudit.svg)](https://pypi.org/project/openaudit/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Powered by NeuralForge](https://img.shields.io/badge/Powered%20by-NeuralForge.1-blueviolet)](https://neuralforge.one) +**Next-Gen Security Audit Tool for Modern Codebases.** +*Powered by AI. Secure by Design. Offline First.* -## 🎥 Usage Demo +[🌐 Website](https://neuralforge.one) • [📚 Documentation](https://github.com/neuralforgeone/OpenAuditKit) • [🐛 Report Bug](https://github.com/neuralforgeone/OpenAuditKit/issues) -![OpenAuditKit Demo](path/to/demo.gif) -*(Replace this with your actual usage GIF)* +
-## Usage +--- -### Basic Scan -```bash -openaudit scan . -``` +## � What is OpenAuditKit? -### 🧠 AI-Powered Analysis -Unlock advanced capabilities by configuring your OpenAI API key: +**OpenAuditKit** is not just another linter. It's an intelligent security companion that lives in your terminal. Unlike traditional tools that drown you in false positives, OpenAuditKit combines robust pattern matching (Regex & Entropy) with **Context-Aware AI Agents** to understand *why* a piece of code might be dangerous. -```bash -# 1. Configure API Key -openaudit config set-key sk-your-key-here +Whether you are a solo developer or part of a large enterprise, OpenAuditKit helps you ship secure code faster. -# 2. Run Scan with AI Agents -openaudit scan . --ai +## ✨ Key Features -# 3. Explain a specific file -openaudit explain openaudit/main.py -``` +| Feature | Description | +| :--- | :--- | +| **🕵️ Secret Scanning** | Detects API keys, tokens, and credentials with high-entropy validation. | +| **⚙️ Config Audit** | Discovers misconfigurations in `Dockerfile`, `.env`, `Kubernetes`, and more. | +| **🧠 AI Advisory** | **(New)** Integrated AI Agents explain vulnerabilities and suggest fixes. | +| **🏗️ Architecture Analysis** | AI agents analyze your project structure for design flaws. | +| **🛡️ Threat Modeling** | auto-generates STRIDE threat models based on your codebase. | +| **🔌 Integrations** | Native support for CI/CD pipelines (GitHub Actions, GitLab CI). | +| **📝 JSON Reporting** | Export findings for easy integration with dashboards like DefectDojo. | + +## 🚀 Installation -**AI Agents:** -- **Architecture Agent**: Reviews modularity and dependencies. -- **Cross-File Agent**: Traces dangerous data flows across modules. -- **Explain Agent**: Provides detailed code explanations. -- **Secret Agent**: Validates if found secrets are likely real or test data. -- **Threat Model Agent**: Generates a STRIDE threat model for your project structure. +Install simply via pip: -### JSON Output ```bash -openaudit scan . --format json --output report.json +pip install openaudit ``` -## 🛠 Features +## ⚡ Quick Start -- **Secret Scanning**: Detects API keys and secrets using regex and entropy checks. -- **Config Scanning**: Identifies misconfigurations in deployment files (e.g., .env, Dockerfile). -- **Secure**: Secrets are masked in outputs; offline-first design (unless AI is enabled). -- **Backend Ready**: Feature-based architecture with Pydantic models for easy integration into dashboards or APIs. -- **Customizable**: Add your own rules! See [Rule Documentation](openaudit/rules/README.md). +### 1. Basic Scan +Run a security scan on your current directory: -## 🛡️ Why OpenAuditKit? +```bash +openaudit scan . +``` -Often, security tools are either too simple (grep) or too complex (enterprise SAST). OpenAuditKit bridges the gap: +### 2. Enable AI Superpowers 🧠 +Unlock the full potential with AI agents that analyze architecture and data flow: -| Feature | OpenAuditKit | Gitleaks | TruffleHog | -| :--- | :---: | :---: | :---: | -| **Secret Scanning** | ✅ | ✅ | ✅ | -| **Config Scanning** | ✅ | ❌ | ❌ | -| **Offline First** | ✅ | ✅ | ❌ (Often requires API) | -| **AI Analysis** | ✅ (Optional) | ❌ | ❌ | -| **Custom Rules** | ✅ (YAML) | ✅ (TOML) | ✅ (Detectors) | -| **Backend Integration** | ✅ (Pydantic Models) | ❌ | ❌ | +```bash +# Set your OpenAI API Key +openaudit config set-key sk-your-api-key -### Security Philosophy -1. **Offline First**: No data leaves your machine unless you explicitly enable AI features. -2. **Confidence > Noise**: We use entropy checks and specific regexes to minimize false positives. -3. **Actionable**: Every finding comes with a remediation step. +# Run an AI-enhanced scan +openaudit scan . --ai +``` -## Installation +### 3. Ask Your Code +Don't understand a complex file? Let the **Explain Agent** break it down: ```bash -# From PyPI -pip install openaudit - -# From Source -git clone https://github.com/neuralforgeone/OpenAuditKit.git -cd OpenAuditKit -pip install . +openaudit explain src/complex_logic.py ``` -## 🚀 CI/CD Integration +## 📊 Comparison -OpenAuditKit is designed to run in CI/CD pipelines. Use the `--ci` flag to enable CI mode (exit code 1 on failure, no interactive elements). +| Feature | OpenAuditKit | Gitleaks | TruffleHog | +| :--- | :---: | :---: | :---: | +| **Finding Secrets** | ✅ | ✅ | ✅ | +| **Config Analysis** | ✅ | ❌ | ❌ | +| **AI Context Analysis** | ✅ | ❌ | ❌ | +| **Architecture Review** | ✅ | ❌ | ❌ | +| **Offline Capabilities** | ✅ | ✅ | ❌* | + +*\*TruffleHog often requires API connectivity for verification.* -### GitHub Actions Example +## 🤖 CI/CD Integration -Create `.github/workflows/audit.yml`: +Secure your pipeline with zero effort. Add this to your `.github/workflows/security.yml`: ```yaml name: Security Audit @@ -129,24 +120,29 @@ jobs: openaudit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - run: pip install openaudit - - run: openaudit scan . --ci --fail-on high + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - run: pip install openaudit + - run: openaudit scan . --ci --fail-on high --ai + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Optional for AI features ``` -### Exit Codes -- `0`: No issues found (or issues below threshold). -- `1`: Issues found matching or exceeding severity threshold. +## 🛡️ Security Philosophy -## 🛠 Development & Testing +At **NeuralForge**, we believe security tools should be: +1. **Silent but Deadly:** Only alert on real issues (Low False Positives). +2. **Educational:** Don't just find bugs, explain them. +3. **Private:** Your code never leaves your machine unless you explicitly opt-in to AI features (which are redacted by default). -Run the test suite with coverage: -```bash -pip install -e .[dev] -pytest tests --cov=openaudit -``` +## 🤝 Contributing + +We love contributions! Please check out our [Contributing Guide](CONTRIBUTING.md) to get started. + +--- -We enforce a 90% test coverage threshold. +
+ Built with ❤️ by the NeuralForge Team. +