From a8c6a243e39bc4ee94c6229d1f57470ac223d2b6 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Thu, 7 May 2026 18:36:36 +0200 Subject: [PATCH] fix(gitlab): populate repositories for scan-all Populate GitLab repositories before scanning when the registry is configured to scan all repos, so registryx host discovery can resolve the actual registry host. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Matthias Bertschy --- mainhandler/vulnscan.go | 17 +++++ mainhandler/vulnscan_gitlab_test.go | 101 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 mainhandler/vulnscan_gitlab_test.go diff --git a/mainhandler/vulnscan.go b/mainhandler/vulnscan.go index 6f430a1..b0c1770 100644 --- a/mainhandler/vulnscan.go +++ b/mainhandler/vulnscan.go @@ -127,6 +127,9 @@ func (actionHandler *ActionHandler) scanRegistriesV2(ctx context.Context, imageR if err != nil { return fmt.Errorf("failed to get registry client: %w", err) } + if err := populateGitLabRepositoriesForScan(ctx, client, imageRegistry); err != nil { + return fmt.Errorf("failed to prepare registry scan: %w", err) + } images, err := client.GetImagesToScan(ctx) if err != nil { @@ -146,6 +149,20 @@ func (actionHandler *ActionHandler) scanRegistriesV2(ctx context.Context, imageR return nil } +func populateGitLabRepositoriesForScan(ctx context.Context, client interfaces.RegistryClient, imageRegistry apitypes.ContainerImageRegistry) error { + base := imageRegistry.GetBase() + if base.Provider != apitypes.Gitlab || len(base.Repositories) > 0 { + return nil + } + + repositories, err := client.GetAllRepositories(ctx) + if err != nil { + return fmt.Errorf("failed to get GitLab repositories: %w", err) + } + base.Repositories = repositories + return nil +} + func (actionHandler *ActionHandler) loadRegistrySecret(ctx context.Context, imageRegistry apitypes.ContainerImageRegistry) error { secretName := actionHandler.sessionObj.Command.Args[apitypes.RegistrySecretNameArgKey].(string) secret, err := actionHandler.k8sAPI.KubernetesClient.CoreV1().Secrets(actionHandler.config.Namespace()).Get(ctx, secretName, metav1.GetOptions{}) diff --git a/mainhandler/vulnscan_gitlab_test.go b/mainhandler/vulnscan_gitlab_test.go new file mode 100644 index 0000000..ab4fc0b --- /dev/null +++ b/mainhandler/vulnscan_gitlab_test.go @@ -0,0 +1,101 @@ +package mainhandler + +import ( + "context" + "errors" + "testing" + + apitypes "github.com/armosec/armoapi-go/armotypes" + "github.com/armosec/registryx/interfaces" + dockerregistry "github.com/docker/docker/api/types/registry" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var _ interfaces.RegistryClient = (*fakeRegistryClient)(nil) + +type fakeRegistryClient struct { + repositories []string + getAllErr error + getAllCalls int +} + +func (f *fakeRegistryClient) GetAllRepositories(_ context.Context) ([]string, error) { + f.getAllCalls++ + if f.getAllErr != nil { + return nil, f.getAllErr + } + return append([]string(nil), f.repositories...), nil +} + +func (f *fakeRegistryClient) GetImagesToScan(context.Context) (map[string]string, error) { + return nil, nil +} + +func (f *fakeRegistryClient) GetDockerAuth() (*dockerregistry.AuthConfig, error) { + return &dockerregistry.AuthConfig{}, nil +} + +func TestPopulateGitLabRepositoriesForScan(t *testing.T) { + t.Run("gitlab scan-all populates repositories", func(t *testing.T) { + registry := &apitypes.GitlabImageRegistry{ + BaseContainerImageRegistry: apitypes.BaseContainerImageRegistry{ + Provider: apitypes.Gitlab, + }, + } + client := &fakeRegistryClient{repositories: []string{"group/service", "group/worker"}} + + err := populateGitLabRepositoriesForScan(context.Background(), client, registry) + + require.NoError(t, err) + assert.Equal(t, 1, client.getAllCalls) + assert.Equal(t, []string{"group/service", "group/worker"}, registry.Repositories) + }) + + t.Run("gitlab with selected repositories skips lookup", func(t *testing.T) { + registry := &apitypes.GitlabImageRegistry{ + BaseContainerImageRegistry: apitypes.BaseContainerImageRegistry{ + Provider: apitypes.Gitlab, + Repositories: []string{"group/service"}, + }, + } + client := &fakeRegistryClient{repositories: []string{"group/worker"}} + + err := populateGitLabRepositoriesForScan(context.Background(), client, registry) + + require.NoError(t, err) + assert.Equal(t, 0, client.getAllCalls) + assert.Equal(t, []string{"group/service"}, registry.Repositories) + }) + + t.Run("non-gitlab scan-all skips lookup", func(t *testing.T) { + registry := &apitypes.HarborImageRegistry{ + BaseContainerImageRegistry: apitypes.BaseContainerImageRegistry{ + Provider: apitypes.Harbor, + }, + } + client := &fakeRegistryClient{repositories: []string{"project/app"}} + + err := populateGitLabRepositoriesForScan(context.Background(), client, registry) + + require.NoError(t, err) + assert.Equal(t, 0, client.getAllCalls) + assert.Empty(t, registry.Repositories) + }) + + t.Run("gitlab scan-all surfaces lookup errors", func(t *testing.T) { + registry := &apitypes.GitlabImageRegistry{ + BaseContainerImageRegistry: apitypes.BaseContainerImageRegistry{ + Provider: apitypes.Gitlab, + }, + } + client := &fakeRegistryClient{getAllErr: errors.New("boom")} + + err := populateGitLabRepositoriesForScan(context.Background(), client, registry) + + require.Error(t, err) + assert.Equal(t, 1, client.getAllCalls) + assert.ErrorContains(t, err, "failed to get GitLab repositories") + assert.Empty(t, registry.Repositories) + }) +}