Establish AAISA research foundation

This commit is contained in:
2026-09-17 15:11:34 +00:00
parent 0d61911dda
commit d9fc3ca18b
30 changed files with 1497 additions and 2 deletions
+98
View File
@@ -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,
}