@@ -91,22 +91,46 @@ func executeUploadSBOM(imageRef string) int {
9191 "org" : sbomOrg ,
9292 })
9393
94- // Generate SBOM with Trivy
94+ sbomPath , err := generateSBOM (imageRef )
95+ if err != nil {
96+ return 2
97+ }
98+ defer os .Remove (sbomPath )
99+
100+ fmt .Printf ("Uploading SBOM to Codacy (org: %s/%s)...\n " , sbomProvider , sbomOrg )
101+ params := sbomUploadParams {
102+ provider : sbomProvider ,
103+ org : sbomOrg ,
104+ apiToken : sbomAPIToken ,
105+ repoName : sbomRepoName ,
106+ env : sbomEnv ,
107+ }
108+ if err := uploadSBOMToCodacy (sbomPath , sbomImageName , tag , params ); err != nil {
109+ logger .Error ("Failed to upload SBOM" , logrus.Fields {"error" : err .Error ()})
110+ color .Red ("Error: Failed to upload SBOM: %v" , err )
111+ return 1
112+ }
113+
114+ color .Green ("Successfully uploaded SBOM for %s:%s" , sbomImageName , tag )
115+ return 0
116+ }
117+
118+ // generateSBOM runs Trivy to generate an SBOM file and returns the path to it.
119+ func generateSBOM (imageRef string ) (string , error ) {
95120 trivyPath , err := getTrivyPath ()
96121 if err != nil {
97122 handleTrivyNotFound (err )
98- return 2
123+ return "" , err
99124 }
100125
101126 tmpFile , err := os .CreateTemp ("" , "codacy-sbom-*" )
102127 if err != nil {
103128 logger .Error ("Failed to create temp file" , logrus.Fields {"error" : err .Error ()})
104129 color .Red ("Error: Failed to create temporary file: %v" , err )
105- return 2
130+ return "" , err
106131 }
107132 tmpFile .Close ()
108133 sbomPath := tmpFile .Name ()
109- defer os .Remove (sbomPath )
110134
111135 fmt .Printf ("Generating SBOM for image: %s\n " , imageRef )
112136 args := []string {"image" , "--format" , sbomFormat , "-o" , sbomPath , imageRef }
@@ -120,20 +144,11 @@ func executeUploadSBOM(imageRef string) int {
120144 color .Red ("Error: Failed to generate SBOM: %v" , err )
121145 }
122146 logger .Error ("Trivy SBOM generation failed" , logrus.Fields {"error" : err .Error ()})
123- return 2
147+ os .Remove (sbomPath )
148+ return "" , err
124149 }
125150 fmt .Println ("SBOM generated successfully" )
126-
127- // Upload SBOM to Codacy
128- fmt .Printf ("Uploading SBOM to Codacy (org: %s/%s)...\n " , sbomProvider , sbomOrg )
129- if err := uploadSBOMToCodacy (sbomPath , sbomImageName , tag ); err != nil {
130- logger .Error ("Failed to upload SBOM" , logrus.Fields {"error" : err .Error ()})
131- color .Red ("Error: Failed to upload SBOM: %v" , err )
132- return 1
133- }
134-
135- color .Green ("Successfully uploaded SBOM for %s:%s" , sbomImageName , tag )
136- return 0
151+ return sbomPath , nil
137152}
138153
139154// parseImageRef splits an image reference into name and tag.
@@ -162,38 +177,23 @@ func parseImageRef(imageRef string) (string, string) {
162177 return imageRef , "latest"
163178}
164179
165- func uploadSBOMToCodacy (sbomPath , imageName , tag string ) error {
180+ type sbomUploadParams struct {
181+ provider string
182+ org string
183+ apiToken string
184+ repoName string
185+ env string
186+ }
187+
188+ func uploadSBOMToCodacy (sbomPath , imageName , tag string , params sbomUploadParams ) error {
166189 url := fmt .Sprintf ("https://app.codacy.com/api/v3/organizations/%s/%s/image-sboms" ,
167- sbomProvider , sbomOrg )
190+ params . provider , params . org )
168191
169192 body := & bytes.Buffer {}
170193 writer := multipart .NewWriter (body )
171194
172- // Add the SBOM file
173- sbomFile , err := os .Open (sbomPath )
174- if err != nil {
175- return fmt .Errorf ("failed to open SBOM file: %w" , err )
176- }
177- defer sbomFile .Close ()
178-
179- part , err := writer .CreateFormFile ("sbom" , filepath .Base (sbomPath ))
180- if err != nil {
181- return fmt .Errorf ("failed to create form file: %w" , err )
182- }
183- if _ , err := io .Copy (part , sbomFile ); err != nil {
184- return fmt .Errorf ("failed to write SBOM to form: %w" , err )
185- }
186-
187- // Add required fields
188- writer .WriteField ("imageName" , imageName )
189- writer .WriteField ("tag" , tag )
190-
191- // Add optional fields
192- if sbomRepoName != "" {
193- writer .WriteField ("repositoryName" , sbomRepoName )
194- }
195- if sbomEnv != "" {
196- writer .WriteField ("environment" , sbomEnv )
195+ if err := buildSBOMMultipartForm (writer , sbomPath , imageName , tag , params ); err != nil {
196+ return err
197197 }
198198
199199 if err := writer .Close (); err != nil {
@@ -206,7 +206,7 @@ func uploadSBOMToCodacy(sbomPath, imageName, tag string) error {
206206 }
207207 req .Header .Set ("Content-Type" , writer .FormDataContentType ())
208208 req .Header .Set ("Accept" , "application/json" )
209- req .Header .Set ("api-token" , sbomAPIToken )
209+ req .Header .Set ("api-token" , params . apiToken )
210210
211211 resp , err := http .DefaultClient .Do (req )
212212 if err != nil {
@@ -221,3 +221,40 @@ func uploadSBOMToCodacy(sbomPath, imageName, tag string) error {
221221
222222 return nil
223223}
224+
225+ // buildSBOMMultipartForm populates the multipart form with the SBOM file and metadata fields.
226+ func buildSBOMMultipartForm (writer * multipart.Writer , sbomPath , imageName , tag string , params sbomUploadParams ) error {
227+ sbomFile , err := os .Open (sbomPath )
228+ if err != nil {
229+ return fmt .Errorf ("failed to open SBOM file: %w" , err )
230+ }
231+ defer sbomFile .Close ()
232+
233+ part , err := writer .CreateFormFile ("sbom" , filepath .Base (sbomPath ))
234+ if err != nil {
235+ return fmt .Errorf ("failed to create form file: %w" , err )
236+ }
237+ if _ , err := io .Copy (part , sbomFile ); err != nil {
238+ return fmt .Errorf ("failed to write SBOM to form: %w" , err )
239+ }
240+
241+ if err := writer .WriteField ("imageName" , imageName ); err != nil {
242+ return fmt .Errorf ("failed to write imageName field: %w" , err )
243+ }
244+ if err := writer .WriteField ("tag" , tag ); err != nil {
245+ return fmt .Errorf ("failed to write tag field: %w" , err )
246+ }
247+
248+ if params .repoName != "" {
249+ if err := writer .WriteField ("repositoryName" , params .repoName ); err != nil {
250+ return fmt .Errorf ("failed to write repositoryName field: %w" , err )
251+ }
252+ }
253+ if params .env != "" {
254+ if err := writer .WriteField ("environment" , params .env ); err != nil {
255+ return fmt .Errorf ("failed to write environment field: %w" , err )
256+ }
257+ }
258+
259+ return nil
260+ }
0 commit comments