Add source code files
This commit is contained in:
202
src/codeguard/cli/__init__.py
Normal file
202
src/codeguard/cli/__init__.py
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
"""CLI module for CodeGuard."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from codeguard.core.scanner import CodeScanner
|
||||||
|
from codeguard.git.hooks import HookManager
|
||||||
|
from codeguard.utils.config import ConfigLoader
|
||||||
|
from codeguard.utils.output import OutputFormatter
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
@click.option(
|
||||||
|
"--ollama-url",
|
||||||
|
default="http://localhost:11434",
|
||||||
|
help="Ollama server URL",
|
||||||
|
envvar="CODEGUARD_OLLAMA_URL",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--model",
|
||||||
|
default="codellama",
|
||||||
|
help="Ollama model to use",
|
||||||
|
envvar="CODEGUARD_MODEL",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--timeout",
|
||||||
|
default=120,
|
||||||
|
help="Request timeout in seconds",
|
||||||
|
envvar="CODEGUARD_TIMEOUT",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--config",
|
||||||
|
default="codeguard.yaml",
|
||||||
|
help="Path to config file",
|
||||||
|
envvar="CODEGUARD_CONFIG",
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def main(
|
||||||
|
ctx: click.Context,
|
||||||
|
ollama_url: str,
|
||||||
|
model: str,
|
||||||
|
timeout: int,
|
||||||
|
config: str,
|
||||||
|
) -> None:
|
||||||
|
"""CodeGuard: Local LLM-based code security analysis."""
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
ctx.obj["ollama_url"] = ollama_url
|
||||||
|
ctx.obj["model"] = model
|
||||||
|
ctx.obj["timeout"] = timeout
|
||||||
|
ctx.obj["config"] = config
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.option(
|
||||||
|
"--path",
|
||||||
|
default=".",
|
||||||
|
help="Path to scan",
|
||||||
|
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--output",
|
||||||
|
type=click.Choice(["text", "json"]),
|
||||||
|
default="text",
|
||||||
|
help="Output format",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--fail-level",
|
||||||
|
type=click.Choice(["critical", "high", "medium", "low", "none"]),
|
||||||
|
default="none",
|
||||||
|
help="Exit with error if findings at or above this level",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--include",
|
||||||
|
multiple=True,
|
||||||
|
help="File patterns to include",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--exclude",
|
||||||
|
multiple=True,
|
||||||
|
help="File patterns to exclude",
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def scan(
|
||||||
|
ctx: click.Context,
|
||||||
|
path: str,
|
||||||
|
output: str,
|
||||||
|
fail_level: str,
|
||||||
|
include: tuple,
|
||||||
|
exclude: tuple,
|
||||||
|
) -> None:
|
||||||
|
"""Scan code for security vulnerabilities."""
|
||||||
|
config = ConfigLoader.load(ctx.obj["config"])
|
||||||
|
scanner = CodeScanner(
|
||||||
|
ollama_url=ctx.obj["ollama_url"],
|
||||||
|
model=ctx.obj["model"],
|
||||||
|
timeout=ctx.obj["timeout"],
|
||||||
|
config=config,
|
||||||
|
)
|
||||||
|
findings = scanner.scan(path, include=list(include), exclude=list(exclude))
|
||||||
|
OutputFormatter.print(findings, output_format=output)
|
||||||
|
if fail_level != "none":
|
||||||
|
severity_levels = ["low", "medium", "high", "critical"]
|
||||||
|
fail_index = severity_levels.index(fail_level)
|
||||||
|
for finding in findings:
|
||||||
|
if finding.severity.value in severity_levels[: fail_index + 1]:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.option(
|
||||||
|
"--path",
|
||||||
|
default=".",
|
||||||
|
help="Path to git repository",
|
||||||
|
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--force",
|
||||||
|
is_flag=True,
|
||||||
|
help="Force reinstall existing hook",
|
||||||
|
)
|
||||||
|
def install_hook(path: str, force: bool) -> None:
|
||||||
|
"""Install git pre-commit hook."""
|
||||||
|
manager = HookManager(path)
|
||||||
|
manager.install(force=force)
|
||||||
|
click.echo("Pre-commit hook installed successfully")
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.argument(
|
||||||
|
"paths",
|
||||||
|
nargs=-1,
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--output",
|
||||||
|
type=click.Choice(["text", "json"]),
|
||||||
|
default="text",
|
||||||
|
help="Output format",
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def check(
|
||||||
|
ctx: click.Context,
|
||||||
|
paths: tuple[str, ...],
|
||||||
|
output: str,
|
||||||
|
) -> None:
|
||||||
|
"""Check specific files for security issues."""
|
||||||
|
if not paths:
|
||||||
|
click.echo("No files specified", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
config = ConfigLoader.load(ctx.obj["config"])
|
||||||
|
scanner = CodeScanner(
|
||||||
|
ollama_url=ctx.obj["ollama_url"],
|
||||||
|
model=ctx.obj["model"],
|
||||||
|
timeout=ctx.obj["timeout"],
|
||||||
|
config=config,
|
||||||
|
)
|
||||||
|
findings = scanner.check_files(list(paths))
|
||||||
|
OutputFormatter.print(findings, output_format=output)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
def version() -> None:
|
||||||
|
"""Show version."""
|
||||||
|
from codeguard import __version__
|
||||||
|
click.echo(f"CodeGuard-CLI v{__version__}")
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.option(
|
||||||
|
"--ollama-url",
|
||||||
|
default=None,
|
||||||
|
help="Ollama server URL",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--model",
|
||||||
|
default=None,
|
||||||
|
help="Ollama model to use",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--timeout",
|
||||||
|
default=None,
|
||||||
|
help="Request timeout in seconds",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
def status(ollama_url: Optional[str], model: Optional[str], timeout: Optional[str]) -> None:
|
||||||
|
"""Check CodeGuard and Ollama status."""
|
||||||
|
from codeguard.llm.client import OllamaClient
|
||||||
|
|
||||||
|
url = ollama_url or "http://localhost:11434"
|
||||||
|
client = OllamaClient(url)
|
||||||
|
|
||||||
|
click.echo("Checking Ollama connection...")
|
||||||
|
if client.health_check():
|
||||||
|
click.secho("Ollama is running", fg="green")
|
||||||
|
else:
|
||||||
|
click.secho("Ollama is not accessible", fg="red")
|
||||||
|
return
|
||||||
|
|
||||||
|
click.echo(f"Available models: {', '.join(client.list_models())}")
|
||||||
Reference in New Issue
Block a user