Skip to content
Open
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
70 changes: 69 additions & 1 deletion api/types/discoveryconfig/discoveryconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,12 +253,80 @@ func (a *DiscoveryConfig) MatchSearch(values []string) bool {
}

// IsMatchersEmpty returns true if all matchers are empty.
//
// Deprecated: check the Spec matcher fields directly, or use
// ReferencesOnlyIntegration to check if the config belongs to one integration.
func (a *DiscoveryConfig) IsMatchersEmpty() bool {
return len(a.Spec.AWS) == 0 &&
len(a.Spec.Azure) == 0 &&
len(a.Spec.GCP) == 0 &&
len(a.Spec.Kube) == 0 &&
(a.Spec.AccessGraph == nil || len(a.Spec.AccessGraph.AWS) == 0)
(a.Spec.AccessGraph == nil ||
(len(a.Spec.AccessGraph.AWS) == 0 && len(a.Spec.AccessGraph.Azure) == 0))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it's only caller is removed should we deprecate IsMatchersEmpty ?

}

// ReferencesIntegration returns true if any matcher or Access Graph sync uses
// the named integration.
func (a *DiscoveryConfig) ReferencesIntegration(integration string) bool {
if integration == "" {
return false
}

for _, matcher := range a.Spec.AWS {
if matcher.Integration == integration {
return true
}
}
for _, matcher := range a.Spec.Azure {
if matcher.Integration == integration {
return true
}
}

if a.Spec.AccessGraph != nil {
for _, sync := range a.Spec.AccessGraph.AWS {
if sync != nil && sync.Integration == integration {
return true
}
}
for _, sync := range a.Spec.AccessGraph.Azure {
if sync != nil && sync.Integration == integration {
return true
}
}
}

return false
}

// ReferencesOnlyIntegration returns true if every matcher and Access Graph sync
// uses the named integration. GCP and Kubernetes matchers never do.
func (a *DiscoveryConfig) ReferencesOnlyIntegration(integration string) bool {
for _, matcher := range a.Spec.AWS {
if matcher.Integration != integration {
return false
}
}
for _, matcher := range a.Spec.Azure {
if matcher.Integration != integration {
return false
}
}

if a.Spec.AccessGraph != nil {
for _, sync := range a.Spec.AccessGraph.AWS {
if sync == nil || sync.Integration != integration {
return false
}
}
for _, sync := range a.Spec.AccessGraph.Azure {
if sync == nil || sync.Integration != integration {
return false
}
}
}

return len(a.Spec.GCP) == 0 && len(a.Spec.Kube) == 0
}

// CloneResource returns a copy of the resource as types.ResourceWithLabels.
Expand Down
270 changes: 268 additions & 2 deletions api/types/discoveryconfig/discoveryconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func TestNewDiscoveryConfig(t *testing.T) {
}
}

func TestDiscoveryConfig_IsMatchersEmpty(t *testing.T) {
func TestIsMatchersEmpty(t *testing.T) {
for _, tt := range []struct {
name string
config *DiscoveryConfig
Expand Down Expand Up @@ -527,14 +527,28 @@ func TestDiscoveryConfig_IsMatchersEmpty(t *testing.T) {
expected: false,
},
{
name: "has AccessGraph but no AWS",
name: "has AccessGraph but no syncs",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{},
},
},
expected: true,
},
{
name: "has AccessGraph Azure sync",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
Azure: []*types.AccessGraphAzureSync{{
Integration: "integration1",
SubscriptionID: "sub-id",
}},
},
},
},
expected: false,
},
{
name: "has multiple matcher types",
config: &DiscoveryConfig{
Expand All @@ -558,3 +572,255 @@ func TestDiscoveryConfig_IsMatchersEmpty(t *testing.T) {
})
}
}

func TestReferencesIntegration(t *testing.T) {
for _, tt := range []struct {
name string
config *DiscoveryConfig
expected bool
}{
{
name: "empty config",
config: &DiscoveryConfig{Spec: Spec{}},
expected: false,
},
{
name: "AWS matcher on the integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{
{Integration: "integration2"},
{Integration: "integration1"},
},
},
},
expected: true,
},
{
name: "Azure matcher on the integration",
config: &DiscoveryConfig{
Spec: Spec{
Azure: []types.AzureMatcher{{Integration: "integration1"}},
},
},
expected: true,
},
{
name: "AccessGraph AWS sync on the integration",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{{Integration: "integration1"}},
},
},
},
expected: true,
},
{
name: "AccessGraph Azure sync on the integration",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
Azure: []*types.AccessGraphAzureSync{{Integration: "integration1"}},
},
},
},
expected: true,
},
{
name: "only another integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration2"}},
Azure: []types.AzureMatcher{{Integration: "integration2"}},
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{{Integration: "integration2"}},
Azure: []*types.AccessGraphAzureSync{{Integration: "integration2"}},
},
},
},
expected: false,
},
{
name: "nil AccessGraph sync entries",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{nil},
Azure: []*types.AccessGraphAzureSync{nil},
},
},
},
expected: false,
},
{
name: "GCP and Kube matchers cannot reference an integration",
config: &DiscoveryConfig{
Spec: Spec{
GCP: []types.GCPMatcher{{Types: []string{"gce"}}},
Kube: []types.KubernetesMatcher{{Types: []string{"app"}}},
},
},
expected: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.expected, tt.config.ReferencesIntegration("integration1"))
})
}

t.Run("matchers using ambient credentials reference no integration", func(t *testing.T) {
config := &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Types: []string{"ec2"}}},
Azure: []types.AzureMatcher{{Types: []string{"vm"}}},
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{{Regions: []string{"us-east-1"}}},
Azure: []*types.AccessGraphAzureSync{{SubscriptionID: "sub-id"}},
},
},
}

require.False(t, config.ReferencesIntegration(""))
})
}

func TestReferencesOnlyIntegration(t *testing.T) {
for _, tt := range []struct {
name string
config *DiscoveryConfig
expected bool
}{
{
name: "empty config",
config: &DiscoveryConfig{Spec: Spec{}},
expected: true,
},
{
name: "AWS matchers on the integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{
{Integration: "integration1"},
{Integration: "integration1"},
},
},
},
expected: true,
},
{
name: "one AWS matcher on another integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{
{Integration: "integration1"},
{Integration: "integration2"},
},
},
},
expected: false,
},
{
name: "AWS matcher with no integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Types: []string{"ec2"}}},
},
},
expected: false,
},
{
name: "Azure matcher on another integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
Azure: []types.AzureMatcher{{Integration: "integration2"}},
},
},
expected: false,
},
{
name: "AccessGraph syncs on the integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{{Integration: "integration1"}},
Azure: []*types.AccessGraphAzureSync{{Integration: "integration1"}},
},
},
},
expected: true,
},
{
name: "AccessGraph AWS sync on another integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{{Integration: "integration2"}},
},
},
},
expected: false,
},
{
name: "AccessGraph Azure sync on another integration",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
AccessGraph: &types.AccessGraphSync{
Azure: []*types.AccessGraphAzureSync{{Integration: "integration2"}},
},
},
},
expected: false,
},
{
name: "nil AccessGraph AWS sync entry",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
AWS: []*types.AccessGraphAWSSync{nil},
},
},
},
expected: false,
},
{
name: "nil AccessGraph Azure sync entry",
config: &DiscoveryConfig{
Spec: Spec{
AccessGraph: &types.AccessGraphSync{
Azure: []*types.AccessGraphAzureSync{nil},
},
},
},
expected: false,
},
{
name: "GCP matcher",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
GCP: []types.GCPMatcher{{Types: []string{"gce"}}},
},
},
expected: false,
},
{
name: "Kube matcher",
config: &DiscoveryConfig{
Spec: Spec{
AWS: []types.AWSMatcher{{Integration: "integration1"}},
Kube: []types.KubernetesMatcher{{Types: []string{"app"}}},
},
},
expected: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.expected, tt.config.ReferencesOnlyIntegration("integration1"))
})
}
}
Loading
Loading