github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/pkg/utils/build/task_results.go (about) 1 package build 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 8 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 9 pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 10 "k8s.io/apimachinery/pkg/types" 11 12 crclient "sigs.k8s.io/controller-runtime/pkg/client" 13 ) 14 15 var taskNames = []string{"clair-scan", "clamav-scan", "deprecated-base-image-check", "inspect-image", "sbom-json-check"} 16 17 type TestOutput struct { 18 Result string `json:"result"` 19 Timestamp string `json:"timestamp"` 20 Note string `json:"note"` 21 Namespace string `json:"namespace"` 22 Successes int `json:"successes"` 23 Failures int `json:"failures"` 24 Warnings int `json:"warnings"` 25 } 26 27 type ClairScanResult struct { 28 Vulnerabilities Vulnerabilities `json:"vulnerabilities"` 29 } 30 31 type Vulnerabilities struct { 32 Critical int `json:"critical"` 33 High int `json:"high"` 34 Medium int `json:"medium"` 35 Low int `json:"low"` 36 } 37 38 type PipelineBuildInfo struct { 39 runtime string 40 strategy string 41 } 42 43 func GetPipelineBuildInfo(pr *pipeline.PipelineRun) PipelineBuildInfo { 44 labels := pr.GetLabels() 45 runtime := labels["pipelines.openshift.io/runtime"] 46 strategy := labels["pipelines.openshift.io/strategy"] 47 return PipelineBuildInfo{ 48 runtime: runtime, 49 strategy: strategy, 50 } 51 } 52 53 func IsDockerBuild(pr *pipeline.PipelineRun) bool { 54 info := GetPipelineBuildInfo(pr) 55 return info.runtime == "generic" && info.strategy == "docker" 56 } 57 58 func IsFBCBuild(pr *pipeline.PipelineRun) bool { 59 info := GetPipelineBuildInfo(pr) 60 return info.runtime == "fbc" && info.strategy == "fbc" 61 } 62 63 func ValidateBuildPipelineTestResults(pipelineRun *pipeline.PipelineRun, c crclient.Client) error { 64 for _, taskName := range taskNames { 65 // The inspect-image task is only required for FBC pipelines which we can infer by the component name 66 isFBCBuild := IsFBCBuild(pipelineRun) 67 68 if !isFBCBuild && taskName == "inspect-image" { 69 continue 70 } 71 if isFBCBuild && (taskName == "clair-scan" || taskName == "clamav-scan") { 72 continue 73 } 74 results, err := fetchTaskRunResults(c, pipelineRun, taskName) 75 if err != nil { 76 return err 77 } 78 79 resultsToValidate := []string{constants.TektonTaskTestOutputName} 80 81 switch taskName { 82 case "clair-scan": 83 resultsToValidate = append(resultsToValidate, "CLAIR_SCAN_RESULT") 84 case "deprecated-image-check": 85 resultsToValidate = append(resultsToValidate, "PYXIS_HTTP_CODE") 86 case "inspect-image": 87 resultsToValidate = append(resultsToValidate, "BASE_IMAGE", "BASE_IMAGE_REPOSITORY") 88 } 89 90 if err := validateTaskRunResult(results, resultsToValidate, taskName); err != nil { 91 return err 92 } 93 94 } 95 return nil 96 } 97 98 func fetchTaskRunResults(c crclient.Client, pr *pipeline.PipelineRun, pipelineTaskName string) ([]pipeline.TaskRunResult, error) { 99 for _, chr := range pr.Status.ChildReferences { 100 if chr.PipelineTaskName != pipelineTaskName { 101 continue 102 } 103 taskRun := &pipeline.TaskRun{} 104 taskRunKey := types.NamespacedName{Namespace: pr.Namespace, Name: chr.Name} 105 if err := c.Get(context.Background(), taskRunKey, taskRun); err != nil { 106 return nil, err 107 } 108 return taskRun.Status.TaskRunStatusFields.Results, nil 109 } 110 return nil, fmt.Errorf( 111 "pipelineTaskName %q not found in PipelineRun %s/%s", pipelineTaskName, pr.GetName(), pr.GetNamespace()) 112 } 113 114 func validateTaskRunResult(trResults []pipeline.TaskRunResult, expectedResultNames []string, taskName string) error { 115 for _, rn := range expectedResultNames { 116 found := false 117 for _, r := range trResults { 118 if rn == r.Name { 119 found = true 120 switch r.Name { 121 case constants.TektonTaskTestOutputName: 122 var testOutput = &TestOutput{} 123 err := json.Unmarshal([]byte(r.Value.StringVal), &testOutput) 124 if err != nil { 125 return fmt.Errorf("cannot parse %q result: %+v", constants.TektonTaskTestOutputName, err) 126 } 127 // If the test result isn't SUCCESS, the overall outcome is a failure 128 if taskName == "sbom-json-check" { 129 if testOutput.Result == "FAILURE" { 130 return fmt.Errorf("expected Result for Task name %q to be SUCCESS: %+v", taskName, testOutput) 131 } 132 } 133 case "CLAIR_SCAN_RESULT": 134 var testOutput = &ClairScanResult{} 135 err := json.Unmarshal([]byte(r.Value.StringVal), &testOutput) 136 if err != nil { 137 return fmt.Errorf("cannot parse CLAIR_SCAN_RESULT result: %+v", err) 138 } 139 case "PYXIS_HTTP_CODE", "BASE_IMAGE", "BASE_IMAGE_REPOSITORY": 140 if len(r.Value.StringVal) < 1 { 141 return fmt.Errorf("value of %q result is empty", r.Name) 142 } 143 } 144 } 145 } 146 if !found { 147 return fmt.Errorf("expected result name %q not found in Task %q result", rn, taskName) 148 } 149 } 150 return nil 151 }