diff --git a/api/integrations_ctr_reg.go b/api/integrations_ctr_reg.go index a31e4f323..51f1e5ede 100644 --- a/api/integrations_ctr_reg.go +++ b/api/integrations_ctr_reg.go @@ -124,8 +124,8 @@ func (svc *IntegrationsService) UpdateContainerRegistry(integration ContainerReg return } -// ListContainerRegistries lists the CONT_VULN_CFG external integrations available on the Lacework Server -func (svc *IntegrationsService) ListContainerRegistries() (response ContainerRegIntResponse, err error) { +// ListContainerRegistryIntegrations lists the CONT_VULN_CFG external integrations available on the Lacework Server +func (svc *IntegrationsService) ListContainerRegistryIntegrations() (response ContainerRegIntResponse, err error) { err = svc.listByType(ContainerRegistryIntegration, &response) return } diff --git a/cli/cmd/compliance.go b/cli/cmd/compliance.go index 37ee90266..7a84041c6 100644 --- a/cli/cmd/compliance.go +++ b/cli/cmd/compliance.go @@ -74,7 +74,7 @@ Get started by integrating one or more cloud accounts using the command: $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://.lacework.net diff --git a/cli/cmd/compliance_aws.go b/cli/cmd/compliance_aws.go index f1ee415b1..53e87db5e 100644 --- a/cli/cmd/compliance_aws.go +++ b/cli/cmd/compliance_aws.go @@ -50,7 +50,7 @@ Get started by integrating your AWS accounts to analyze configuration compliance $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://%s.lacework.net diff --git a/cli/cmd/compliance_azure.go b/cli/cmd/compliance_azure.go index 8844abc73..0a033fdd0 100644 --- a/cli/cmd/compliance_azure.go +++ b/cli/cmd/compliance_azure.go @@ -82,7 +82,7 @@ Get started by integrating your Azure Tenants to analyze configuration complianc $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://%s.lacework.net diff --git a/cli/cmd/vuln_container.go b/cli/cmd/vuln_container.go index d2b460066..588a2295a 100644 --- a/cli/cmd/vuln_container.go +++ b/cli/cmd/vuln_container.go @@ -48,9 +48,9 @@ Arguments: repository name that contains the container image either a tag or an image digest to scan (digest format: sha256:1ee...1d3b) -To list all Container Registries configured in your account: +To list all container registries configured in your account: - $ lacework vuln container list-registries`, + $ lacework vulnerability container list-registries`, Args: cobra.ExactArgs(3), RunE: func(_ *cobra.Command, args []string) error { return requestOnDemandContainerVulnerabilityScan(args) @@ -75,22 +75,22 @@ To list all Container Registries configured in your account: vulContainerListRegistriesCmd = &cobra.Command{ Use: "list-registries", Aliases: []string{"list-reg", "registries"}, - Short: "list all Container Registries configured", - Long: `List all Container Registries configured in your account.`, + Short: "list all container registries configured", + Long: `List all container registries configured in your account.`, Args: cobra.NoArgs, RunE: func(_ *cobra.Command, args []string) error { - regsIntegrations, err := cli.LwApi.Integrations.ListContainerRegistries() + registries, err := getContainerRegistries() if err != nil { - return errors.Wrap(err, "unable to get container registry integrations") + return err } - if len(regsIntegrations.Data) == 0 { - msg := `There are no Container Registries configured in your account. + if len(registries) == 0 { + msg := `There are no container registries configured in your account. -Get started by integrating your Container Registry using the command: +Get started by integrating your container registry using the command: $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://%s.lacework.net @@ -100,21 +100,6 @@ Then navigate to Settings > Integrations > Container Registry. return nil } - registries := make([]string, 0) - for _, i := range regsIntegrations.Data { - // avoid adding empty registries coming from the new local_scanner - if i.Data.RegistryDomain == "" { - continue - } - - // avoid adding duplicate registries - if array.ContainsStr(registries, i.Data.RegistryDomain) { - continue - } - - registries = append(registries, i.Data.RegistryDomain) - } - if cli.JSONOutput() { return cli.OutputJSON(registries) } @@ -340,7 +325,7 @@ func requestOnDemandContainerVulnerabilityScan(args []string) error { ) scan, err := cli.LwApi.Vulnerabilities.Container.Scan(args[0], args[1], args[2]) if err != nil { - return errors.Wrap(err, "unable to request on-demand vulnerability scan") + return userFriendlyErrorForOnDemandCtrVulnScan(err, args[0], args[1], args[2]) } cli.Log.Debugw("vulnerability scan", "details", scan) @@ -819,3 +804,89 @@ func filterSeverity(severity string, threshold string) bool { func vulFiltersEnabled() bool { return vulCmdState.Severity != "" || vulCmdState.Fixable } + +func getContainerRegistries() ([]string, error) { + var ( + registries = make([]string, 0) + regsIntegrations, err = cli.LwApi.Integrations.ListContainerRegistryIntegrations() + ) + if err != nil { + return registries, errors.Wrap(err, "unable to get container registry integrations") + } + + for _, i := range regsIntegrations.Data { + // avoid adding empty registries coming from the new local_scanner and avoid adding duplicate registries + if i.Data.RegistryDomain == "" || array.ContainsStr(registries, i.Data.RegistryDomain) { + continue + } + + registries = append(registries, i.Data.RegistryDomain) + } + + return registries, nil +} + +// Creates a user-friendly error message +func userFriendlyErrorForOnDemandCtrVulnScan(err error, registry, repo, tag string) error { + if strings.Contains(err.Error(), + "Could not find integraion matching the registry provided", + ) || strings.Contains(err.Error(), + "Could not find vulnerability integrations", + ) { + + registries, errReg := getContainerRegistries() + if errReg != nil { + cli.Log.Debugw("error trying to retrieve configured registries", "error", errReg) + return errors.Errorf("container registry '%s' not found", registry) + } + + if len(registries) == 0 { + msg := `there are no container registries configured in your account. + +Get started by integrating your container registry using the command: + + $ lacework integration create + +If you prefer to configure the integration via the WebUI, log in to your account at: + + https://%s.lacework.net + +Then navigate to Settings > Integrations > Container Registry. +` + return errors.New(fmt.Sprintf(msg, cli.Account)) + } + + msg := `container registry '%s' not found + +Your account has the following container registries configured: + + > %s + +To integrate a new container registry use the command: + + $ lacework integration create +` + return errors.New(fmt.Sprintf(msg, registry, strings.Join(registries, "\n > "))) + } + + if strings.Contains( + err.Error(), + "Could not successfully send scan request to available integrations for given repo and label", + ) { + + msg := `container image '%s:%s' not found in registry '%s'. + +This error is likely due to a problem with the container registry integration +configured in your account. Verify that the integration was configured with +Lacework using the correct permissions, and that the repository belongs +to the provided registry. + +To view all container registries configured in your account use the command: + + $ lacework vulnerability container list-registries +` + return errors.Errorf(msg, repo, tag, registry) + } + + return errors.Wrap(err, "unable to request on-demand vulnerability scan") +} diff --git a/cli/cmd/vuln_container_test.go b/cli/cmd/vuln_container_test.go new file mode 100644 index 000000000..987948fea --- /dev/null +++ b/cli/cmd/vuln_container_test.go @@ -0,0 +1,44 @@ +// +// Author:: Salim Afiune Maya () +// Copyright:: Copyright 2021, Lacework Inc. +// License:: Apache License, Version 2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cmd + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestUserFriendlyErrorFromOnDemandCtrVulnScanRepositoryNotFound(t *testing.T) { + err := userFriendlyErrorForOnDemandCtrVulnScan( + errors.New("Could not successfully send scan request to available integrations for given repo and label"), + "my-registry.example.com", "image", "tag", + ) + if assert.NotNil(t, err) { + assert.Contains(t, + err.Error(), + "container image 'image:tag' not found in registry 'my-registry.example.com'") + assert.Contains(t, + err.Error(), + "To view all container registries configured in your account use the command:") + assert.Contains(t, + err.Error(), + "$ lacework vulnerability container list-registries") + } +} diff --git a/cli/cmd/vulnerability.go b/cli/cmd/vulnerability.go index 69a79d744..7e6bc7305 100644 --- a/cli/cmd/vulnerability.go +++ b/cli/cmd/vulnerability.go @@ -99,7 +99,7 @@ To create a new integration use the following command: $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://.lacework.net diff --git a/integration/compliance_test.go b/integration/compliance_test.go index 3a4199895..0baa641b3 100644 --- a/integration/compliance_test.go +++ b/integration/compliance_test.go @@ -37,7 +37,7 @@ Get started by integrating one or more cloud accounts using the command: $ lacework integration create -Or, if you prefer to do it via the WebUI, log in to your account at: +If you prefer to configure the integration via the WebUI, log in to your account at: https://.lacework.net diff --git a/integration/container_vulnerability_test.go b/integration/container_vulnerability_test.go index aea8d97a2..da46662ef 100644 --- a/integration/container_vulnerability_test.go +++ b/integration/container_vulnerability_test.go @@ -101,6 +101,41 @@ func TestContainerVulnerabilityCommandListAssessments(t *testing.T) { }) } +func TestContainerVulnerabilityCommandScanErrorRegistryNotFound(t *testing.T) { + out, err, exitcode := LaceworkCLIWithTOMLConfig( + "vulnerability", "container", "scan", "my.registry.example.com", "foo", "bar", + ) + assert.Empty(t, out.String(), + "STDOUT should be empty") + assert.Contains(t, err.String(), + "container registry 'my.registry.example.com' not found", + "STDERR mismatch, please check") + assert.Contains(t, err.String(), + "Your account has the following container registries configured", + "STDERR mismatch, please check") + assert.Contains(t, err.String(), + fmt.Sprintf("> %s", registry), + "STDERR mismatch, please check") + assert.Equal(t, 1, exitcode, + "EXITCODE is not the expected one") +} + +func TestContainerVulnerabilityCommandScanErrorContainerImageNotFound(t *testing.T) { + out, err, exitcode := LaceworkCLIWithTOMLConfig( + "vulnerability", "container", "scan", registry, "foo", "bar", + ) + assert.Empty(t, out.String(), + "STDOUT should be empty") + assert.Contains(t, err.String(), + fmt.Sprintf("container image 'foo:bar' not found in registry '%s'.", registry), + "STDERR mismatch, please check") + assert.Contains(t, err.String(), + "To view all container registries configured in your account use the command", + "STDERR mismatch, please check") + assert.Equal(t, 1, exitcode, + "EXITCODE is not the expected one") +} + func TestContainerVulnerabilityCommandScanHumanReadablePollGenerateHtml(t *testing.T) { // create a temporal directory to check that the HTML file is deployed home := createTOMLConfigFromCIvars()