feat(remediation): use rescored severity - #1309
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
It introduces a panic-stuck risk in the async MV trigger path and a join strategy in the batch vulnerability query that can unnecessarily multiply rows and degrade performance at scale.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the MariaDB materialized-view refresh logic and the image vulnerability batch query so that rescore remediations affect the severity shown to API/UI consumers (including service-scoped views), and wires remediation changes to trigger MV refreshes and cache invalidation.
Changes:
- Apply rescore remediation severity when computing vulnerability severities in MV refresh procedures and service-scoped views.
- Extend
GetVulnerabilitiesByComponentIDsto accept optional service CCRNs and usemvVulnerabilityService.max_severitywhere applicable. - Trigger MV refresh asynchronously on remediation create/update/delete events and invalidate related caches; add targeted tests.
File summaries
| File | Description |
|---|---|
| internal/database/mariadb/test/fixture.go | Adds seeder helper for refreshing mvVulnerabilityService. |
| internal/database/mariadb/mvproc.go | Introduces reusable SQL expressions for effective severity and adjusts MV refresh queries to account for rescore remediations. |
| internal/database/mariadb/mve.go | Adds async trigger coalescing for MV refresh runs. |
| internal/database/mariadb/mv_vulnerabilities_test.go | Adds tests validating rescore behavior (rebucketing vs suppression; service scoping). |
| internal/database/mariadb/migrations/20260909120000_add_max_severity_to_mv_vulnerability_service.up.sql | Adds max_severity column to mvVulnerabilityService. |
| internal/database/mariadb/migrations/20260909120000_add_max_severity_to_mv_vulnerability_service.down.sql | Drops max_severity column on rollback. |
| internal/database/mariadb/image_batch.go | Extends batch vulnerability preload to compute effective severity with optional service CCRN scoping. |
| internal/database/interface.go | Updates DB interface for new GetVulnerabilitiesByComponentIDs signature. |
| internal/app/remediation/remediation_handler.go | Invalidates image/vulnerability-related caches on remediation create/update/delete. |
| internal/app/heureka.go | Subscribes to remediation change events to trigger MV refresh asynchronously. |
| internal/app/component/component_handler_interface.go | Updates component handler interface for new vulnerability batch signature. |
| internal/app/component/component_handler_batch.go | Passes service CCRNs into cached vulnerability batch calls. |
| internal/app/comment/comment_handler_test.go | Minor formatting-only change. |
| internal/api/graphql/graph/baseResolver/image.go | Passes service filter into vulnerability batch preload. |
Review details
Suppressed comments (1)
internal/database/mariadb/image_batch.go:341
- The current LEFT JOIN on mvVulnerabilityService is only by issue_id; for issues present in many services this multiplies rows before the GROUP BY, even though only a small set of service CCRNs is needed. Constrain the join to the target services up front (e.g., via a service_id subquery) and drop the extra Service join.
query = query.
LeftJoin("mvVulnerabilityService MVS ON MVS.issue_id = I.issue_id").
LeftJoin(fmt.Sprintf("Service S ON S.service_id = MVS.service_id AND S.service_ccrn IN (%s)", inPlaceholders), ccrnArgs...)
}
- Files reviewed: 14/14 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
b3258fd to
e37b0fc
Compare
There was a problem hiding this comment.
🟡 Changes recommended
There is a confirmed race condition in the new async MV trigger implementation (and a nondeterministic SQL ordering in latest-rescore selection) that can lead to incorrect concurrent refresh behavior and unstable severity results.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 14/14 changed files
- Comments generated: 3
- Review effort level: Lite
| go func() { | ||
| defer func() { | ||
| mve.triggerMu.Lock() | ||
| mve.running = false | ||
| mve.triggerMu.Unlock() | ||
| }() |
| @@ -284,7 +285,7 @@ func (r *issueCountWithComponentRow) asIssueSeverityCounts() entity.IssueSeverit | |||
| // using the mvVulnerabilityList materialized view. This eliminates N+1 queries when loading | |||
| // nested vulnerabilities for multiple images. | |||
| // Join path: ComponentVersionIssue → ComponentVersion → Issue → mvVulnerabilityList | |||
| func (s *SqlDatabase) GetVulnerabilitiesByComponentIDs(ctx context.Context, componentIDs []int64) (map[int64][]entity.VulnerabilityResult, error) { | |||
| func (s *SqlDatabase) GetVulnerabilitiesByComponentIDs(ctx context.Context, componentIDs []int64, serviceCCRN []*string) (map[int64][]entity.VulnerabilityResult, error) { | |||
bcb349b to
52b32f1
Compare
| AND remediation_deleted_at IS NULL | ||
| AND (remediation_expiration_date IS NULL OR remediation_expiration_date >= CURDATE()) | ||
| ) r | ||
| WHERE r.rn = 1 |
There was a problem hiding this comment.
nit: Could you use squirrel in this query?
Signed-off-by: Kanstantsin Buklis <kanstantsin.buklis@sap.com>
52b32f1 to
cd556cd
Compare
Description
In this PR I've added logic related to the rescored remediation type
What type of PR is this? (check all applicable)
Related Tickets & Documents
Added tests?
Added to documentation?