Skip to content

Commit 68b3b5c

Browse files
authored
chore: improve ignoredetails and issue implementation (#482)
1 parent 5a4bd0f commit 68b3b5c

File tree

4 files changed

+506
-89
lines changed

4 files changed

+506
-89
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package testapi
2+
3+
import "github.com/google/uuid"
4+
5+
func (f *FindingData) GetIgnoreDetails() IssueIgnoreDetails {
6+
if f.Attributes == nil || f.Attributes.Suppression == nil {
7+
return nil
8+
}
9+
result := &issueIgnoreDetailsImpl{
10+
finding: f,
11+
}
12+
13+
// Extract policy information from suppression
14+
if result.finding.Attributes.Suppression.Policy != nil {
15+
if localRef, err := result.finding.Attributes.Suppression.Policy.AsPolicyRef0(); !(err == nil && localRef == PolicyRef0LocalPolicy) {
16+
// Try as a managed policy (has ID field)
17+
if managedRef, err := result.finding.Attributes.Suppression.Policy.AsManagedPolicyRef(); err == nil && managedRef.Id != uuid.Nil {
18+
// It's a managed policy with a valid ID
19+
idStr := managedRef.Id.String()
20+
result.policyID = &idStr
21+
result.ignoreData = searchFindingForIgnoreAction(result.finding, result.policyID)
22+
}
23+
// If both fail, policy type cannot be determined (isLocalPolicy remains nil)
24+
}
25+
}
26+
27+
return result
28+
}

pkg/apiclients/testapi/issues.go

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ type issue struct {
334334
sourceLocations []SourceLocation
335335
riskScore uint16
336336
reachability *ReachabilityEvidence
337-
suppression *Suppression
338337
metadata map[string]interface{} // case-insensitive key storage (lowercase keys)
338+
ignoreDetail IssueIgnoreDetails
339339
}
340340

341341
// GetFindings returns all findings that are part of this issue.
@@ -423,10 +423,7 @@ func (i *issue) GetReachability() *ReachabilityEvidence {
423423

424424
// GetIgnoreDetails returns the ignore/suppression details for this issue.
425425
func (i *issue) GetIgnoreDetails() IssueIgnoreDetails {
426-
if i.suppression == nil {
427-
return nil
428-
}
429-
return newIgnoreDetailsFromSuppression(i.suppression, i.findings)
426+
return i.ignoreDetail
430427
}
431428

432429
// NewIssueFromFindings creates a single Issue instance from a group of related findings.
@@ -471,8 +468,8 @@ type issueBuilder struct {
471468
sourceLocations []SourceLocation
472469
riskScore uint16
473470
reachability *ReachabilityEvidence
474-
suppression *Suppression
475471
findings []*FindingData
472+
ignoreDetails []IssueIgnoreDetails
476473
}
477474

478475
// processFindings extracts data from all findings
@@ -489,18 +486,27 @@ func (b *issueBuilder) processFindings(findings []*FindingData) {
489486

490487
// processFinding extracts data from a single finding
491488
func (b *issueBuilder) processFinding(finding *FindingData) {
489+
// ignore all data if the given finding is ignored
490+
ignoreDetails := finding.GetIgnoreDetails()
491+
b.ignoreDetails = append(b.ignoreDetails, ignoreDetails)
492+
493+
// skipping the details of an ignored finding seems reasonable but currently breaks tests, which is why it is for now commented
494+
//if ignoreDetails != nil && ignoreDetails.IsActive() {
495+
// return
496+
//}
497+
492498
b.setBasicInfo(finding)
493499
for i := range finding.Attributes.Problems {
494500
b.allProblems = append(b.allProblems, &finding.Attributes.Problems[i])
495501
}
502+
503+
b.extractPackageInfo(finding)
504+
b.processProblems(finding)
496505
b.extractSourceLocations(finding)
497506
b.extractSeverityAndRisk(finding)
498507
b.extractEffectiveSeverity(finding)
499508
b.extractReachability(finding)
500-
b.extractSuppression(finding)
501509
b.extractDependencyPaths(finding)
502-
b.extractPackageInfo(finding)
503-
b.processProblems(finding)
504510
}
505511

506512
// setBasicInfo sets finding type, title, and description from the first finding
@@ -569,16 +575,6 @@ func (b *issueBuilder) extractReachability(finding *FindingData) {
569575
}
570576
}
571577

572-
// extractSuppression extracts suppression information
573-
func (b *issueBuilder) extractSuppression(finding *FindingData) {
574-
if b.suppression != nil {
575-
return
576-
}
577-
if finding.Attributes.Suppression != nil {
578-
b.suppression = finding.Attributes.Suppression
579-
}
580-
}
581-
582578
// extractDependencyPaths extracts dependency paths from evidence
583579
func (b *issueBuilder) extractDependencyPaths(finding *FindingData) {
584580
for _, ev := range finding.Attributes.Evidence {
@@ -766,6 +762,7 @@ func (b *issueBuilder) deduplicate() {
766762
// build constructs the final Issue from collected data
767763
func (b *issueBuilder) build() *issue {
768764
metadata := b.buildMetadata()
765+
activeIgnoreDetail := determineActiveIgnoreDetail(b.ignoreDetails)
769766

770767
return &issue{
771768
findings: b.findings,
@@ -783,9 +780,27 @@ func (b *issueBuilder) build() *issue {
783780
sourceLocations: b.sourceLocations,
784781
riskScore: b.riskScore,
785782
reachability: b.reachability,
786-
suppression: b.suppression,
787783
metadata: metadata,
784+
ignoreDetail: activeIgnoreDetail,
785+
}
786+
}
787+
788+
func determineActiveIgnoreDetail(ignoreDetails []IssueIgnoreDetails) IssueIgnoreDetails {
789+
activeIgnores := 0
790+
var firstIgnoreDetail IssueIgnoreDetails
791+
for _, detail := range ignoreDetails {
792+
if detail != nil && detail.IsActive() {
793+
firstIgnoreDetail = detail
794+
activeIgnores++
795+
}
788796
}
797+
798+
// if all findings are ignored, return the first ignore details
799+
if activeIgnores == len(ignoreDetails) {
800+
return firstIgnoreDetail
801+
}
802+
803+
return nil
789804
}
790805

791806
// buildMetadata constructs the metadata map

pkg/apiclients/testapi/issues_ignore_details.go

Lines changed: 27 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package testapi
22

33
import (
44
"time"
5-
6-
"github.com/google/uuid"
75
)
86

97
// IssueIgnoreDetails provides combined information about issue suppression/ignore status,
@@ -39,57 +37,59 @@ type IssueIgnoreDetails interface {
3937

4038
// GetIgnoredBy returns the user who created the ignore action.
4139
GetIgnoredBy() *IgnoredBy
40+
41+
IsActive() bool
4242
}
4343

4444
// issueIgnoreDetailsImpl is the concrete implementation of IssueIgnoreDetails.
4545
type issueIgnoreDetailsImpl struct {
46-
suppression *Suppression
47-
policyID *string
48-
ignoreData *Ignore
46+
finding *FindingData
47+
policyID *string
48+
ignoreData *Ignore
4949
}
5050

5151
// === Suppression Status Methods ===
5252

5353
func (id *issueIgnoreDetailsImpl) GetStatus() SuppressionStatus {
54-
if id.suppression == nil {
54+
if !id.isInitialized() {
5555
return ""
5656
}
57-
return id.suppression.Status
57+
return id.finding.Attributes.Suppression.Status
5858
}
5959

6060
func (id *issueIgnoreDetailsImpl) GetCreatedAt() *time.Time {
61-
if id.suppression == nil {
61+
if !id.isInitialized() {
6262
return nil
6363
}
64-
return id.suppression.CreatedAt
64+
return id.finding.Attributes.Suppression.CreatedAt
6565
}
6666

6767
func (id *issueIgnoreDetailsImpl) GetExpiresAt() *time.Time {
68-
if id.suppression == nil {
68+
if !id.isInitialized() {
6969
return nil
7070
}
71-
return id.suppression.ExpiresAt
71+
return id.finding.Attributes.Suppression.ExpiresAt
7272
}
7373

7474
func (id *issueIgnoreDetailsImpl) GetJustification() *string {
75-
if id.suppression == nil {
75+
if !id.isInitialized() {
7676
return nil
7777
}
78-
return id.suppression.Justification
78+
return id.finding.Attributes.Suppression.Justification
7979
}
8080

8181
func (id *issueIgnoreDetailsImpl) GetPath() *[]string {
82-
if id.suppression == nil {
82+
if !id.isInitialized() {
8383
return nil
8484
}
85-
return id.suppression.Path
85+
return id.finding.Attributes.Suppression.Path
8686
}
8787

8888
func (id *issueIgnoreDetailsImpl) SkipIfFixable() *bool {
89-
if id.suppression == nil {
89+
if !id.isInitialized() {
9090
return nil
9191
}
92-
return id.suppression.SkipIfFixable
92+
return id.finding.Attributes.Suppression.SkipIfFixable
9393
}
9494

9595
// === Policy Information Methods ===
@@ -128,65 +128,23 @@ func (id *issueIgnoreDetailsImpl) GetIgnoredBy() *IgnoredBy {
128128
return id.ignoreData.Ignore.IgnoredBy
129129
}
130130

131-
// newIgnoreDetailsFromSuppression creates an IssueIgnoreDetails from suppression data and findings.
132-
func newIgnoreDetailsFromSuppression(suppression *Suppression, findings []*FindingData) IssueIgnoreDetails {
133-
if suppression == nil {
134-
return nil
131+
func (id *issueIgnoreDetailsImpl) IsActive() bool {
132+
if !id.isInitialized() {
133+
return false
135134
}
136135

137-
result := &issueIgnoreDetailsImpl{
138-
suppression: suppression,
136+
if id.finding.Attributes.Suppression.Status != SuppressionStatusIgnored {
137+
return false
139138
}
140139

141-
// Extract policy information from suppression
142-
if suppression.Policy != nil {
143-
// Determine policy type and ID by checking the structure
144-
// PolicyRef is a union of either a string (local) or an object with ID (managed)
145-
146-
if localRef, err := suppression.Policy.AsPolicyRef0(); !(err == nil && localRef == PolicyRef0LocalPolicy) {
147-
// Try as a managed policy (has ID field)
148-
if managedRef, err := suppression.Policy.AsManagedPolicyRef(); err == nil && managedRef.Id != uuid.Nil {
149-
// It's a managed policy with a valid ID
150-
idStr := managedRef.Id.String()
151-
result.policyID = &idStr
152-
153-
// Try to find the matching expanded policy data in findings
154-
result.ignoreData = findMatchingIgnoreData(suppression.Policy, findings)
155-
}
156-
// If both fail, policy type cannot be determined (isLocalPolicy remains nil)
157-
}
158-
}
159-
160-
return result
140+
return true
161141
}
162142

163-
// findMatchingIgnoreData finds the Ignore action that matches the given policy reference.
164-
func findMatchingIgnoreData(policyRef *PolicyRef, findings []*FindingData) *Ignore {
165-
if policyRef == nil {
166-
return nil
143+
func (id *issueIgnoreDetailsImpl) isInitialized() bool {
144+
if id.finding == nil || id.finding.Attributes == nil || id.finding.Attributes.Suppression == nil {
145+
return false
167146
}
168-
169-
policyIDToMatch := extractPolicyTypeFromRef(policyRef)
170-
171-
// Search through findings for matching policy
172-
for _, finding := range findings {
173-
if ignoreAction := searchFindingForIgnoreAction(finding, policyIDToMatch); ignoreAction != nil {
174-
return ignoreAction
175-
}
176-
}
177-
178-
return nil
179-
}
180-
181-
// extractPolicyTypeFromRef determines if a PolicyRef is local or managed and returns the policy ID.
182-
func extractPolicyTypeFromRef(policyRef *PolicyRef) *string {
183-
// Try as a managed policy (has ID field)
184-
if managedRef, err := policyRef.AsManagedPolicyRef(); err == nil && managedRef.Id != uuid.Nil {
185-
idStr := managedRef.Id.String()
186-
return &idStr
187-
}
188-
189-
return nil
147+
return true
190148
}
191149

192150
// searchFindingForIgnoreAction searches a finding for a matching ignore action.

0 commit comments

Comments
 (0)