From 58b67af6df927c8420fda8cb184adf3653020535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Engin=20A=C3=A7=C4=B1kg=C3=B6z?= Date: Mon, 27 May 2024 18:27:43 +0300 Subject: [PATCH 1/4] Remove V1 endpoints, use V2 instead of. And improve some logics --- client/projects.go | 22 ++++++++-------- client/scanners.go | 62 ++++++++++++++++++++++++++++++++++++++++++--- client/scans.go | 54 ++++++++++++++++++++++++++------------- cmd/listScanners.go | 11 +++++--- cmd/project.go | 6 ++--- cmd/scan.go | 4 +-- 6 files changed, 118 insertions(+), 41 deletions(-) diff --git a/client/projects.go b/client/projects.go index cebb79b..0e4888b 100755 --- a/client/projects.go +++ b/client/projects.go @@ -45,7 +45,7 @@ func (c *Client) ListProjects(name, repo string) ([]Project, error) { klog.Debug("retrieving project list...") - req, err := c.newRequest("GET", "/api/v1/projects", nil) + req, err := c.newRequest("GET", "/api/v2/projects", nil) if err != nil { return projects, err } @@ -141,20 +141,18 @@ func (c *Client) CreateProject(pd ProjectDetail) (*Project, error) { } type ReleaseStatus struct { - Status string `json:"status" bson:"status"` - SAST PlaybookTypeDetail `json:"sast" bson:"sast"` - DAST PlaybookTypeDetail `json:"dast" bson:"dast"` - PENTEST PlaybookTypeDetail `json:"pentest" bson:"pentest"` - IAST PlaybookTypeDetail `json:"iast" bson:"iast"` - SCA PlaybookTypeDetail `json:"sca" bson:"sca"` - CS PlaybookTypeDetail `json:"cs" bson:"cs"` - IAC PlaybookTypeDetail `json:"iac" bson:"iac"` + Status string `json:"status"` + SAST PlaybookTypeDetail `json:"sast"` + DAST PlaybookTypeDetail `json:"dast"` + PENTEST PlaybookTypeDetail `json:"pentest"` + IAST PlaybookTypeDetail `json:"iast"` + SCA PlaybookTypeDetail `json:"sca"` + CS PlaybookTypeDetail `json:"cs"` + IAC PlaybookTypeDetail `json:"iac"` } type PlaybookTypeDetail struct { - Tool string `json:"tool" bson:"tool"` Status string `json:"status" bson:"status"` - Manual bool `json:"manual" bson:"manual"` ScanID string `json:"scan_id,omitempty" bson:"scan_id"` } @@ -163,7 +161,7 @@ func (c *Client) ReleaseStatus(project, branch string) (*ReleaseStatus, error) { return nil, errors.New("missing project id or name") } - path := fmt.Sprintf("/api/v1/projects/%s/release", project) + path := fmt.Sprintf("/api/v2/projects/%s/release", project) req, err := c.newRequest("GET", path, nil) if err != nil { diff --git a/client/scanners.go b/client/scanners.go index 357f264..71dd446 100644 --- a/client/scanners.go +++ b/client/scanners.go @@ -15,6 +15,30 @@ import ( "github.com/google/go-querystring/query" ) +type ScannerType string + +const ( + ScannerTypeSAST ScannerType = "sast" + ScannerTypeDAST ScannerType = "dast" + ScannerTypeSCA ScannerType = "sca" + ScannerTypeCS ScannerType = "cs" + ScannerTypeIAC ScannerType = "iac" + ScannerTypeIAST ScannerType = "iast" + ScannerTypeCSPM ScannerType = "cspm" + ScannerTypeMAST ScannerType = "mast" +) + +func (s ScannerType) String() string { + return string(s) +} + +func ScannerTypes() []ScannerType { + return []ScannerType{ + ScannerTypeSAST, ScannerTypeDAST, ScannerTypeSCA, ScannerTypeCS, + ScannerTypeIAC, ScannerTypeIAST, ScannerTypeCSPM, ScannerTypeMAST, + } +} + type ( ScannersSearchParams struct { Types string `url:"types"` @@ -117,17 +141,45 @@ const ( ScannerLabelCreatableOnTool = "creatable-on-tool" ) +type ListActiveScannersInput struct { + Types []ScannerType + Labels string + Name string + Limit int +} + +func (i *ListActiveScannersInput) prepareRequestQueryParameters() ScannersSearchParams { + var scannerTypes = make([]string, 0) + + if i.Types == nil || len(i.Types) == 0 { + for _, t := range ScannerTypes() { + scannerTypes = append(scannerTypes, t.String()) + } + } else { + for _, t := range i.Types { + scannerTypes = append(scannerTypes, t.String()) + } + } + + return ScannersSearchParams{ + Types: strings.Join(scannerTypes, ","), + Labels: i.Labels, + Name: i.Name, + Limit: i.Limit, + } +} + // ListActiveScanners returns a list of active scanners -func (c *Client) ListActiveScanners(params *ScannersSearchParams) (*ScannersResponse, error) { +func (c *Client) ListActiveScanners(input *ListActiveScannersInput) (*ScannersResponse, error) { klog.Debugf("retrieving active scanners") - path := fmt.Sprintf("/api/v1/scanners/active") + path := fmt.Sprintf("/api/v2/scanners/active") req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { return nil, err } - v, err := query.Values(params) + v, err := query.Values(input.prepareRequestQueryParameters()) if err != nil { return nil, err } @@ -150,7 +202,9 @@ func (c *Client) ListActiveScanners(params *ScannersSearchParams) (*ScannersResp func (c *Client) IsValidTool(tool string) bool { klog.Debugf("validating given tool name [%s]", tool) - scanners, err := c.ListActiveScanners(&ScannersSearchParams{Name: tool}) + scanners, err := c.ListActiveScanners(&ListActiveScannersInput{ + Name: tool, + }) if err != nil { klog.Debugf("failed to get active tools: %v", err) return false diff --git a/client/scans.go b/client/scans.go index 86e1ca5..bf2002c 100755 --- a/client/scans.go +++ b/client/scans.go @@ -24,6 +24,15 @@ import ( ) type ( + ImageScanParams struct { + Project string `json:"project"` + Tool string `json:"tool"` + Branch string `json:"branch"` + Image string `json:"image"` + MetaData string `json:"meta_data"` + Environment string `json:"environment"` + } + ScanDetail struct { ID string `json:"id"` Name string `json:"name"` @@ -156,7 +165,7 @@ func (c *Client) CreateNewScan(scan *Scan) (string, error) { func (c *Client) RestartScanByScanID(id string) (string, error) { klog.Debug("starting scan by scan_id") - path := fmt.Sprintf("/api/v1/scans/%s/restart", id) + path := fmt.Sprintf("/api/v2/scans/%s/restart", id) req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { return "", err @@ -180,7 +189,7 @@ func (c *Client) RestartScanWithOption(id string, opt *ScanPROptions) (string, e return "", errors.New("missing scan options") } - path := fmt.Sprintf("/api/v1/scans/%s/restart_with_option", id) + path := fmt.Sprintf("/api/v2/scans/%s/restart_with_option", id) req, err := c.newRequest(http.MethodPost, path, opt) if err != nil { return "", err @@ -207,19 +216,30 @@ func (c *Client) RestartScanWithOption(id string, opt *ScanPROptions) (string, e return rsr.Event, nil } -type ImageScanParams struct { - Project string `json:"project"` - Tool string `json:"tool"` - Branch string `json:"branch"` - Image string `json:"image"` - MetaData string `json:"meta_data"` - Environment string `json:"environment"` +type ScanByImageInput struct { + Project string + Tool string + Branch string + Image string + MetaData string + Environment string +} + +func (i *ScanByImageInput) prepareRequestQueryParameters() ImageScanParams { + return ImageScanParams{ + Project: i.Project, + Tool: i.Tool, + Branch: i.Branch, + Image: i.Image, + MetaData: i.MetaData, + Environment: i.Environment, + } } -func (c *Client) ScanByImage(pr *ImageScanParams) (string, error) { - path := "/api/v1/scans/image" +func (c *Client) ScanByImage(pr *ScanByImageInput) (string, error) { + path := "/api/v2/scans/image" - req, err := c.newRequest(http.MethodPost, path, pr) + req, err := c.newRequest(http.MethodPost, path, pr.prepareRequestQueryParameters()) if err != nil { return "", fmt.Errorf("failed to create HTTP request: %w", err) } @@ -247,7 +267,7 @@ type ImportForm map[string]string func (c *Client) ImportScanResult(file string, form ImportForm) (string, error) { klog.Debugf("importing scan results using the file:%s", file) - path := "/api/v1/scans/import" + path := "/api/v2/scans/import" rel := &url.URL{Path: path} u := c.BaseURL.ResolveReference(rel) @@ -312,7 +332,7 @@ func (c *Client) ListScans(project string, params *ScanSearchParams) ([]ScanDeta klog.Debugf("retrieving scans of the project: %s", project) scans := make([]ScanDetail, 0) - path := fmt.Sprintf("/api/v1/projects/%s/scans", project) + path := fmt.Sprintf("/api/v2/projects/%s/scans", project) req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { return scans, err @@ -325,7 +345,7 @@ func (c *Client) ListScans(project string, params *ScanSearchParams) ([]ScanDeta req.URL.RawQuery = v.Encode() type getProjectScansResponse struct { - Scans []ScanDetail `json:"data"` + Scans []ScanDetail `json:"scans"` Total int `json:"total"` } var ps getProjectScansResponse @@ -360,7 +380,7 @@ func (c *Client) FindScan(project string, params *ScanSearchParams) (*ScanDetail } func (c *Client) FindScanByID(id string) (*ScanDetail, error) { - path := fmt.Sprintf("/api/v1/scans/%s", id) + path := fmt.Sprintf("/api/v2/scans/%s", id) req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { return nil, err @@ -400,7 +420,7 @@ func (c *Client) GetScanStatus(eventId string) (*Event, error) { } func (c *Client) GetLastResults(id string) (map[string]*ResultSet, error) { - path := fmt.Sprintf("/api/v1/scans/%s/last_results", id) + path := fmt.Sprintf("/api/v2/scans/%s/last_results", id) req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { return nil, err diff --git a/cmd/listScanners.go b/cmd/listScanners.go index 0b26413..f1d7014 100644 --- a/cmd/listScanners.go +++ b/cmd/listScanners.go @@ -18,10 +18,15 @@ var listScannersCmd = &cobra.Command{ qwe(ExitCodeError, err, "could not initialize Kondukto client") } - scannerType := cmd.Flag("type").Value.String() + var scannerTypes []client.ScannerType + scannerTypeFlag := cmd.Flag("type").Value.String() + if scannerTypeFlag != "" { + scannerTypes = []client.ScannerType{client.ScannerType(scannerTypeFlag)} + } + scannerLabels := cmd.Flag("labels").Value.String() - activeScanners, err := c.ListActiveScanners(&client.ScannersSearchParams{ - Types: scannerType, + activeScanners, err := c.ListActiveScanners(&client.ListActiveScannersInput{ + Types: scannerTypes, Labels: scannerLabels, }) if err != nil { diff --git a/cmd/project.go b/cmd/project.go index 4c7b3ba..21df277 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -29,11 +29,11 @@ const ( VCSToolBitbucket = "bitbucket" // VCSToolBitbucketServer represents the Bitbucket server VCS tool name VCSToolBitbucketServer = "bitbucketserver" - // VCSToolGitHub represents the Github VCS tool name + // VCSToolGitHub represents the GitHub VCS tool name VCSToolGitHub = "github" - // VCSToolGitLab represents the Gitlab Cloud VCS tool name + // VCSToolGitLabCloud represents the Gitlab Cloud VCS tool name VCSToolGitLabCloud = "gitlabcloud" - // VCSToolGitLab represents the Gitlab On-Prem VCS tool name + // VCSToolGitLabOnPrem represents the Gitlab On-Prem VCS tool name VCSToolGitLabOnPrem = "gitlabonprem" // VCSToolGit represents the Git VCS tool name VCSToolGit = "git" diff --git a/cmd/scan.go b/cmd/scan.go index 5266394..5e948ef 100755 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -236,7 +236,7 @@ func (s *Scan) scanByImage() (string, error) { if image == "" { return "", errors.New("image name is required") } - var pr = &client.ImageScanParams{ + var pr = &client.ScanByImageInput{ Project: project.ID, Tool: tool, Branch: branch, @@ -1008,7 +1008,7 @@ func (s *Scan) checkForRescanOnlyTool() (bool, *client.ScannerInfo, error) { if err != nil || name == "" { return false, nil, errors.New("missing require tool flag") } - scanners, err := s.client.ListActiveScanners(&client.ScannersSearchParams{Name: name, Limit: 1}) + scanners, err := s.client.ListActiveScanners(&client.ListActiveScannersInput{Name: name, Limit: 1}) if err != nil { return false, nil, fmt.Errorf("failed to get active scanners: %w", err) } From 92aad475dacd266d4e57c5d2f44821007c3735bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Engin=20A=C3=A7=C4=B1kg=C3=B6z?= Date: Tue, 4 Jun 2024 14:09:36 +0300 Subject: [PATCH 2/4] fix typo --- cmd/scan.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/scan.go b/cmd/scan.go index 5e948ef..ad24238 100755 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -1432,8 +1432,8 @@ func appendKeyToParamsMap(key string, custom client.Custom, parsedValue interfac custom.Params[key0] = key0map default: - klog.Debugf("unsupportted key: [%s]", key) - qwm(ExitCodeError, "unsupportted key, key can only contain one or two dots") + klog.Debugf("unsupported key: [%s]", key) + qwm(ExitCodeError, "unsupported key, key can only contain one or two dots") } return custom } From efd4fc83b1f73819a31daf38b109053cec80c2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Engin=20A=C3=A7=C4=B1kg=C3=B6z?= Date: Tue, 4 Jun 2024 14:09:50 +0300 Subject: [PATCH 3/4] Add MAST type handling --- client/projects.go | 1 + client/scanners.go | 2 +- cmd/listScanners.go | 2 +- cmd/release.go | 17 +++++++++++++---- cmd/scan.go | 3 +++ 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/client/projects.go b/client/projects.go index 0e4888b..67d6892 100755 --- a/client/projects.go +++ b/client/projects.go @@ -149,6 +149,7 @@ type ReleaseStatus struct { SCA PlaybookTypeDetail `json:"sca"` CS PlaybookTypeDetail `json:"cs"` IAC PlaybookTypeDetail `json:"iac"` + MAST PlaybookTypeDetail `json:"mast"` } type PlaybookTypeDetail struct { diff --git a/client/scanners.go b/client/scanners.go index 71dd446..781e996 100644 --- a/client/scanners.go +++ b/client/scanners.go @@ -151,7 +151,7 @@ type ListActiveScannersInput struct { func (i *ListActiveScannersInput) prepareRequestQueryParameters() ScannersSearchParams { var scannerTypes = make([]string, 0) - if i.Types == nil || len(i.Types) == 0 { + if len(i.Types) == 0 { for _, t := range ScannerTypes() { scannerTypes = append(scannerTypes, t.String()) } diff --git a/cmd/listScanners.go b/cmd/listScanners.go index f1d7014..75c37fd 100644 --- a/cmd/listScanners.go +++ b/cmd/listScanners.go @@ -19,7 +19,7 @@ var listScannersCmd = &cobra.Command{ } var scannerTypes []client.ScannerType - scannerTypeFlag := cmd.Flag("type").Value.String() + var scannerTypeFlag = cmd.Flag("type").Value.String() if scannerTypeFlag != "" { scannerTypes = []client.ScannerType{client.ScannerType(scannerTypeFlag)} } diff --git a/cmd/release.go b/cmd/release.go index 8b327a4..dd70851 100755 --- a/cmd/release.go +++ b/cmd/release.go @@ -65,9 +65,9 @@ func releaseRootCommand(cmd *cobra.Command, _ []string) { } releaseCriteriaRows := []Row{ - {Columns: []string{"STATUS", "SAST", "DAST", "PENTEST", "IAST", "SCA", "CS", "IAC"}}, - {Columns: []string{"------", "----", "----", "-------", "----", "---", "--", "---"}}, - {Columns: []string{rs.Status, rs.SAST.Status, rs.DAST.Status, rs.PENTEST.Status, rs.IAST.Status, rs.SCA.Status, rs.CS.Status, rs.IAC.Status}}, + {Columns: []string{"STATUS", "SAST", "DAST", "PENTEST", "IAST", "SCA", "CS", "IAC", "MAST"}}, + {Columns: []string{"------", "----", "----", "-------", "----", "---", "--", "---", "----"}}, + {Columns: []string{rs.Status, rs.SAST.Status, rs.DAST.Status, rs.PENTEST.Status, rs.IAST.Status, rs.SCA.Status, rs.CS.Status, rs.IAC.Status, rs.MAST.Status}}, } TableWriter(releaseCriteriaRows...) @@ -106,7 +106,12 @@ func releaseRootCommand(cmd *cobra.Command, _ []string) { qwm(ExitCodeError, "failed to parse iac flag") } - isSpecific := sast || dast || pentest || iast || sca || cs || iac + mast, err := cmd.Flags().GetBool("mast") + if err != nil { + qwm(ExitCodeError, "failed to parse mast flag") + } + + isSpecific := sast || dast || pentest || iast || sca || cs || iac || mast var spesificMap = make(map[string]bool, 0) spesificMap["SAST"] = sast @@ -116,6 +121,7 @@ func releaseRootCommand(cmd *cobra.Command, _ []string) { spesificMap["SCA"] = sca spesificMap["CS"] = cs spesificMap["IAC"] = iac + spesificMap["MAST"] = mast isReleaseFailed(rs, isSpecific, spesificMap) } @@ -150,6 +156,9 @@ func isReleaseFailed(release *client.ReleaseStatus, isSpecific bool, specificMap if release.IAC.Status == statusFail { failedScans["IAC"] = release.IAC.ScanID } + if release.MAST.Status == statusFail { + failedScans["MAST"] = release.MAST.ScanID + } if verbose { c, err := client.New() diff --git a/cmd/scan.go b/cmd/scan.go index ad24238..11a8ac6 100755 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -1220,6 +1220,9 @@ func isScanReleaseFailed(scan *client.ScanDetail, release *client.ReleaseStatus, if release.IAC.Status == statusFail { failedScans["IAC"] = scan.ID } + if release.MAST.Status == statusFail { + failedScans["MAST"] = scan.ID + } if breakByScannerType { scannerType := strings.ToUpper(scan.ScannerType) From befa90957f28561cb623ad0a5da8c357a4c59832 Mon Sep 17 00:00:00 2001 From: yusuf Date: Tue, 4 Jun 2024 17:05:29 +0300 Subject: [PATCH 4/4] Move the teams endpoint from v3 to v2 --- client/team.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/team.go b/client/team.go index 3800308..f2b7596 100644 --- a/client/team.go +++ b/client/team.go @@ -24,7 +24,7 @@ func (c *Client) CreateTeam(teamName, responsible string) error { }, } - req, err := c.newRequest(http.MethodPost, "/api/v3/teams", team) + req, err := c.newRequest(http.MethodPost, "/api/v2/teams", team) if err != nil { return err }