Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions pkg/providers/gcp/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -761,11 +761,11 @@ func newOrganizationProvider(options schema.OptionBlock, id, JSONData, organizat

// Get projects under the organization
projects := []string{}
manager, err := cloudresourcemanager.NewService(context.Background(), creds)
if err != nil {
return nil, errkit.Wrap(err, "could not create resource manager")
}
if len(configuredProjects) > 0 {
manager, err := cloudresourcemanager.NewService(context.Background(), creds)
if err != nil {
return nil, errkit.Wrap(err, "could not create resource manager")
}
scope := newProjectScope(configuredProjects)
if scope == nil {
return nil, errkit.New("no valid project ids provided in configuration")
Expand All @@ -775,23 +775,29 @@ func newOrganizationProvider(options schema.OptionBlock, id, JSONData, organizat
}
projects = scope.listIDs()
provider.projectScope = scope
if len(projects) == 0 {
return nil, errkit.New("no valid project ids available after resolution")
}
gologger.Info().Msgf("Restricting organization discovery to %d configured project(s)", len(projects))
} else {
list := manager.Projects.List()
err = list.Pages(context.Background(), func(resp *cloudresourcemanager.ListProjectsResponse) error {
for _, project := range resp.Projects {
projects = append(projects, project.ProjectId)
}
return nil
})
manager, err := cloudresourcemanager.NewService(context.Background(), creds)
if err != nil {
return nil, errkit.Wrap(err, "could not list projects")
gologger.Warning().Msgf("Could not create resource manager to list projects: %s", err)
} else {
list := manager.Projects.List()
err = list.Pages(context.Background(), func(resp *cloudresourcemanager.ListProjectsResponse) error {
for _, project := range resp.Projects {
projects = append(projects, project.ProjectId)
}
return nil
})
if err != nil {
gologger.Warning().Msgf("Could not list projects under organization: %s", err)
}
}
if len(projects) == 0 {
gologger.Info().Msgf("No projects listed, will use organization-level Asset API discovery for org %s", organizationID)
}
}
if len(projects) == 0 {
return nil, errkit.New("no projects available for organization discovery")
}
if len(configuredProjects) > 0 {
gologger.Info().Msgf("Restricting organization discovery to %d configured project(s)", len(projects))
}
provider.projects = projects

Expand Down
57 changes: 57 additions & 0 deletions pkg/providers/gcp/gcp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package gcp

import (
"testing"

"github.com/projectdiscovery/cloudlist/pkg/schema"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewOrganizationProvider_NoProjectsListedFallsBackToOrgLevel(t *testing.T) {
// When organization_id is set without project_ids, the provider should be
// created successfully regardless of whether Projects.List returns results.
// Previously, the code returned "no projects available for organization discovery"
// which blocked org-level Asset API discovery for SAs without project-list permission.

options := schema.OptionBlock{
"provider": "gcp",
"organization_id": "123456789",
"extended_metadata": "false",
}

provider, err := newOrganizationProvider(options, "test-id", "", "123456789")

if err != nil {
assert.NotContains(t, err.Error(), "no projects available for organization discovery",
"org-level provider should not fail just because Projects.List returns 0 projects")
t.Skipf("skipping (no GCP creds): %v", err)
}

require.NotNil(t, provider)
assert.Equal(t, "123456789", provider.organizationID)
assert.Nil(t, provider.projectScope, "projectScope should be nil for org-level discovery")
}

func TestNewOrganizationProvider_ConfiguredProjectsStillValidated(t *testing.T) {
// When project_ids are explicitly configured, we should still fail if they
// resolve to an empty list — this is a real config error.
options := schema.OptionBlock{
"provider": "gcp",
"organization_id": "123456789",
"project_ids": "",
}

provider, err := newOrganizationProvider(options, "test-id", "", "123456789")

// With empty project_ids, getProjectIDsFromOptions returns nil, so it
// takes the org-level path (no project scope). Should not fail.
if err != nil {
assert.NotContains(t, err.Error(), "no projects available",
"empty project_ids should fall through to org-level discovery")
t.Skipf("skipping in CI (no GCP creds): %v", err)
}

require.NotNil(t, provider)
assert.Nil(t, provider.projectScope)
}
Comment thread
knakul853 marked this conversation as resolved.
Loading