API Reference
Python API documentation for using CodeQL Wrapper programmatically.
Overview
CodeQL Wrapper provides a Python API for integrating CodeQL analysis into your applications. The main entry points are the CodeQLAnalysisUseCase
and SarifUploadUseCase
classes.
Installation
from codeql_wrapper.domain.use_cases.codeql_analysis_use_case import CodeQLAnalysisUseCase
from codeql_wrapper.domain.entities.codeql_analysis import CodeQLAnalysisRequest
from codeql_wrapper.infrastructure.logger import get_logger
Basic Usage
import logging
from pathlib import Path
from codeql_wrapper.domain.use_cases.codeql_analysis_use_case import CodeQLAnalysisUseCase
from codeql_wrapper.domain.entities.codeql_analysis import CodeQLAnalysisRequest
from codeql_wrapper.infrastructure.logger import get_logger
from codeql_wrapper.infrastructure.git_utils import GitInfo
# Set up logging
logger = get_logger(__name__, level=logging.INFO)
# Create use case instance
analysis_use_case = CodeQLAnalysisUseCase(logger)
# Create analysis request
request = CodeQLAnalysisRequest(
repository_path=Path("/path/to/repository"),
git_info=GitInfo(working_dir=Path("/path/to/repository"), branch="main", commit_sha="abcdef12345"),
output_directory=Path("/path/to/output"),
verbose=True
)
# Execute analysis
try:
result = analysis_use_case.execute(request)
print(f"Analysis completed: {result.success_rate:.2%} success rate")
print(f"Total findings: {result.total_findings}")
except Exception as e:
print(f"Analysis failed: {e}")
Core Classes
CodeQLAnalysisRequest
Represents a request for CodeQL analysis.
@dataclass
class CodeQLAnalysisRequest:
repository_path: Path
git_info: GitInfo
force_install: bool = False
target_languages: Optional[Set[CodeQLLanguage]] = None
verbose: bool = False
output_directory: Optional[Path] = None
monorepo: bool = False
build_mode: Optional[str] = None
build_script: Optional[Path] = None
queries: Optional[List[str]] = None
max_workers: Optional[int] = None
only_changed_files: bool = False
Properties
repository_path: Path
- Path to the repository to analyze.git_info: GitInfo
- Git information for the repository (e.g., branch, commit SHA).force_install: bool
- IfTrue
, forces reinstallation of CodeQL CLI even if already present. Defaults toFalse
.target_languages: Optional[Set[CodeQLLanguage]]
- A set of specific languages to analyze. IfNone
, all detected languages will be analyzed.verbose: bool
- IfTrue
, enables verbose logging for more detailed output. Defaults toFalse
.output_directory: Optional[Path]
- The directory where analysis results (SARIF files, databases) will be stored. IfNone
, results are stored in a default location within the project directory.monorepo: bool
- IfTrue
, treats the repository as a monorepo and attempts to detect multiple projects within it. Defaults toFalse
.build_mode: Optional[str]
- Specifies the build mode for compiled languages (e.g., "autobuild", "none").build_script: Optional[Path]
- Path to a custom build script to be executed before analysis for compiled languages.queries: Optional[List[str]]
- A list of CodeQL query suite paths or names to run. IfNone
, default queries are used.max_workers: Optional[int]
- The maximum number of parallel workers to use for analysis. IfNone
, an optimal number is calculated based on system resources.only_changed_files: bool
- IfTrue
, only analyzes projects that have changed files based on Git history. Defaults toFalse
.
RepositoryAnalysisSummary
Contains the aggregated results of a CodeQL analysis across all detected projects.
@dataclass
class RepositoryAnalysisSummary:
repository_path: Path
detected_projects: List[ProjectInfo]
analysis_results: List[CodeQLAnalysisResult]
total_findings: int = 0
successful_analyses: int = 0
failed_analyses: int = 0
error: Optional[str] = None
Properties
repository_path: Path
- The path to the repository that was analyzed.detected_projects: List[ProjectInfo]
- A list ofProjectInfo
objects representing all projects detected within the repository.analysis_results: List[CodeQLAnalysisResult]
- A list ofCodeQLAnalysisResult
objects, each containing the results for a single project's analysis.total_findings: int
- The total number of security findings across all successful analyses.successful_analyses: int
- The count of analyses that completed successfully.failed_analyses: int
- The count of analyses that failed.error: Optional[str]
- An aggregated error message if any top-level error occurred during the analysis process.success_rate: float
- The success rate of analyses (calculated assuccessful_analyses / total_analyses
).
CodeQLAnalysisResult
Results for a single project's CodeQL analysis.
@dataclass
class CodeQLAnalysisResult:
project_info: ProjectInfo
status: AnalysisStatus
start_time: datetime
end_time: Optional[datetime] = None
output_files: Optional[List[Path]] = None
error_message: Optional[str] = None
findings_count: int = 0
Properties
project_info: ProjectInfo
- Information about the specific project that was analyzed.status: AnalysisStatus
- The current status of the analysis (e.g.,PENDING
,RUNNING
,COMPLETED
,FAILED
).start_time: datetime
- The timestamp when the analysis started.end_time: Optional[datetime]
- The timestamp when the analysis ended.None
if still running or failed early.output_files: Optional[List[Path]]
- A list of paths to the output files generated by the analysis (e.g., SARIF files).error_message: Optional[str]
- A detailed error message if the analysis failed for this specific project.findings_count: int
- The number of security findings identified in this project's analysis.duration: float
- The duration of the analysis in seconds (calculated fromstart_time
andend_time
).
ProjectInfo
Information about a detected project within a repository.
@dataclass
class ProjectInfo:
repository_path: Path
project_path: Path
name: str
framework: Optional[str] = None
build_files: Optional[List[str]] = None
build_script: Optional[Path] = None
queries: Optional[List[str]] = None
non_compiled_languages: Set[CodeQLLanguage] = field(default_factory=set)
compiled_languages: Set[CodeQLLanguage] = field(default_factory=set)
target_language: Optional[CodeQLLanguage] = None
build_mode: Optional[str] = None
log_color: Optional[str] = None
Properties
repository_path: Path
- The root path of the Git repository containing the project.project_path: Path
- The absolute path to the project directory.name: str
- A human-readable name for the project.framework: Optional[str]
- Detected framework of the project (e.g., "React", "Spring").build_files: Optional[List[str]]
- List of detected build-related files (e.g.,pom.xml
,package.json
).build_script: Optional[Path]
- Path to a detected build script for the project.queries: Optional[List[str]]
- Specific CodeQL queries or query suites configured for this project.non_compiled_languages: Set[CodeQLLanguage]
- Set of non-compiled languages detected in the project (e.g., Python, JavaScript).compiled_languages: Set[CodeQLLanguage]
- Set of compiled languages detected in the project (e.g., Java, C#).target_language: Optional[CodeQLLanguage]
- The primary language targeted for analysis if specified.build_mode: Optional[str]
- The build mode used for the project (e.g., "autobuild", "none").log_color: Optional[str]
- ANSI escape code for logging output color, used for distinguishing project logs.
GitInfo
Information about the Git repository state.
@dataclass
class GitInfo:
working_dir: Path
branch: str
commit_sha: str
remote_url: Optional[str] = None
base_branch: Optional[str] = None
base_commit_sha: Optional[str] = None
Properties
working_dir: Path
- The working directory of the Git repository.branch: str
- The current branch name.commit_sha: str
- The full SHA of the current commit.remote_url: Optional[str]
- The URL of the remote Git repository.base_branch: Optional[str]
- The base branch for pull request analysis.base_commit_sha: Optional[str]
- The base commit SHA for pull request analysis.
Enumerations
CodeQLLanguage
Supported CodeQL languages:
class CodeQLLanguage(Enum):
JAVASCRIPT = "javascript"
TYPESCRIPT = "typescript"
PYTHON = "python"
JAVA = "java"
CSHARP = "csharp"
CPP = "cpp"
GO = "go"
RUBY = "ruby"
SWIFT = "swift"
KOTLIN = "kotlin"
ACTIONS = "actions"
AnalysisStatus
Analysis status values:
class AnalysisStatus(Enum):
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
SKIPPED = "skipped"
Advanced Usage
Monorepo Analysis
# Analyze a monorepo
request = CodeQLAnalysisRequest(
repository_path=Path("/path/to/monorepo"),
git_info=GitInfo(working_dir=Path("/path/to/monorepo"), branch="main", commit_sha="abcdef12345"),
monorepo=True,
output_directory=Path("/path/to/output")
)
result = analysis_use_case.execute(request)
# Process results for each project
for analysis_result in result.analysis_results:
project = analysis_result.project_info
print(f"Project: {project.name}")
# Note: project.languages is now split into non_compiled_languages and compiled_languages
print(f"Non-compiled Languages: {[lang.value for lang in project.non_compiled_languages]}")
print(f"Compiled Languages: {[lang.value for lang in project.compiled_languages]}")
print(f"Findings: {analysis_result.findings_count}")
print(f"Status: {analysis_result.status.value}")
Language Filtering
from codeql_wrapper.domain.entities.codeql_analysis import CodeQLLanguage, CodeQLAnalysisRequest
from codeql_wrapper.infrastructure.git_utils import GitInfo
# Analyze only Python and JavaScript
target_languages = {CodeQLLanguage.PYTHON, CodeQLLanguage.JAVASCRIPT}
request = CodeQLAnalysisRequest(
repository_path=Path("/path/to/repository"),
git_info=GitInfo(working_dir=Path("/path/to/repository"), branch="main", commit_sha="abcdef12345"),
target_languages=target_languages
)
result = analysis_use_case.execute(request)
Custom Output Processing
import json
# Analyze and process SARIF files
result = analysis_use_case.execute(request)
for analysis_result in result.analysis_results:
if analysis_result.output_files:
for output_file in analysis_result.output_files:
if output_file.suffix == ".sarif":
# Process SARIF file
with open(output_file, "r") as f:
sarif_data = json.load(f)
# Custom processing...
SARIF Upload
SarifUploadUseCase
Upload SARIF files to GitHub Code Scanning:
from codeql_wrapper.domain.use_cases.sarif_upload_use_case import SarifUploadUseCase
from codeql_wrapper.domain.entities.codeql_analysis import SarifUploadRequest
from pathlib import Path
# Create upload use case
upload_use_case = SarifUploadUseCase(logger)
# Create upload request
upload_request = SarifUploadRequest(
sarif_files=[Path("/path/to/results1.sarif"), Path("/path/to/results2.sarif")], # Note: sarif_files is a list
repository="owner/repo",
commit_sha="abc123",
ref="refs/heads/main",
github_token="your_token"
)
# Upload SARIF
try:
upload_result = upload_use_case.execute(upload_request)
if upload_result.success:
print("SARIF uploaded successfully")
else:
print(f"Upload failed: {upload_result.errors}")
except Exception as e:
print(f"Upload error: {e}")
SarifUploadResult
Result of SARIF upload operation.
@dataclass
class SarifUploadResult:
success: bool
successful_uploads: int
failed_uploads: int
total_files: int
errors: Optional[List[str]] = None
Properties
success: bool
-True
if all SARIF files were uploaded successfully,False
otherwise.successful_uploads: int
- The number of SARIF files successfully uploaded.failed_uploads: int
- The number of SARIF files that failed to upload.total_files: int
- The total number of SARIF files attempted to upload.errors: Optional[List[str]]
- A list of error messages for failed uploads.success_rate: float
- The success rate of the upload operation (calculated assuccessful_uploads / total_files
).
Error Handling
from codeql_wrapper.domain.entities.codeql_analysis import AnalysisStatus
try:
result = analysis_use_case.execute(request)
# Check overall result
if result.error:
print(f"Analysis error: {result.error}")
# Check individual results
for analysis_result in result.analysis_results:
if analysis_result.status == AnalysisStatus.FAILED:
print(f"Failed: {analysis_result.project_info.name}")
print(f"Error: {analysis_result.error_message}")
elif analysis_result.status == AnalysisStatus.COMPLETED:
print(f"Success: {analysis_result.project_info.name}")
print(f"Findings: {analysis_result.findings_count}")
except ValueError as e:
print(f"Invalid input: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Logging
Custom Logger Setup
from codeql_wrapper.infrastructure.logger import get_logger, configure_logging
import logging
# Configure global logging
configure_logging(verbose=True)
# Get logger for your module
logger = get_logger(__name__, level=logging.DEBUG)
# Use with analysis
analysis_use_case = CodeQLAnalysisUseCase(logger)
Examples
Complete Analysis Workflow
#!/usr/bin/env python3
"""
Complete CodeQL analysis workflow example
"""
import json
import logging
from pathlib import Path
from typing import List
from codeql_wrapper.domain.use_cases.codeql_analysis_use_case import CodeQLAnalysisUseCase
from codeql_wrapper.domain.entities.codeql_analysis import (
CodeQLAnalysisRequest,
CodeQLLanguage,
AnalysisStatus
)
from codeql_wrapper.infrastructure.logger import get_logger, configure_logging
from codeql_wrapper.infrastructure.git_utils import GitInfo
def analyze_repository(repo_path: str, output_dir: str) -> None:
"""Analyze a repository and generate report."""
# Configure logging
configure_logging(verbose=True)
logger = get_logger(__name__)
# Create analysis request
# Note: GitInfo is now a required parameter
request = CodeQLAnalysisRequest(
repository_path=Path(repo_path),
git_info=GitInfo(working_dir=Path(repo_path), branch="main", commit_sha="abcdef12345"), # Example GitInfo
output_directory=Path(output_dir),
verbose=True
)
# Create and execute analysis
analysis_use_case = CodeQLAnalysisUseCase(logger)
try:
result = analysis_use_case.execute(request)
# Generate summary report
report = {
"repository": str(result.repository_path),
"total_projects": len(result.detected_projects),
"total_analyses": len(result.analysis_results),
"successful_analyses": result.successful_analyses,
"success_rate": result.success_rate,
"total_findings": result.total_findings,
"projects": []
}
# Add project details
for analysis_result in result.analysis_results:
project_info = {
"name": analysis_result.project_info.name,
"path": str(analysis_result.project_info.project_path),
"non_compiled_languages": [lang.value for lang in analysis_result.project_info.non_compiled_languages],
"compiled_languages": [lang.value for lang in analysis_result.project_info.compiled_languages],
"status": analysis_result.status.value,
"findings": analysis_result.findings_count,
"duration": analysis_result.duration
}
if analysis_result.error_message:
project_info["error"] = analysis_result.error_message
if analysis_result.output_files:
project_info["output_files"] = [str(f) for f in analysis_result.output_files]
report["projects"].append(project_info)
# Save report
report_file = Path(output_dir) / "analysis-report.json"
with open(report_file, "w") as f:
json.dump(report, f, indent=2)
print(f"Analysis completed: {result.success_rate:.2%} success rate")
print(f"Report saved to: {report_file}")
except Exception as e:
logger.error(f"Analysis failed: {e}")
raise
if __name__ == "__main__":
import sys
if len(sys.argv) != 3:
print("Usage: python analyze.py <repo_path> <output_dir>")
sys.exit(1)
analyze_repository(sys.argv[1], sys.argv[2])