Skip to content

Commit 0c0d520

Browse files
committed
feat(security): gate Approve modal on baseline dangerous findings (Spec 077 US1)
Related #784 Related: Spec 077 (specs/077-scanner-simplification) The server Approve confirmation now blocks on baseline DANGEROUS (hard-tier) findings only (FR-021), mirroring the tier-driven server verdict, instead of `critical` severity — a non-blocking soft finding can be high/critical severity yet must not gate approval. Applied to both ServerDetail.vue and ServerCard.vue (same approval gate), with the dialog wording updated to "dangerous". ## Testing - vue-tsc --noEmit clean; vite build succeeds.
1 parent b6f8902 commit 0c0d520

2 files changed

Lines changed: 22 additions & 14 deletions

File tree

frontend/src/components/ServerCard.vue

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,11 @@
265265
<div v-if="showApproveConfirmation" class="modal modal-open">
266266
<div class="modal-box">
267267
<h3 class="font-bold text-lg mb-4">
268-
{{ approveDialogMode === 'no_scan' ? 'No Security Scan Run' : 'Critical Findings Detected' }}
268+
{{ approveDialogMode === 'no_scan' ? 'No Security Scan Run' : 'Dangerous Findings Detected' }}
269269
</h3>
270270
<p v-if="approveDialogMode === 'critical'" class="mb-4">
271271
<strong>{{ server.name }}</strong> has
272-
<span class="text-error font-semibold">{{ criticalFindingCount }} critical finding{{ criticalFindingCount === 1 ? '' : 's' }}</span>
272+
<span class="text-error font-semibold">{{ dangerousFindingCount }} dangerous finding{{ dangerousFindingCount === 1 ? '' : 's' }}</span>
273273
in its most recent security scan. Approving this server will allow it to run despite these warnings.
274274
</p>
275275
<p v-else class="mb-4">
@@ -722,14 +722,17 @@ async function triggerLogout() {
722722
}
723723
}
724724
725-
// Counts critical findings from the scan summary if available. Used to gate
726-
// the Approve button behind an extra confirmation (F-04).
727-
const criticalFindingCount = computed(() => {
725+
// Counts baseline DANGEROUS findings from the scan summary if available. Used to
726+
// gate the Approve button behind an extra confirmation (F-04). Spec 077 FR-021:
727+
// the gate blocks on baseline dangerous (hard-tier) findings only, matching the
728+
// tier-driven server verdict — not on `critical` severity, which a non-blocking
729+
// soft finding could also carry.
730+
const dangerousFindingCount = computed(() => {
728731
const scan = props.server.security_scan as any
729732
if (!scan) return 0
730-
// finding_counts.critical is populated from the latest report summary.
733+
// finding_counts.dangerous is populated from the latest report summary.
731734
const fc = scan.finding_counts as Record<string, number> | undefined
732-
if (fc && typeof fc.critical === 'number') return fc.critical
735+
if (fc && typeof fc.dangerous === 'number') return fc.dangerous
733736
return 0
734737
})
735738
@@ -750,7 +753,7 @@ function handleApproveClick() {
750753
showApproveConfirmation.value = true
751754
return
752755
}
753-
if (criticalFindingCount.value > 0) {
756+
if (dangerousFindingCount.value > 0) {
754757
approveDialogMode.value = 'critical'
755758
showApproveConfirmation.value = true
756759
return

frontend/src/views/ServerDetail.vue

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,11 @@
221221
<div v-if="showApproveConfirmation" class="modal modal-open">
222222
<div class="modal-box">
223223
<h3 class="font-bold text-lg mb-4">
224-
{{ approveDialogMode === 'no_scan' ? 'No Security Scan Run' : 'Critical Findings Detected' }}
224+
{{ approveDialogMode === 'no_scan' ? 'No Security Scan Run' : 'Dangerous Findings Detected' }}
225225
</h3>
226226
<p v-if="approveDialogMode === 'critical'" class="mb-4">
227227
<strong>{{ server.name }}</strong> has
228-
<span class="text-error font-semibold">{{ criticalFindingCount }} critical finding{{ criticalFindingCount === 1 ? '' : 's' }}</span>
228+
<span class="text-error font-semibold">{{ dangerousFindingCount }} dangerous finding{{ dangerousFindingCount === 1 ? '' : 's' }}</span>
229229
in its most recent security scan. Approving will allow this server to run despite these warnings.
230230
</p>
231231
<p v-else class="mb-4">
@@ -2399,13 +2399,18 @@ async function unquarantineServer() {
23992399
const showApproveConfirmation = ref(false)
24002400
const approveDialogMode = ref<'no_scan' | 'critical'>('no_scan')
24012401
2402-
const criticalFindingCount = computed(() => {
2402+
// Spec 077 FR-021: the approval gate blocks on baseline DANGEROUS findings only
2403+
// (hard-tier). Deep-scan findings inform but never gate. The server-side verdict
2404+
// is now tier-driven, so the modal mirrors it by counting `dangerous` (threat
2405+
// level) rather than `critical` (severity) — a soft finding can be "high"
2406+
// severity yet must not block approval.
2407+
const dangerousFindingCount = computed(() => {
24032408
// Prefer the loaded scan report summary if available; otherwise fall back
24042409
// to finding_counts on the server's security_scan summary (if populated).
24052410
const rep = scanReport.value as any
2406-
if (rep?.summary?.critical != null) return rep.summary.critical as number
2411+
if (rep?.summary?.dangerous != null) return rep.summary.dangerous as number
24072412
const scan = server.value?.security_scan as any
2408-
if (scan?.finding_counts?.critical != null) return scan.finding_counts.critical as number
2413+
if (scan?.finding_counts?.dangerous != null) return scan.finding_counts.dangerous as number
24092414
return 0
24102415
})
24112416
@@ -2421,7 +2426,7 @@ function handleApproveClick() {
24212426
showApproveConfirmation.value = true
24222427
return
24232428
}
2424-
if (criticalFindingCount.value > 0) {
2429+
if (dangerousFindingCount.value > 0) {
24252430
approveDialogMode.value = 'critical'
24262431
showApproveConfirmation.value = true
24272432
return

0 commit comments

Comments
 (0)