Skip to content

Commit 3cd47ce

Browse files
authored
Merge pull request #19 from nchelluri/nchelluri/allow-specifying-doctype
Add flags and payload values to facilitate OpenVEX
2 parents 6cc245c + 16c6d0b commit 3cd47ce

File tree

2 files changed

+60
-28
lines changed

2 files changed

+60
-28
lines changed

main.go

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,8 @@ type DocumentType string
5959

6060
// Document* is the enumerables of DocumentType
6161
const (
62-
DocumentITE6SLSA DocumentType = "SLSA"
63-
DocumentITE6Generic DocumentType = "ITE6"
64-
DocumentITE6Vul DocumentType = "ITE6VUL"
65-
DocumentITE6EOL DocumentType = "ITE6EOL"
66-
// ClearlyDefined
67-
DocumentITE6ClearlyDefined DocumentType = "ITE6CD"
68-
DocumentDSSE DocumentType = "DSSE"
69-
DocumentSPDX DocumentType = "SPDX"
70-
DocumentOpaque DocumentType = "OPAQUE"
71-
DocumentScorecard DocumentType = "SCORECARD"
72-
DocumentCycloneDX DocumentType = "CycloneDX"
73-
DocumentDepsDev DocumentType = "DEPS_DEV"
74-
DocumentCsaf DocumentType = "CSAF"
75-
DocumentOpenVEX DocumentType = "OPEN_VEX"
76-
DocumentIngestPredicates DocumentType = "INGEST_PREDICATES"
77-
DocumentUnknown DocumentType = "UNKNOWN"
62+
DocumentSBOM DocumentType = "SBOM"
63+
DocumentOpenVEX DocumentType = "OPEN_VEX"
7864
)
7965

8066
// FormatType describes the document format for malform checks
@@ -142,6 +128,10 @@ func main() {
142128
rootCmd.Flags().StringP("token-endpoint", "k", "", "Token endpoint URL (required)")
143129
rootCmd.Flags().StringP("alias", "a", "", "Alias that supersedes the subject in Kusari platform (optional)")
144130
rootCmd.Flags().StringP("document-type", "d", "", "Type of the document (image or build) sbom (optional)")
131+
rootCmd.Flags().Bool("open-vex", false, "Indicate that this is an OpenVEX document (optional, only works with files)")
132+
rootCmd.Flags().String("tag", "", "Tag value to set in the document wrapper upload meta (optional, e.g. govulncheck)")
133+
rootCmd.Flags().String("software-id", "", "Kusari Platform Software ID value to set in the document wrapper upload meta (optional)")
134+
rootCmd.Flags().String("sbom-subject", "", "Kusari Platform Software sbom subject substring value to set in the document wrapper upload meta (optional)")
145135

146136
// Bind flags to Viper with error handling
147137
mustBindPFlag(rootCmd, "file-path")
@@ -151,6 +141,10 @@ func main() {
151141
mustBindPFlag(rootCmd, "token-endpoint")
152142
mustBindPFlag(rootCmd, "alias")
153143
mustBindPFlag(rootCmd, "document-type")
144+
mustBindPFlag(rootCmd, "open-vex")
145+
mustBindPFlag(rootCmd, "tag")
146+
mustBindPFlag(rootCmd, "software-id")
147+
mustBindPFlag(rootCmd, "sbom-subject")
154148

155149
// Allow environment variables
156150
viper.SetEnvPrefix("UPLOADER")
@@ -205,12 +199,21 @@ func uploadFiles(cmd *cobra.Command, args []string) {
205199
tokenEndPoint := viper.GetString("token-endpoint")
206200
alias := viper.GetString("alias")
207201
docType := viper.GetString("document-type")
202+
isOpenVex := viper.GetBool("open-vex")
203+
tag := viper.GetString("tag")
204+
softwareID := viper.GetString("software-id")
205+
sbomSubject := viper.GetString("sbom-subject")
208206

209207
// Validate required configuration
210208
if filePath == "" || clientID == "" || clientSecret == "" ||
211209
tenantEndPoint == "" || tokenEndPoint == "" {
212210
log.Fatal().Msg("All required parameters must be provided")
213211
}
212+
213+
if isOpenVex && (tag == "" || (softwareID == "" && sbomSubject == "")) {
214+
log.Fatal().Msg("When using OpenVEX, tag must be specified, and so must software-id or sbom-subject")
215+
}
216+
214217
// Get authorized client
215218
authorizedClient := getAuthorizedClient(ctx, clientID, clientSecret, tokenEndPoint)
216219
defaultClient := &http.Client{}
@@ -223,13 +226,26 @@ func uploadFiles(cmd *cobra.Command, args []string) {
223226
Msg("Error getting file info")
224227
}
225228

229+
if fileInfo.IsDir() && isOpenVex {
230+
log.Fatal().Msg("OpenVEX can't be used with directories, only single files")
231+
}
232+
226233
uploadMeta := map[string]string{}
227234
if alias != "" {
228235
uploadMeta["alias"] = alias
229236
}
230237
if docType != "" {
231238
uploadMeta["type"] = docType
232239
}
240+
if tag != "" {
241+
uploadMeta["tag"] = tag
242+
}
243+
if softwareID != "" {
244+
uploadMeta["software_id"] = softwareID
245+
}
246+
if sbomSubject != "" {
247+
uploadMeta["sbom_subject"] = sbomSubject
248+
}
233249

234250
// Upload based on file type
235251
if fileInfo.IsDir() {
@@ -239,7 +255,7 @@ func uploadFiles(cmd *cobra.Command, args []string) {
239255
Msg("Directory upload failed")
240256
}
241257
} else {
242-
if err := uploadSingleFile(authorizedClient, defaultClient, tenantEndPoint, filePath, uploadMeta); err != nil {
258+
if err := uploadSingleFile(authorizedClient, defaultClient, tenantEndPoint, filePath, isOpenVex, uploadMeta); err != nil {
243259
log.Fatal().
244260
Err(err).
245261
Msg("Single file upload failed")
@@ -297,14 +313,13 @@ func getPresignedUrl(authorizedClient HttpClient, tenantApiEndpoint string, payl
297313
}
298314

299315
// uploadDirectory uses filepath.Walk to walk through the directory and upload the files that are found
300-
func uploadDirectory(authorizedClient, defaultClient HttpClient, tenantApiEndpoint,
301-
dirPath string, uploadMeta map[string]string) error {
316+
func uploadDirectory(authorizedClient, defaultClient HttpClient, tenantApiEndpoint, dirPath string, uploadMeta map[string]string) error {
302317
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
303318
if err != nil {
304319
return err
305320
}
306321
if !info.IsDir() {
307-
err = uploadSingleFile(authorizedClient, defaultClient, tenantApiEndpoint, path, uploadMeta)
322+
err = uploadSingleFile(authorizedClient, defaultClient, tenantApiEndpoint, path, false, uploadMeta)
308323
if err != nil {
309324
return fmt.Errorf("uploadSingleFile failed with error: %w", err)
310325
}
@@ -315,7 +330,8 @@ func uploadDirectory(authorizedClient, defaultClient HttpClient, tenantApiEndpoi
315330
}
316331

317332
// uploadSingleFile creates a presigned URL for the filepath and calls uploadFile to upload the actual file
318-
func uploadSingleFile(authorizedClient, defaultClient HttpClient, tenantApiEndpoint, filePath string, uploadMeta map[string]string) error {
333+
func uploadSingleFile(authorizedClient, defaultClient HttpClient, tenantApiEndpoint, filePath string, isOpenVex bool,
334+
uploadMeta map[string]string) error {
319335
// check that the file is not empty
320336
checkFile, err := os.Stat(filePath)
321337
if err != nil {
@@ -345,14 +361,21 @@ func uploadSingleFile(authorizedClient, defaultClient HttpClient, tenantApiEndpo
345361
}
346362

347363
// pass in default client without the jwt other wise it will error with both the presigned url and jwt
348-
return uploadBlob(defaultClient, presignedUrl, filePath, blob, uploadMeta)
364+
return uploadBlob(defaultClient, presignedUrl, filePath, blob, isOpenVex, uploadMeta)
349365
}
350366

351367
// uploadBlob takes the file and creates a `processor.Document` blob which is uploaded to S3
352-
func uploadBlob(defaultClient HttpClient, presignedUrl, filePath string, readFile []byte, uploadMeta map[string]string) error {
368+
func uploadBlob(defaultClient HttpClient, presignedUrl, filePath string, readFile []byte, isOpenVex bool,
369+
uploadMeta map[string]string) error {
370+
371+
doctype := DocumentSBOM
372+
if isOpenVex {
373+
doctype = DocumentOpenVEX
374+
}
375+
353376
baseDoc := &Document{
354377
Blob: readFile,
355-
Type: DocumentUnknown,
378+
Type: doctype,
356379
Format: FormatUnknown,
357380
SourceInformation: SourceInformation{
358381
Collector: "Kusari-Uploader",

main_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818
import (
1919
"bytes"
2020
"encoding/json"
21+
"fmt"
2122
"io"
2223
"net/http"
2324
"testing"
@@ -268,8 +269,12 @@ func Test_uploadSingleFile(t *testing.T) {
268269
}
269270
for _, tt := range tests {
270271
t.Run(tt.name, func(t *testing.T) {
271-
if err := uploadSingleFile(tt.args.authenticatedClient, tt.args.defaultClient, tt.args.tenantApiEndpoint, tt.args.filePath, tt.args.uploadMeta); (err != nil) != tt.wantErr {
272-
t.Errorf("uploadSingleFile() error = %v, wantErr %v", err, tt.wantErr)
272+
for _, isOpenVex := range []bool{false, true} {
273+
t.Run(fmt.Sprintf("isOpenVex is %v", isOpenVex), func(t *testing.T) {
274+
if err := uploadSingleFile(tt.args.authenticatedClient, tt.args.defaultClient, tt.args.tenantApiEndpoint, tt.args.filePath, isOpenVex, tt.args.uploadMeta); (err != nil) != tt.wantErr {
275+
t.Errorf("uploadSingleFile() error = %v, wantErr %v", err, tt.wantErr)
276+
}
277+
})
273278
}
274279
})
275280
}
@@ -350,8 +355,12 @@ func Test_uploadBlob(t *testing.T) {
350355
}
351356
for _, tt := range tests {
352357
t.Run(tt.name, func(t *testing.T) {
353-
if err := uploadBlob(tt.args.authenticatedClient, tt.args.presignedUrl, tt.args.filePath, []byte("hello"), tt.args.uploadMeta); (err != nil) != tt.wantErr {
354-
t.Errorf("uploadFile() error = %v, wantErr %v", err, tt.wantErr)
358+
for _, isOpenVex := range []bool{false, true} {
359+
t.Run(fmt.Sprintf("isOpenVex is %v", isOpenVex), func(t *testing.T) {
360+
if err := uploadBlob(tt.args.authenticatedClient, tt.args.presignedUrl, tt.args.filePath, []byte("hello"), isOpenVex, tt.args.uploadMeta); (err != nil) != tt.wantErr {
361+
t.Errorf("uploadFile() error = %v, wantErr %v", err, tt.wantErr)
362+
}
363+
})
355364
}
356365
})
357366
}

0 commit comments

Comments
 (0)