@@ -22,25 +22,25 @@ import (
2222 "fmt"
2323 "os"
2424 "path/filepath"
25+ "strings"
2526 "time"
2627
28+ ecc "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
2729 "github.com/sigstore/cosign/v2/pkg/oci"
2830 log "github.com/sirupsen/logrus"
2931 "github.com/spf13/afero"
3032
3133 "github.com/conforma/cli/internal/applicationsnapshot"
32- "github.com/conforma/cli/internal/evaluator"
3334)
3435
3536// Predicate represents a Verification Summary Attestation (VSA) predicate.
3637type Predicate struct {
37- ImageRef string `json:"imageRef"`
38- ValidationResult string `json:"validationResult"`
39- Timestamp string `json:"timestamp"`
40- Verifier string `json:"verifier"`
41- PolicySource string `json:"policySource"`
42- Component map [string ]interface {} `json:"component"`
43- RuleResults []evaluator.Result `json:"ruleResults"`
38+ ImageRef string `json:"imageRef"`
39+ Timestamp string `json:"timestamp"`
40+ Verifier string `json:"verifier"`
41+ PolicySource string `json:"policySource"`
42+ Component map [string ]interface {} `json:"component"`
43+ Results * FilteredReport `json:"results,omitempty"` // Filtered report containing target component and its variants
4444}
4545
4646// Generator handles VSA predicate generation
@@ -57,6 +57,56 @@ func NewGenerator(report applicationsnapshot.Report, comp applicationsnapshot.Co
5757 }
5858}
5959
60+ // FilteredReport represents a filtered version of the application snapshot report
61+ // that contains only the target component and its architecture variants.
62+ type FilteredReport struct {
63+ Snapshot string `json:"snapshot"`
64+ Components []applicationsnapshot.Component `json:"components"`
65+ Key string `json:"key"`
66+ Policy ecc.EnterpriseContractPolicySpec `json:"policy"`
67+ EcVersion string `json:"ec-version"`
68+ EffectiveTime time.Time `json:"effective-time"`
69+ }
70+
71+ // FilterReportForComponent filters the report to include only the target component and its architecture variants.
72+ // It returns a filtered report that excludes the top-level "success" field and includes only components
73+ // that match the target component name or are architecture variants of the same base component.
74+ //
75+ // Parameters:
76+ // - report: The complete application snapshot report
77+ // - targetComponentName: The name of the component to filter for
78+ //
79+ // Returns:
80+ // - A FilteredReport containing only the target component and its variants
81+ func FilterReportForComponent (report applicationsnapshot.Report , targetComponentName string ) * FilteredReport {
82+ // Extract the base component name (before the first dash)
83+ baseName := targetComponentName
84+ if idx := strings .Index (targetComponentName , "-" ); idx != - 1 {
85+ baseName = targetComponentName [:idx ]
86+ }
87+
88+ // Filter components that match the base name or are architecture variants
89+ var filteredComponents []applicationsnapshot.Component
90+ for _ , comp := range report .Components {
91+ // Check if this component is the target, the base component, or a variant
92+ if comp .Name == targetComponentName ||
93+ comp .Name == baseName ||
94+ strings .HasPrefix (comp .Name , baseName + "-" ) {
95+ filteredComponents = append (filteredComponents , comp )
96+ }
97+ }
98+
99+ // Create a filtered report without the success field
100+ return & FilteredReport {
101+ Snapshot : report .Snapshot ,
102+ Components : filteredComponents ,
103+ Key : report .Key ,
104+ Policy : report .Policy ,
105+ EcVersion : report .EcVersion ,
106+ EffectiveTime : report .EffectiveTime ,
107+ }
108+ }
109+
60110// GeneratePredicate creates a Predicate for a validated image/component.
61111func (g * Generator ) GeneratePredicate (ctx context.Context ) (* Predicate , error ) {
62112 log .Infof ("Generating VSA predicate for image: %s" , g .Component .ContainerImage )
@@ -68,30 +118,21 @@ func (g *Generator) GeneratePredicate(ctx context.Context) (*Predicate, error) {
68118 "source" : g .Component .Source ,
69119 }
70120
71- // Compose rule results: combine violations, warnings, and successes
72- ruleResults := make ([]evaluator.Result , 0 , len (g .Component .Violations )+ len (g .Component .Warnings )+ len (g .Component .Successes ))
73- ruleResults = append (ruleResults , g .Component .Violations ... )
74- ruleResults = append (ruleResults , g .Component .Warnings ... )
75- ruleResults = append (ruleResults , g .Component .Successes ... )
76-
77- validationResult := "failed"
78- if g .Component .Success {
79- validationResult = "passed"
80- }
81-
82121 policySource := ""
83122 if g .Report .Policy .Name != "" {
84123 policySource = g .Report .Policy .Name
85124 }
86125
126+ // Filter the report to include only the target component and its architecture variants
127+ filteredReport := FilterReportForComponent (g .Report , g .Component .Name )
128+
87129 return & Predicate {
88- ImageRef : g .Component .ContainerImage ,
89- ValidationResult : validationResult ,
90- Timestamp : time .Now ().UTC ().Format (time .RFC3339 ),
91- Verifier : "ec-cli" ,
92- PolicySource : policySource ,
93- Component : componentInfo ,
94- RuleResults : ruleResults ,
130+ ImageRef : g .Component .ContainerImage ,
131+ Timestamp : time .Now ().UTC ().Format (time .RFC3339 ),
132+ Verifier : "ec-cli" ,
133+ PolicySource : policySource ,
134+ Component : componentInfo ,
135+ Results : filteredReport ,
95136 }, nil
96137}
97138
0 commit comments