-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
241 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package client | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"mime/multipart" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/kondukto-io/kdt/klog" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func (c *Client) ImportSBOM(file string, repo string, form ImportForm) error { | ||
klog.Debugf("importing sbom content using file:%s", file) | ||
|
||
projectId := form["project"] | ||
|
||
if projectId != "" { | ||
projects, err := c.ListProjects(projectId, repo) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if len(projects) == 0 { | ||
return errors.New("no projects found for given parameters") | ||
} | ||
|
||
if len(projects) == 1 { | ||
projectId = projects[0].ID | ||
form["project"] = projects[0].Name | ||
} | ||
|
||
if len(projects) > 1 { | ||
return errors.New("multiple projects found for given parameters") | ||
} | ||
} else { | ||
projects, err := c.ListProjects(projectId, repo) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if len(projects) == 0 { | ||
return errors.New("no projects found for given parameters") | ||
} | ||
|
||
if len(projects) == 1 { | ||
projectId = projects[0].ID | ||
form["project"] = projects[0].Name | ||
} | ||
|
||
if len(projects) > 1 { | ||
return errors.New("multiple projects found for given parameters") | ||
} | ||
} | ||
|
||
path := fmt.Sprintf("/api/v2/%s/sbom/upload", projectId) | ||
rel := &url.URL{Path: path} | ||
u := c.BaseURL.ResolveReference(rel) | ||
|
||
body := &bytes.Buffer{} | ||
writer := multipart.NewWriter(body) | ||
|
||
if _, err := os.Stat(file); os.IsNotExist(err) { | ||
return err | ||
} | ||
f, err := os.Open(file) | ||
if err != nil { | ||
return err | ||
} | ||
defer func() { _ = f.Close() }() | ||
part, err := writer.CreateFormFile("file", filepath.Base(f.Name())) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = io.Copy(part, f) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for k := range form { | ||
if err = writer.WriteField(k, form[k]); err != nil { | ||
return fmt.Errorf("failed to write form field [%s]: %w", k, err) | ||
} | ||
} | ||
|
||
_ = writer.Close() | ||
|
||
req, err := http.NewRequest(http.MethodPost, u.String(), body) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
req.Header.Add("Content-Type", writer.FormDataContentType()) | ||
|
||
req.Header.Set("Accept", "application/json") | ||
req.Header.Set("User-Agent", userAgent) | ||
req.Header.Set("X-Cookie", viper.GetString("token")) | ||
|
||
type importSBOMResponse struct { | ||
Message string `json:"message"` | ||
Error string `json:"error"` | ||
} | ||
|
||
var importResponse importSBOMResponse | ||
resp, err := c.do(req, &importResponse) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
return fmt.Errorf("failed to import sbom: %s, status code: %s", importResponse.Error, resp.StatusCode) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package cmd | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/kondukto-io/kdt/client" | ||
"github.com/kondukto-io/kdt/klog" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// sbomCmd represents the sbom root command | ||
var sbomCmd = &cobra.Command{ | ||
Use: "sbom", | ||
Short: "base command for SBOM(Software bill of materials) imports", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if len(args) == 0 { | ||
_ = cmd.Help() | ||
qwm(ExitCodeSuccess, "") | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(sbomCmd) | ||
|
||
sbomCmd.AddCommand(importSbomCmd) | ||
|
||
importSbomCmd.Flags().StringP("file", "f", "", "SBOM file to be imported. Currently only .json format is supported") | ||
importSbomCmd.Flags().StringP("project", "p", "", "Kondukto project id or name") | ||
importSbomCmd.Flags().StringP("repo-id", "r", "", "URL or ID of ALM repository") | ||
importSbomCmd.Flags().StringP("sbom-type", "s", "", "Custom type(optional). Passing a different value than existing type(i.e application, container etc.) is advised") | ||
importSbomCmd.Flags().StringP("branch", "b", "", "Branch name for the project receiving the sbom") | ||
} | ||
|
||
// importSbomCmd represents the sbom import command | ||
var importSbomCmd = &cobra.Command{ | ||
Use: "import", | ||
Short: "imports sbom file to Kondukto", | ||
Run: importSbomRootCommand, | ||
} | ||
|
||
func importSbomRootCommand(cmd *cobra.Command, _ []string) { | ||
// Initialize Kondukto client | ||
c, err := client.New() | ||
if err != nil { | ||
qwe(ExitCodeError, err, "could not initialize Kondukto client") | ||
} | ||
sbomImport := SBOMImport{ | ||
cmd: cmd, | ||
client: c, | ||
} | ||
if err = sbomImport.sbomImport(); err != nil { | ||
qwe(ExitCodeError, err, "failed to import sbom file") | ||
} | ||
} | ||
|
||
type SBOMImport struct { | ||
cmd *cobra.Command | ||
client *client.Client | ||
} | ||
|
||
func (s *SBOMImport) sbomImport() error { | ||
// Parse command line flags needed for file uploads | ||
file, err := s.cmd.Flags().GetString("file") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse file flag: %w", err) | ||
} | ||
|
||
if !s.cmd.Flags().Changed("repo-id") && !s.cmd.Flags().Changed("project") { | ||
return errors.New("missing a required flag(repo or project) to get project detail") | ||
} | ||
|
||
projectName, err := s.cmd.Flags().GetString("project") | ||
if err != nil { | ||
return fmt.Errorf("failed to get project flag: %w", err) | ||
} | ||
|
||
branch, err := s.cmd.Flags().GetString("branch") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse branch flag: %w", err) | ||
} | ||
|
||
repo, err := s.cmd.Flags().GetString("repo-id") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse repo-id flag: %w", err) | ||
} | ||
|
||
sbomType, err := s.cmd.Flags().GetString("sbom-type") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse sbom-type flag: %w", err) | ||
} | ||
|
||
var form = client.ImportForm{ | ||
"project": projectName, | ||
"branch": branch, | ||
"sbom_type": sbomType, | ||
} | ||
|
||
err = s.client.ImportSBOM(file, repo, form) | ||
if err != nil { | ||
return fmt.Errorf("failed to import scan results: %w", err) | ||
} | ||
|
||
importInfo := "" | ||
if projectName == "" { | ||
importInfo = fmt.Sprintf("%s(ALM)", repo) | ||
} else { | ||
importInfo = fmt.Sprintf("%s(kondukto project)", projectName) | ||
} | ||
|
||
klog.Printf("sbom file imported successfully for: [%s]", importInfo) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters