feat(compliance): add DORA (EU 2022/2554) framework with ATT&CK mappings
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled

Implements the Digital Operational Resilience Act as a compliance framework
using the same pattern as CIS Controls v8 (hardcoded curated mappings,
no official STIX bundle exists for DORA).

22 controls across 5 chapters mapped to MITRE ATT&CK techniques:
  Ch. II  — ICT Risk Management (Art. 5–15): governance, identification,
            protection, detection, response, backup, threat intel
  Ch. III — Incident Management (Art. 17–19): classification, reporting
  Ch. IV  — Resilience Testing (Art. 24–27): general testing + TLPT
            (Art. 26 explicitly based on TIBER-EU/ATT&CK threat-led testing)
  Ch. V   — Third-Party Risk (Art. 28, 30, 42): supply chain, trusted rels.
  Ch. VI  — Information Sharing (Art. 45)

Technique mappings derived from ENISA DORA guidelines and TIBER-EU framework.
Import is triggered via POST /api/v1/compliance/import/dora (admin only).
Frontend: new 'DORA' button in the Compliance page import section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kitos
2026-05-29 13:52:51 +02:00
parent 70b5c833d4
commit 7d856bef43
4 changed files with 283 additions and 3 deletions

View File

@@ -120,3 +120,9 @@ export async function importCisMappings(): Promise<Record<string, unknown>> {
const { data } = await client.post("/compliance/import/cis-controls-v8");
return data;
}
/** Import DORA (EU 2022/2554) compliance mappings (admin). */
export async function importDoraMappings(): Promise<Record<string, unknown>> {
const { data } = await client.post("/compliance/import/dora");
return data;
}

View File

@@ -7,6 +7,7 @@ import {
downloadComplianceCSV,
importNistMappings,
importCisMappings,
importDoraMappings,
type ComplianceFrameworkSummary,
} from "../api/compliance";
import { useAuth } from "../context/AuthContext";
@@ -81,7 +82,15 @@ export default function CompliancePage() {
},
});
const isImporting = importNist.isPending || importCis.isPending;
const importDora = useMutation({
mutationFn: importDoraMappings,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["compliance-frameworks"] });
queryClient.invalidateQueries({ queryKey: ["compliance-status"] });
},
});
const isImporting = importNist.isPending || importCis.isPending || importDora.isPending;
if (isLoading && !frameworkStatus) {
return (
@@ -215,10 +224,18 @@ export default function CompliancePage() {
{importCis.isPending ? <Loader2 className="h-3 w-3 animate-spin" /> : <Plus className="h-3 w-3" />}
CIS Controls v8
</button>
{(importNist.isSuccess || importCis.isSuccess) && (
<button
onClick={() => importDora.mutate()}
disabled={isImporting}
className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-xs font-medium text-gray-300 hover:border-cyan-500/50 hover:text-white transition-colors disabled:opacity-50"
>
{importDora.isPending ? <Loader2 className="h-3 w-3 animate-spin" /> : <Plus className="h-3 w-3" />}
DORA
</button>
{(importNist.isSuccess || importCis.isSuccess || importDora.isSuccess) && (
<span className="text-xs text-green-400">Import complete</span>
)}
{(importNist.isError || importCis.isError) && (
{(importNist.isError || importCis.isError || importDora.isError) && (
<span className="text-xs text-red-400">Import failed</span>
)}
</div>