diff --git a/frontend/src/pages/reports/ReportsPage.tsx b/frontend/src/pages/reports/ReportsPage.tsx index c8459490..f2d8e8a4 100644 --- a/frontend/src/pages/reports/ReportsPage.tsx +++ b/frontend/src/pages/reports/ReportsPage.tsx @@ -469,7 +469,10 @@ function LibraryTab({ // session cookie authenticates it (same-origin credentials) and no CSRF // token is needed; the filename comes from the server's // Content-Disposition. Errors are surfaced to the caller. -async function downloadReportFace(id: string, format: 'pdf' | 'json' | 'csv'): Promise { +async function downloadReportFace( + id: string, + format: 'pdf' | 'json' | 'csv' | 'oscal_sar', +): Promise { const res = await fetch(`/api/v1/reports/${id}/export?format=${format}`, { credentials: 'same-origin', }); @@ -595,12 +598,12 @@ function ReportDetail({ id: string; onClose: () => void; }) { - const [downloading, setDownloading] = useState<'pdf' | 'json' | 'csv' | null>(null); + const [downloading, setDownloading] = useState<'pdf' | 'json' | 'csv' | 'oscal_sar' | null>(null); const [downloadError, setDownloadError] = useState(null); const [verifying, setVerifying] = useState(false); const [verifyResult, setVerifyResult] = useState(null); - async function onDownload(format: 'pdf' | 'json' | 'csv') { + async function onDownload(format: 'pdf' | 'json' | 'csv' | 'oscal_sar') { setDownloading(format); setDownloadError(null); try { @@ -655,6 +658,22 @@ function ReportDetail({ ? 'Download the per-host, per-rule CSV evidence' : 'Download the one-page executive PDF'; + // Secondary faces offered beside the primary + JSON. An attestation also + // exposes its bounded PDF cover and the fleet OSCAL SAR (the + // machine-readable assessment-results); an executive report has no extra + // faces (PDF is its primary, JSON is shown for both below). + const secondaryFaces: { face: 'pdf' | 'oscal_sar'; label: string; title: string }[] = + isAttestation + ? [ + { face: 'pdf', label: 'PDF', title: 'Download the one-page attestation cover PDF' }, + { + face: 'oscal_sar', + label: 'OSCAL SAR', + title: 'Download the OSCAL assessment-results (evidence referenced by hash)', + }, + ] + : []; + return (
{downloading === primaryFace ? 'Preparing…' : primaryLabel} + {secondaryFaces.map((f) => ( + + ))}