Skip to content
Open
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
190 changes: 190 additions & 0 deletions custom_context.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- =============================================================================
AutoFiC Team-Atlanta Style CUSTOM_CONTEXT XSD (v1.1)
============================================================================= -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:autofic:custom-context"
xmlns="urn:autofic:custom-context"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:element name="CUSTOM_CONTEXT">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="META" type="MetaType"/>
<xsd:element name="VULNERABILITY" type="VulnType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="version" type="xsd:string" use="required"/>
<xsd:attribute ref="xsi:schemaLocation" use="optional"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</xsd:complexType>
</xsd:element>

<xsd:complexType name="MetaType">
<xsd:attribute name="generatedAt" type="xsd:string" use="required"/>
<xsd:attribute name="tool" type="xsd:string" use="required"/>
<xsd:attribute name="count" type="xsd:nonNegativeInteger" use="required"/>
</xsd:complexType>

<xsd:complexType name="VulnType">
<xsd:sequence>
<xsd:element name="FILE" type="FileType"/>
<xsd:element name="RANGE" type="RangeType"/>
<xsd:element name="SEVERITY" type="SeverityType"/>
<xsd:element name="MESSAGE" type="MessageType"/>
<xsd:element name="SNIPPET" type="CDataString"/>

<xsd:element name="BIT" type="BitType"/>

<xsd:element name="CLASSES" type="ClassesType" minOccurs="0"/>
<xsd:element name="WEAKNESSES" type="WeaknessesType" minOccurs="0"/>
<xsd:element name="REFERENCES" type="ReferencesType" minOccurs="0"/>
<xsd:element name="SOURCE" type="SourceType" minOccurs="0"/>
<xsd:element name="EVIDENCE" type="EvidenceType" minOccurs="0"/>
<xsd:element name="PRECONDITIONS" type="StringListType" minOccurs="0"/>
<xsd:element name="ENV" type="EnvType" minOccurs="0"/>
<xsd:element name="MITIGATION" type="MitigationType" minOccurs="0"/>
<xsd:element name="TRACKING" type="TrackingType" minOccurs="0"/>
<xsd:element name="CONTEXT" type="ContextType" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="FileType">
<xsd:attribute name="path" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="RangeType">
<xsd:attribute name="start" type="xsd:positiveInteger" use="required"/>
<xsd:attribute name="end" type="xsd:positiveInteger" use="required"/>
</xsd:complexType>

<xsd:complexType name="SeverityType">
<xsd:attribute name="overall" type="xsd:string" use="required"/>
<xsd:attribute name="bit" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="MessageType" mixed="true">
<xsd:sequence minOccurs="0">
<xsd:element name="MESSAGES" type="StringListType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="BitType">
<xsd:sequence>
<xsd:element name="TRIGGER" type="CDataString"/>
<xsd:element name="STEPS" type="StepsType"/>
<xsd:element name="REPRODUCTION" type="CDataString"/>
<xsd:element name="BIT_SEVERITY" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="StepsType">
<xsd:sequence>
<xsd:element name="STEP" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ClassesType">
<xsd:sequence>
<xsd:element name="CLASS" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="WeaknessesType">
<xsd:sequence>
<xsd:element name="CWE" type="CweType" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="CweType">
<xsd:attribute name="id" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="ReferencesType">
<xsd:sequence>
<xsd:element name="REF" type="RefType" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="RefType">
<xsd:attribute name="href" type="xsd:anyURI" use="required"/>
</xsd:complexType>

<xsd:complexType name="SourceType">
<xsd:attribute name="tool" type="xsd:string" use="optional"/>
<xsd:attribute name="id" type="xsd:string" use="optional"/>
<xsd:attribute name="helpUri" type="xsd:anyURI" use="optional"/>
</xsd:complexType>

<xsd:complexType name="EvidenceType">
<xsd:sequence>
<xsd:element name="SINK" type="PointType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="SOURCE" type="PointType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="FLOW" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="PointType">
<xsd:attribute name="line" type="xsd:positiveInteger" use="optional"/>
<xsd:attribute name="symbol" type="xsd:string" use="optional"/>
<xsd:attribute name="taint" type="xsd:string" use="optional"/>
</xsd:complexType>

<xsd:complexType name="StringListType">
<xsd:sequence>
<xsd:element name="ITEM" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="EnvType">
<xsd:sequence>
<xsd:element name="RUNTIME" type="RuntimeType" minOccurs="0"/>
<xsd:element name="DEPENDENCY" type="DependencyType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="RuntimeType">
<xsd:attribute name="node" type="xsd:string" use="optional"/>
<xsd:attribute name="os" type="xsd:string" use="optional"/>
</xsd:complexType>

<xsd:complexType name="DependencyType">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="version" type="xsd:string" use="optional"/>
</xsd:complexType>

<xsd:complexType name="MitigationType">
<xsd:sequence>
<xsd:element name="SUMMARY" type="xsd:string" minOccurs="1"/>
<xsd:element name="CODE_HINT" type="CDataString" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="TrackingType">
<xsd:sequence>
<xsd:element name="ISSUE" type="IssueType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="COMMIT" type="CommitType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="IssueType">
<xsd:attribute name="key" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="CommitType">
<xsd:attribute name="hash" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="ContextType">
<xsd:attribute name="before" type="xsd:nonNegativeInteger" use="required"/>
<xsd:attribute name="after" type="xsd:nonNegativeInteger" use="required"/>
</xsd:complexType>

<xsd:complexType name="CDataString" mixed="true">
<xsd:simpleContent>
<xsd:extension base="xsd:string"/>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>
135 changes: 111 additions & 24 deletions src/autofic_core/cli.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,122 @@
from __future__ import annotations

from pathlib import Path
from typing import Optional

import click
from autofic_core.app import AutoFiCApp

SAST_TOOL_CHOICES = ['semgrep', 'codeql', 'snykcode']
from autofic_core.pipeline import AutoFiCPipeline


@click.command()
@click.option('--explain', is_flag=True, help="Print AutoFiC usage guide.")
@click.option('--repo', required=False, help="Target GitHub repository URL to analyze (required).")
@click.option('--save-dir', required=False, default="artifacts/downloaded_repo", help="Directory to save analysis results.")
def _echo_cfg(repo_url, save_dir, sast_tool, run_llm, llm_retry, run_patch, run_pr, xsd_path):
click.echo("AutoFiC - launching pipeline with the following options:\n")
click.echo(f" Repo URL : {repo_url}")
click.echo(f" Save dir : {save_dir}")
click.echo(f" SAST tool : {sast_tool}")
click.echo(f" LLM enabled : {run_llm} (retry={llm_retry})")
click.echo(f" Patch enabled : {run_patch}")
click.echo(f" PR enabled : {run_pr}")
click.echo(f" XSD path : {xsd_path if xsd_path else '(none)'}")
click.echo("")


@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
@click.option(
"--repo",
"repo_url",
required=True,
help="Target GitHub repository URL. e.g., https://github.com/org/project",
)
@click.option(
"--save-dir",
type=click.Path(path_type=Path, file_okay=False, dir_okay=True, writable=True),
default=Path("./artifacts"),
show_default=True,
help="Directory to store outputs (snippets, XML, LLM responses, patches).",
)
@click.option(
'--sast',
type=click.Choice(SAST_TOOL_CHOICES, case_sensitive=False),
required=False,
help='Select SAST tool to use (choose one of: semgrep, codeql, snykcode).'
"--sast",
"sast_tool",
type=click.Choice(["semgrep", "codeql", "snykcode"], case_sensitive=False),
default="semgrep",
show_default=True,
help="Choose SAST tool (legacy style): --sast <semgrep|codeql|snykcode>.",
)
@click.option('--llm', is_flag=True, help="Run LLM to fix vulnerable code and save responses.")
@click.option('--llm-retry', is_flag=True, help="Re-run LLM for final verification and fixes.")
@click.option('--patch', is_flag=True, help="Generate diffs and apply patches using git.")
@click.option('--pr', is_flag=True, help="Automatically create a pull request.")
@click.option(
"--llm/--no-llm",
"run_llm",
default=True,
show_default=True,
help="Run LLM stage after SAST & XML.",
)
@click.option(
"--retry",
"llm_retry",
is_flag=True,
default=False,
help="Use retry directories (retry_llm/retry_parsed/retry_patch).",
)
@click.option(
"--patch/--no-patch",
"run_patch",
default=True,
show_default=True,
help="Generate unified diffs and attempt to apply patches.",
)
@click.option(
"--pr/--no-pr",
"run_pr",
default=False,
show_default=True,
help="(Reserved) Create a PR automatically. (Not wired in this CLI)",
)
@click.option(
"--xsd",
"xsd_path",
type=click.Path(path_type=Path, exists=True, dir_okay=False),
default=None,
help="Path to custom_context.xsd for XML validation (optional). If omitted, CLI will look for ./custom_context.xsd.",
)
def main(
repo_url: str,
save_dir: Path,
sast_tool: str,
run_llm: bool,
llm_retry: bool,
run_patch: bool,
run_pr: bool,
xsd_path: Optional[Path],
) -> None:
"""
AutoFiC — run pipeline end-to-end (legacy CLI).

Examples:
python -m autofic_core.cli --repo https://github.com/org/project --sast semgrep
python -m autofic_core.cli --repo https://github.com/org/project --sast codeql --no-llm
"""
# Normalize paths
save_dir = save_dir.expanduser().resolve()

# Default XSD at project root (optional)
if xsd_path is None:
local_xsd = Path("custom_context.xsd").resolve()
if local_xsd.exists():
xsd_path = local_xsd

def main(explain, repo, save_dir, sast, llm, llm_retry, patch, pr):
app = AutoFiCApp(
explain=explain,
repo=repo,
_echo_cfg(repo_url, save_dir, sast_tool, run_llm, llm_retry, run_patch, run_pr, xsd_path)

pipe = AutoFiCPipeline(
repo_url=repo_url,
save_dir=save_dir,
sast=sast,
llm=llm,
sast=True,
sast_tool=sast_tool.lower(),
llm=run_llm,
llm_retry=llm_retry,
patch=patch,
pr=pr
patch=run_patch,
pr=run_pr,
)
app.run()
pipe.run()


if __name__ == "__main__":
main()
main()
Loading