Establish AAISA research foundation
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from enum import IntEnum
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Severity(IntEnum):
|
||||
INFO = 0
|
||||
LOW = 1
|
||||
MEDIUM = 2
|
||||
HIGH = 3
|
||||
CRITICAL = 4
|
||||
|
||||
@classmethod
|
||||
def parse(cls, value: str) -> "Severity":
|
||||
try:
|
||||
return cls[value.strip().upper()]
|
||||
except KeyError as exc:
|
||||
choices = ", ".join(item.name.lower() for item in cls)
|
||||
raise ValueError(f"unknown severity {value!r}; choose one of: {choices}") from exc
|
||||
|
||||
def label(self) -> str:
|
||||
return self.name.lower()
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Artifact:
|
||||
path: Path
|
||||
relative_path: str
|
||||
kind: str
|
||||
media_type: str
|
||||
size_bytes: int
|
||||
sha256: str
|
||||
text: str | None = field(default=None, repr=False)
|
||||
|
||||
def evidence(self) -> dict[str, Any]:
|
||||
return {
|
||||
"path": self.relative_path,
|
||||
"kind": self.kind,
|
||||
"media_type": self.media_type,
|
||||
"size_bytes": self.size_bytes,
|
||||
"sha256": self.sha256,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Finding:
|
||||
rule_id: str
|
||||
title: str
|
||||
severity: Severity
|
||||
message: str
|
||||
artifact_path: str
|
||||
line: int | None = None
|
||||
column: int | None = None
|
||||
evidence: str | None = None
|
||||
remediation: str | None = None
|
||||
tags: tuple[str, ...] = ()
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
result = asdict(self)
|
||||
result["severity"] = self.severity.label()
|
||||
result["tags"] = list(self.tags)
|
||||
return result
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ScanReport:
|
||||
schema_version: str
|
||||
tool_version: str
|
||||
started_at: str
|
||||
completed_at: str
|
||||
root: str
|
||||
artifacts: list[dict[str, Any]]
|
||||
findings: list[Finding]
|
||||
errors: list[dict[str, str]]
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"schema_version": self.schema_version,
|
||||
"tool": {"name": "AAISA", "version": self.tool_version},
|
||||
"started_at": self.started_at,
|
||||
"completed_at": self.completed_at,
|
||||
"root": self.root,
|
||||
"summary": {
|
||||
"artifact_count": len(self.artifacts),
|
||||
"finding_count": len(self.findings),
|
||||
"error_count": len(self.errors),
|
||||
"by_severity": {
|
||||
level.label(): sum(1 for finding in self.findings if finding.severity == level)
|
||||
for level in Severity
|
||||
},
|
||||
},
|
||||
"artifacts": self.artifacts,
|
||||
"findings": [finding.to_dict() for finding in self.findings],
|
||||
"errors": self.errors,
|
||||
}
|
||||
Reference in New Issue
Block a user