feat: security center page (/security)

Project-scoped security surface: scan trigger (dependency /
configuration / comprehensive, optional service), security score and
vulnerability metric cards, findings list with severity badges and
resolve/ignore actions, and scan history.

Fixed a latent bug in GET /projects/:id/security/metrics: it selected a
non-existent `score` column (the score lives in the security_scans
summary jsonb), so the endpoint 500'd on every project.

Verified live: comprehensive scan produced 4 real findings (insecure
public URL, curl|sh build, http source, unpinned tag) with score 47;
resolve flow and metrics aggregation confirmed.

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-17 18:24:19 +02:00
1 parent d5c99acb8c
commit d5e6bfc40d
6 files changed
+345 -9

No files matched your search

+4 -4
View File
@@ -394,10 +394,10 @@ func (sh *SecurityHandler) GetSecurityMetrics(c *gin.Context) {
}
err = sh.db.QueryRow(`
SELECT id, score, started_at as scanned_at, status
FROM security_scans
WHERE project_id = $1
ORDER BY started_at DESC
SELECT id, COALESCE((summary->>'score')::int, 0), started_at as scanned_at, status
FROM security_scans
WHERE project_id = $1
ORDER BY started_at DESC
LIMIT 1
`, projectID).Scan(&latestScan.ID, &latestScan.Score, &latestScan.ScannedAt, &latestScan.Status)