Skip to content
Closed
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 costom_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>
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ dependencies = [
"python-dotenv>=0.21.0,<1.0.0",
"rich>=13.3.1,<14.0.0",
"openai>=1.0.0,<2.0.0",
"pyfiglet>=1.0.3,<2.0.0"
"pyfiglet>=1.0.3,<2.0.0",
"pydantic>=2.11.6,<3.0.0",
"lxml>=4.9.0,<5.0.0",
"chardet>=5.0.0,<6.0.0",
"jsonschema>=4.0.0,<5.0.0"
]
classifiers = [
"Programming Language :: Python :: 3",
Expand Down
1 change: 1 addition & 0 deletions src/autofic-core
Submodule autofic-core added at 164382
6 changes: 6 additions & 0 deletions src/autofic_core/annotation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Annotation system for AutoFiC"""

from .injector import AnnotationInjector
from .context_generator import ContextGenerator

__all__ = ['AnnotationInjector', 'ContextGenerator']
108 changes: 108 additions & 0 deletions src/autofic_core/annotation/context_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import xml.etree.ElementTree as ET
from xml.dom import minidom
from pathlib import Path
from typing import List
from datetime import datetime
import logging
import xml.sax.saxutils as saxutils
from autofic_core.sast.snippet import BaseSnippet

logger = logging.getLogger(__name__)


class ContextGenerator:

NAMESPACE = 'urn:autofic:custom-context'

def __init__(self, tool_name: str = "AutoFiC"):
self.tool_name = tool_name

def generate(self, snippets: List[BaseSnippet], output_path: Path) -> Path:

ET.register_namespace('', self.NAMESPACE)
ET.register_namespace('xsi', 'http://www.w3.org/2001/XMLSchema-instance')

root = ET.Element(f'{{{self.NAMESPACE}}}CUSTOM_CONTEXT')
root.set('version', '1.0')
root.set(
f'{{{ET.QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation")}}}',
f'{self.NAMESPACE} custom_context.xsd'
)

meta = ET.SubElement(root, f'{{{self.NAMESPACE}}}META')
meta.set('generatedAt', datetime.now().isoformat())
meta.set('tool', self.tool_name)
meta.set('count', str(len(snippets)))

for snippet in snippets:
self._add_vulnerability(root, snippet)

self._save_pretty_xml(root, output_path)

logger.info(f"Generated CUSTOM_CONTEXT.xml: {output_path}")
return output_path

def _add_vulnerability(self, parent: ET.Element, snippet: BaseSnippet):

vuln_id = f"{snippet.path}:{snippet.start_line}-{snippet.end_line}"

vuln = ET.SubElement(parent, f'{{{self.NAMESPACE}}}VULNERABILITY')
vuln.set('id', vuln_id)

file_elem = ET.SubElement(vuln, f'{{{self.NAMESPACE}}}FILE')
file_elem.set('path', snippet.path)

range_elem = ET.SubElement(vuln, f'{{{self.NAMESPACE}}}RANGE')
range_elem.set('start', str(snippet.start_line))
range_elem.set('end', str(snippet.end_line))

bit_severity = getattr(snippet, 'bit_severity', None) or snippet.severity or 'UNKNOWN'
severity_elem = ET.SubElement(vuln, f'{{{self.NAMESPACE}}}SEVERITY')
severity_elem.set('overall', snippet.severity or 'UNKNOWN')
severity_elem.set('bit', bit_severity)

# MESSAGE
message_elem = ET.SubElement(vuln, f'{{{self.NAMESPACE}}}MESSAGE')
#message_elem.text = snippet.message or ''

# SNIPPET
snippet_elem = ET.SubElement(vuln, f'{{{self.NAMESPACE}}}SNIPPET')
#snippet_elem.text = snippet.snippet or ''
snippet_elem.text = saxutils.escape(snippet.snippet or '')
message_elem.text = saxutils.escape(snippet.message or '')

# BIT
if hasattr(snippet, 'bit_trigger') and snippet.bit_trigger:
self._add_bit(vuln, snippet)

def _add_bit(self, parent: ET.Element, snippet: BaseSnippet):
bit = ET.SubElement(parent, f'{{{self.NAMESPACE}}}BIT')

# TRIGGER
trigger = ET.SubElement(bit, f'{{{self.NAMESPACE}}}TRIGGER')
trigger.text = getattr(snippet, 'bit_trigger', None) or ''

# STEPS
if hasattr(snippet, 'bit_steps') and snippet.bit_steps:
steps = ET.SubElement(bit, f'{{{self.NAMESPACE}}}STEPS')
for step_text in snippet.bit_steps:
step = ET.SubElement(steps, f'{{{self.NAMESPACE}}}STEP')
step.text = step_text

# REPRODUCTION
reproduction = ET.SubElement(bit, f'{{{self.NAMESPACE}}}REPRODUCTION')
reproduction.text = getattr(snippet, 'bit_reproduction', None) or ''

# BIT_SEVERITY
bit_severity = ET.SubElement(bit, f'{{{self.NAMESPACE}}}BIT_SEVERITY')
bit_severity.text = getattr(snippet, 'bit_severity', None) or 'UNKNOWN'

def _save_pretty_xml(self, root: ET.Element, output_path: Path):
output_path.parent.mkdir(parents=True, exist_ok=True)

xml_str = ET.tostring(root, encoding='unicode')
dom = minidom.parseString(xml_str)
pretty_xml = dom.toprettyxml(indent=' ', encoding='UTF-8')

with open(output_path, 'wb') as f:
f.write(pretty_xml)
Loading