Skip to content

feat(filter): add exclude_services support across providers and CLI (#749)#754

Open
ThryLox wants to merge 3 commits into
projectdiscovery:devfrom
ThryLox:feat/exclude-services-support
Open

feat(filter): add exclude_services support across providers and CLI (#749)#754
ThryLox wants to merge 3 commits into
projectdiscovery:devfrom
ThryLox:feat/exclude-services-support

Conversation

@ThryLox

@ThryLox ThryLox commented Jun 28, 2026

Copy link
Copy Markdown

Summary

Fixes #749 by adding first-class support for exclude_services (-es, --exclude-service) across provider configuration YAML files and CLI flags.

Context & Problem

While cloudlist previously supported services: as a positive allowlist, users had no clean way to express "enumerate everything except service X". Skipping a single noisy service required manually listing every other supported service in the provider config.

Key Changes

  1. CLI Flag & Config Schema: Added -es / --exclude-service flags to internal/runner/options.go and updated OptionBlock YAML unmarshaling in pkg/schema/schema.go.
  2. Provider Service Filtering: Added ParseServices helper and updated all 19 provider implementations (AWS, GCP, Azure, DigitalOcean, Kubernetes, etc.) to subtract excluded services during enumeration.
  3. Unit Tests: Added unit test coverage in pkg/schema/schema_test.go verifying YAML parsing and service exclusion maps.

Summary by CodeRabbit

  • New Features
    • Added --exclude-service (-es) and exclude_services settings to omit specific services from provider discovery.
    • Exclusions are applied across providers, affecting which resources are discovered.
  • Behavior Changes
    • Updated service allowlisting rules: if services is explicitly provided but contains only unsupported entries, it no longer falls back to enabling all services.
  • Tests
    • Added coverage for exclude_services parsing and for the “no fallback when services are explicitly unsupported” behavior.

…rojectdiscovery#749)

Adds exclude_services (-es, --exclude-service) filtering support to cloudlist. Allows users to specify service exclusions in provider YAML configs and CLI options to filter out unwanted services across AWS, GCP, Azure, DigitalOcean, Kubernetes, and other supported cloud providers.
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6276807-ee00-4fbb-8ff2-fbee8a143510

📥 Commits

Reviewing files that changed from the base of the PR and between d73f61b and 72e648f.

📒 Files selected for processing (1)
  • internal/runner/runner.go

Walkthrough

Adds exclude_services support across schema, CLI, runner, and provider service selection. The schema parses the new option, the runner propagates it into provider config, and providers remove matching services from their discovered service maps. Kubernetes also gates its Services API call on the selected service set.

Changes

exclude_services feature

Layer / File(s) Summary
Schema helpers and parsing
pkg/schema/schema.go, pkg/schema/schema_test.go
Adds GetExcludeServiceNames(), ParseServices(), YAML support for exclude_services, and tests for exclusion and unsupported-service behavior.
CLI flag and runner wiring
internal/runner/options.go, internal/runner/runner.go
Adds ExcludeServices, wires --exclude-service (-es), and injects exclude_services into provider items in Enumerate.
Provider service filtering
pkg/providers/alibaba/alibaba.go, pkg/providers/arvancloud/arvancloud.go, pkg/providers/aws/aws.go, pkg/providers/azure/azure.go, pkg/providers/cloudflare/cloudflare.go, pkg/providers/custom/custom.go, pkg/providers/digitalocean/digitalocean.go, pkg/providers/dnssimple/dnssimple.go, pkg/providers/gcp/gcp.go, pkg/providers/heroku/heroku.go, pkg/providers/hetzner/hetzner.go, pkg/providers/linode/linode.go, pkg/providers/namecheap/namecheap.go, pkg/providers/openstack/openstack.go, pkg/providers/ovh/ovh.go, pkg/providers/scaleway/scaleway.go, pkg/providers/terraform/terraform.go, pkg/providers/vercel/vercel.go
Updates provider constructors to use presence-based services defaults and delete entries listed in exclude_services.
Kubernetes service listing
pkg/providers/k8s/kubernetes.go
Changes Kubernetes service selection and moves the Services API call inside the service check.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through services, one by one,
I kept the good ones, skipped the gone.
A comma here, a trim there too,
exclude_services prunes the view.
Cloudlist now skips what you don't choose!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding exclude_services support across providers and CLI.
Linked Issues check ✅ Passed The PR implements additive exclude_services semantics in schema, CLI, and providers, matching the issue's allowlist-then-exclude requirements.
Out of Scope Changes check ✅ Passed The changes stay focused on service filtering, CLI wiring, schema parsing, and provider updates with no clear unrelated additions.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
pkg/providers/gcp/gcp.go (1)

246-263: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The fallback here still expands an explicit empty selection into all GCP services.

If services is provided but all requested entries are unsupported, Line 254 repopulates the full Services list before exclude_services is applied. That violates the intended filter semantics and can turn services: [unknown] into full GCP enumeration.

As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/gcp/gcp.go` around lines 246 - 263, The service-selection logic
in gcp.go is expanding an explicit filtered request into all GCP services when
`services` is present but yields no supported entries. Update the `services`
handling in the GCP provider so `options.GetMetadata("services")` is honored
strictly, and only fall back to the full `Services` list when the metadata key
is absent, not when it is present but empty/unsupported; keep the
`exclude_services` filtering in `schema.ServiceMap` after that.

Source: Coding guidelines

pkg/providers/custom/custom.go (2)

91-109: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Persist the computed service map on p.

services is never assigned to p.Services, so this filtering result is discarded and the local becomes unused. This will fail compilation once the file is built.

Suggested fix
 	if es, ok := block.GetMetadata("exclude_services"); ok {
 		for _, s := range strings.Split(es, ",") {
 			delete(services, strings.TrimSpace(s))
 		}
 	}
+	p.Services = services
 
 	np, err := networkpolicy.New(networkpolicy.DefaultOptions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/custom/custom.go` around lines 91 - 109, The computed service
filtering in custom provider setup is never stored, so the result is lost and
`services` becomes effectively unused. Update the logic in `custom.go` after
building the map from `block.GetMetadata("services")`, applying the default
`Services`, and removing `exclude_services` so that the final map is assigned to
`p.Services` on the provider struct. Keep the existing filtering flow intact,
but make sure the computed map is persisted on `p` before returning.

92-109: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

This still re-enables all services when the allowlist matches nothing.

If services is explicitly set but every value is unsupported, Lines 100-103 repopulate the full default set before the new exclusion step runs. That breaks the service-filter contract; track whether services was specified, rather than keying fallback off len(services).

As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/custom/custom.go` around lines 92 - 109, The service selection
logic in the custom provider is falling back to all Services whenever the
allowlist produces an empty map, which overrides an explicitly provided but
unsupported services filter. Update the logic in the block that reads
block.GetMetadata("services") and applies exclude_services so it tracks whether
services was specified and only uses the default Services set when no allowlist
was provided at all. Keep the filtering behavior in Services()/custom provider
resource gathering consistent with the -s contract and preserve the
supportedServicesMap/strings.TrimSpace handling.

Source: Coding guidelines

pkg/providers/vercel/vercel.go (1)

28-49: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Vercel has the same allowlist-empty fallback bug.

When services is explicitly provided but none of those names are supported, Lines 40-43 restore every default service before the new exclude_services block runs. That defeats the filter and should resolve to an empty selection instead.

As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/vercel/vercel.go` around lines 28 - 49, The service selection
logic in Vercel falls back to all default services when a provided services
filter matches none, which breaks the intended allowlist behavior. Update the
service-building flow in the provider’s Services handling so that an explicit
metadata filter from options.GetMetadata("services") only includes supported
names and, when it yields no matches, stays empty instead of restoring Services;
keep exclude_services applied afterward to the selected set. Use the existing
supportedServicesMap, services map, and Services slice to locate the fix.

Source: Coding guidelines

pkg/providers/dnssimple/dnssimple.go (1)

60-77: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't treat an empty allowlist intersection as "all services".

When services is present but none of the requested names are supported, Line 68 restores the full default set and the new exclude_services block deletes from that. The effective selection should stay empty instead.

As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/dnssimple/dnssimple.go` around lines 60 - 77, The service
filtering logic in dnssimple should not fall back to all defaults when the
provided services allowlist has no supported intersection; keep the selection
empty instead. Update the services construction in the initialization path that
builds the ServiceMap from options.GetMetadata("services") and applies
exclude_services so len(services) only triggers the default Services set when
the services metadata is absent, not when it was present but matched nothing.
Ensure the final filtering behavior in dnssimple honors the requested service
names and preserves an empty result when appropriate.

Source: Coding guidelines

pkg/providers/ovh/ovh.go (1)

27-46: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

This service selection still falls back to full discovery for an explicit-but-invalid allowlist.

If the user sets services and every value is unsupported, Lines 37-40 rebuild the default set, so the new exclude_services removal operates on all services rather than none. The empty intersection needs to remain empty.

As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/ovh/ovh.go` around lines 27 - 46, The service filtering logic
in ovh.go currently falls back to the full default set when the explicit
services allowlist contains no supported entries, which causes exclude_services
to operate on all services instead of none. Update the Services() selection path
so the presence of a services metadata filter is honored even when the
intersection is empty: only populate the default Services set when no services
filter was provided, and keep the resulting service map empty for an
explicit-but-invalid allowlist before applying exclude_services.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/runner/runner.go`:
- Around line 41-43: The runner is flattening provider-specific exclude lists
into shared global state in runner.go, which causes each schema.OptionBlock to
inherit the union of all YAML exclusions. Update the logic around
GetExcludeServiceNames, options.ExcludeServices, and the later provider stamping
so per-provider exclude_services stays attached to each provider item unless the
CLI flag was explicitly provided. Keep the metadata on each schema.OptionBlock
and only merge or override it in the CLI-driven path.

In `@pkg/providers/k8s/kubernetes.go`:
- Around line 84-88: The Kubernetes provider does not fully honor the
exclude_services filter because Resources() still lists Services unconditionally
even when service has been removed from the services map. Update the
resource-gathering logic in Kubernetes.Resources() to skip calling
p.clientSet.CoreV1().Services("").List(...) when p.services.Has("service") is
false, and only process service resources when the filter allows them. Keep the
filter handling consistent with the existing exclude_services parsing in the
provider.

In `@pkg/schema/schema_test.go`:
- Around line 93-117: Extend TestOptionBlockParsesExcludeServices to cover the
explicit allowlist case in Options.ParseServices: add a scenario where the
Options entry includes services: [unknown] alongside exclude_services, and
assert that ParseServices(supported) returns no services instead of falling back
to all supported ones. Use the existing Options and ParseServices symbols in
schema_test.go so the regression is caught when the allowlist contains only
unsupported values.

In `@pkg/schema/schema.go`:
- Around line 322-337: The service filter logic in schema handling is falling
back to all supported services even when the metadata key is present but filters
down to nothing. Update the service initialization in the schema metadata
parsing path so that the “default to all services” behavior only happens when
the services metadata is absent, not when it exists but yields an empty
intersection; use the existing services parsing and supportedServicesMap logic
to distinguish those cases.

---

Outside diff comments:
In `@pkg/providers/custom/custom.go`:
- Around line 91-109: The computed service filtering in custom provider setup is
never stored, so the result is lost and `services` becomes effectively unused.
Update the logic in `custom.go` after building the map from
`block.GetMetadata("services")`, applying the default `Services`, and removing
`exclude_services` so that the final map is assigned to `p.Services` on the
provider struct. Keep the existing filtering flow intact, but make sure the
computed map is persisted on `p` before returning.
- Around line 92-109: The service selection logic in the custom provider is
falling back to all Services whenever the allowlist produces an empty map, which
overrides an explicitly provided but unsupported services filter. Update the
logic in the block that reads block.GetMetadata("services") and applies
exclude_services so it tracks whether services was specified and only uses the
default Services set when no allowlist was provided at all. Keep the filtering
behavior in Services()/custom provider resource gathering consistent with the -s
contract and preserve the supportedServicesMap/strings.TrimSpace handling.

In `@pkg/providers/dnssimple/dnssimple.go`:
- Around line 60-77: The service filtering logic in dnssimple should not fall
back to all defaults when the provided services allowlist has no supported
intersection; keep the selection empty instead. Update the services construction
in the initialization path that builds the ServiceMap from
options.GetMetadata("services") and applies exclude_services so len(services)
only triggers the default Services set when the services metadata is absent, not
when it was present but matched nothing. Ensure the final filtering behavior in
dnssimple honors the requested service names and preserves an empty result when
appropriate.

In `@pkg/providers/gcp/gcp.go`:
- Around line 246-263: The service-selection logic in gcp.go is expanding an
explicit filtered request into all GCP services when `services` is present but
yields no supported entries. Update the `services` handling in the GCP provider
so `options.GetMetadata("services")` is honored strictly, and only fall back to
the full `Services` list when the metadata key is absent, not when it is present
but empty/unsupported; keep the `exclude_services` filtering in
`schema.ServiceMap` after that.

In `@pkg/providers/ovh/ovh.go`:
- Around line 27-46: The service filtering logic in ovh.go currently falls back
to the full default set when the explicit services allowlist contains no
supported entries, which causes exclude_services to operate on all services
instead of none. Update the Services() selection path so the presence of a
services metadata filter is honored even when the intersection is empty: only
populate the default Services set when no services filter was provided, and keep
the resulting service map empty for an explicit-but-invalid allowlist before
applying exclude_services.

In `@pkg/providers/vercel/vercel.go`:
- Around line 28-49: The service selection logic in Vercel falls back to all
default services when a provided services filter matches none, which breaks the
intended allowlist behavior. Update the service-building flow in the provider’s
Services handling so that an explicit metadata filter from
options.GetMetadata("services") only includes supported names and, when it
yields no matches, stays empty instead of restoring Services; keep
exclude_services applied afterward to the selected set. Use the existing
supportedServicesMap, services map, and Services slice to locate the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20c5fcd9-0957-47ee-b3c6-e658eadface9

📥 Commits

Reviewing files that changed from the base of the PR and between 012f643 and 4dee5ca.

📒 Files selected for processing (23)
  • internal/runner/options.go
  • internal/runner/runner.go
  • pkg/providers/alibaba/alibaba.go
  • pkg/providers/arvancloud/arvancloud.go
  • pkg/providers/aws/aws.go
  • pkg/providers/azure/azure.go
  • pkg/providers/cloudflare/cloudflare.go
  • pkg/providers/custom/custom.go
  • pkg/providers/digitalocean/digitalocean.go
  • pkg/providers/dnssimple/dnssimple.go
  • pkg/providers/gcp/gcp.go
  • pkg/providers/heroku/heroku.go
  • pkg/providers/hetzner/hetzner.go
  • pkg/providers/k8s/kubernetes.go
  • pkg/providers/linode/linode.go
  • pkg/providers/namecheap/namecheap.go
  • pkg/providers/openstack/openstack.go
  • pkg/providers/ovh/ovh.go
  • pkg/providers/scaleway/scaleway.go
  • pkg/providers/terraform/terraform.go
  • pkg/providers/vercel/vercel.go
  • pkg/schema/schema.go
  • pkg/schema/schema_test.go

Comment thread internal/runner/runner.go Outdated
Comment thread pkg/providers/k8s/kubernetes.go
Comment thread pkg/schema/schema_test.go
Comment thread pkg/schema/schema.go
…calls

Addressed CodeRabbit review feedback: tracked servicesSpecified boolean in ParseServices to prevent falling back to all services when an explicit allowlist yields empty results, moved K8s Services API list call inside the service check block, and added regression unit tests.

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (11)
pkg/providers/arvancloud/arvancloud.go (1)

44-56: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use GetMetadata's bool as the services presence signal.

GetMetadata returns false for both a missing key and a present-but-empty value. Here that means an explicit empty services selection is treated as “not specified”, so the fallback branch re-enables all services. Use raw key presence (or a schema helper that preserves presence separately from the resolved value) before defaulting. As per coding guidelines, providers should honor service filtering instead of falling back to the full service set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/arvancloud/arvancloud.go` around lines 44 - 56, The
service-selection logic in arvancloud.go is using GetMetadata("services")’s
boolean as the presence check, which conflates a missing key with an explicitly
empty value. Update the services parsing in the provider initialization to
detect raw key presence separately from the resolved metadata value, and only
fall back to Services when the key is truly absent. Keep the existing
supportedServicesMap filtering and ensure an empty explicit services selection
does not re-enable all services.

Source: Coding guidelines

pkg/providers/aws/aws.go (1)

91-104: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use GetMetadata's bool as the services presence signal.

GetMetadata returns false for both a missing key and a present-but-empty value. Here that means an explicit empty services selection is treated as “not specified”, so the fallback branch re-enables all services. Use raw key presence (or a schema helper that preserves presence separately from the resolved value) before defaulting. As per coding guidelines, providers should honor service filtering instead of falling back to the full service set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/aws/aws.go` around lines 91 - 104, The service-selection logic
in aws.go is using GetMetadata("services") as the presence check, which cannot
distinguish a missing key from an explicitly empty value. Update the block that
populates services in the provider code to detect raw key presence separately
from the resolved metadata value, and only fall back to the full Services list
when the key is truly absent. Keep the filtering behavior in the services
parsing path so an empty services selection does not re-enable all services.

Source: Coding guidelines

pkg/providers/vercel/vercel.go (1)

33-45: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use GetMetadata's bool as the services presence signal.

GetMetadata returns false for both a missing key and a present-but-empty value. Here that means an explicit empty services selection is treated as “not specified”, so the fallback branch re-enables all services. Use raw key presence (or a schema helper that preserves presence separately from the resolved value) before defaulting. As per coding guidelines, providers should honor service filtering instead of falling back to the full service set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/vercel/vercel.go` around lines 33 - 45, The services selection
in the vercel provider should not rely on GetMetadata’s boolean return to detect
presence, because an explicit empty value is being treated as missing and
triggers the full Services fallback. Update the logic in the vercel provider’s
metadata parsing to check raw key presence separately from the resolved value,
then only default to Services when the key is truly absent. Keep the
supportedServicesMap filtering behavior intact so explicit service filtering is
honored.

Source: Coding guidelines

pkg/providers/alibaba/alibaba.go (1)

50-62: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use GetMetadata's bool as the services presence signal.

GetMetadata returns false for both a missing key and a present-but-empty value. Here that means an explicit empty services selection is treated as “not specified”, so the fallback branch re-enables all services. Use raw key presence (or a schema helper that preserves presence separately from the resolved value) before defaulting. As per coding guidelines, providers should honor service filtering instead of falling back to the full service set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/alibaba/alibaba.go` around lines 50 - 62, The Alibaba
provider’s service selection logic is using GetMetadata’s boolean as the
presence check, which cannot distinguish a missing services key from an
explicitly empty value. Update the logic in the alibaba provider’s metadata
parsing path to detect raw key presence separately (or use a helper that
preserves presence) before defaulting. In the code that builds the services map,
keep an explicit empty services selection empty instead of falling back to
Services, and only populate all services when the key is truly absent.

Source: Coding guidelines

pkg/providers/custom/custom.go (1)

92-105: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use GetMetadata's bool as the services presence signal.

GetMetadata returns false for both a missing key and a present-but-empty value. Here that means an explicit empty services selection is treated as “not specified”, so the fallback branch re-enables all services. Use raw key presence (or a schema helper that preserves presence separately from the resolved value) before defaulting. As per coding guidelines, providers should honor service filtering instead of falling back to the full service set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/custom/custom.go` around lines 92 - 105, The service-selection
logic in custom provider setup is using GetMetadata("services") as both value
and presence check, which makes an explicit empty services selection fall back
to all Services. Update the metadata handling in custom.go so the code first
checks raw key presence (or an equivalent helper that distinguishes missing vs
empty) before deciding whether to populate services, and keep the filtered set
empty when the key is present but empty. Use the existing services map
population around supportedServicesMap and Services as the place to apply the
fix.

Source: Coding guidelines

pkg/providers/dnssimple/dnssimple.go (1)

61-77: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim services entries before matching.

This branch still matches raw strings.Split output against supportedServicesMap, so an explicit value like services: "dns, other" only works for tokens without surrounding spaces. exclude_services is trimmed already; the allowlist should use the same normalization or call the shared parser added in this PR. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/dnssimple/dnssimple.go` around lines 61 - 77, The services
allowlist in dnssimple still matches raw strings from strings.Split, so values
with surrounding spaces are not recognized. Update the services parsing in the
servicesSpecified branch to trim each token before checking
supportedServicesMap, or reuse the shared parser used elsewhere in this PR, and
keep exclude_services trimming behavior consistent in dnssimple.Services/options
handling.

Source: Coding guidelines

pkg/providers/linode/linode.go (1)

50-65: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim allowlist entries before the supported-service lookup.

Right now only exclude_services normalizes whitespace. If services contains comma-separated values with spaces, supported entries are ignored because the map lookup uses the raw token. Using the shared schema parser here would keep Linode aligned with the intended resolution semantics. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/linode/linode.go` around lines 50 - 65, The service allowlist
parsing in the Linode provider does not trim whitespace before checking
supported entries, so comma-separated values in the services metadata can be
skipped. Update the services handling in linode.go where
options.GetMetadata("services") is processed so each token is normalized with
trimming before the supportedServicesMap lookup, matching the exclude_services
behavior and the intended Services()/filter semantics.

Source: Coding guidelines

pkg/providers/digitalocean/digitalocean.go (1)

34-50: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim services entries before matching.

The allowlist loop compares raw CSV tokens to supportedServicesMap, so services: "droplet, app" silently drops app. exclude_services is already trimmed, and the schema-layer service parser in this PR trims both lists. Please either strings.TrimSpace(s) here or delegate this whole block to the shared parser so provider filtering stays consistent. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/digitalocean/digitalocean.go` around lines 34 - 50, The
DigitalOcean service filter in digitalocean.go is matching raw CSV tokens
against supportedServicesMap, so values with spaces are skipped while
exclude_services already trims inputs. Update the Services()/metadata parsing
block to trim each token before checking the allowlist, or reuse the shared
service parser used elsewhere so the services and exclude_services handling
stays consistent and honors -s filters correctly.

Source: Coding guidelines

pkg/providers/heroku/heroku.go (1)

41-56: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Normalize allowlisted service names too.

exclude_services trims each entry, but services does not. That makes explicit filters brittle: services: "app, other" works differently depending on whitespace. Please trim s in the allowlist loop or replace this block with the shared schema parser. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/heroku/heroku.go` around lines 41 - 56, The service allowlist
handling in Heroku metadata parsing is inconsistent because the `services`
entries are not trimmed while `exclude_services` entries are; update the
`services` loop in the Heroku provider so each value is normalized with trimming
before checking `supportedServicesMap`, or switch the block to the shared schema
parser used elsewhere. Make sure `servicesSpecified` still honors explicit
filters in `Services()` and that names like `app, other` resolve correctly
regardless of whitespace.

Source: Coding guidelines

pkg/providers/k8s/kubernetes.go (1)

72-88: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim explicit services values here as well.

This constructor still matches raw strings.Split output against supportedServicesMap, so services: "service, ingress" drops ingress if the token is space-prefixed. That diverges from the shared schema service parser and makes Kubernetes filtering behave differently from the rest of this feature. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/k8s/kubernetes.go` around lines 72 - 88, The Kubernetes
provider’s explicit services parsing in the constructor still uses raw strings
from strings.Split, so space-prefixed entries like " ingress" fail to match
supportedServicesMap. Update the services handling in kubernetes.go to trim each
token before lookup, keeping it aligned with the shared schema parser and the
Services()/filtering behavior. Use the existing services map setup and the
options.GetMetadata("services") branch as the place to normalize values before
adding them.

Source: Coding guidelines

pkg/providers/scaleway/scaleway.go (1)

37-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make services parsing match exclude_services parsing.

The new allowlist path still uses raw split tokens, so whitespace-padded values won't match supportedServicesMap. Since the exclude path already trims and the schema helper in this PR trims both, this provider now has slightly different filter behavior than the rest of the stack. As per coding guidelines, "Respect service filtering: Services() must list supported services, and providers should honor -s filters when gathering resources."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/providers/scaleway/scaleway.go` around lines 37 - 52, The services
allowlist parsing in Scaleway should match the trimming behavior used by
exclude_services and the schema helper. Update the services handling in the
Scaleway provider’s metadata parsing so the loop in the Services()/options path
trims each split token before checking supportedServicesMap and adding to
services, keeping filter behavior consistent with the rest of the stack.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/providers/alibaba/alibaba.go`:
- Around line 50-62: The Alibaba provider’s service selection logic is using
GetMetadata’s boolean as the presence check, which cannot distinguish a missing
services key from an explicitly empty value. Update the logic in the alibaba
provider’s metadata parsing path to detect raw key presence separately (or use a
helper that preserves presence) before defaulting. In the code that builds the
services map, keep an explicit empty services selection empty instead of falling
back to Services, and only populate all services when the key is truly absent.

In `@pkg/providers/arvancloud/arvancloud.go`:
- Around line 44-56: The service-selection logic in arvancloud.go is using
GetMetadata("services")’s boolean as the presence check, which conflates a
missing key with an explicitly empty value. Update the services parsing in the
provider initialization to detect raw key presence separately from the resolved
metadata value, and only fall back to Services when the key is truly absent.
Keep the existing supportedServicesMap filtering and ensure an empty explicit
services selection does not re-enable all services.

In `@pkg/providers/aws/aws.go`:
- Around line 91-104: The service-selection logic in aws.go is using
GetMetadata("services") as the presence check, which cannot distinguish a
missing key from an explicitly empty value. Update the block that populates
services in the provider code to detect raw key presence separately from the
resolved metadata value, and only fall back to the full Services list when the
key is truly absent. Keep the filtering behavior in the services parsing path so
an empty services selection does not re-enable all services.

In `@pkg/providers/custom/custom.go`:
- Around line 92-105: The service-selection logic in custom provider setup is
using GetMetadata("services") as both value and presence check, which makes an
explicit empty services selection fall back to all Services. Update the metadata
handling in custom.go so the code first checks raw key presence (or an
equivalent helper that distinguishes missing vs empty) before deciding whether
to populate services, and keep the filtered set empty when the key is present
but empty. Use the existing services map population around supportedServicesMap
and Services as the place to apply the fix.

In `@pkg/providers/digitalocean/digitalocean.go`:
- Around line 34-50: The DigitalOcean service filter in digitalocean.go is
matching raw CSV tokens against supportedServicesMap, so values with spaces are
skipped while exclude_services already trims inputs. Update the
Services()/metadata parsing block to trim each token before checking the
allowlist, or reuse the shared service parser used elsewhere so the services and
exclude_services handling stays consistent and honors -s filters correctly.

In `@pkg/providers/dnssimple/dnssimple.go`:
- Around line 61-77: The services allowlist in dnssimple still matches raw
strings from strings.Split, so values with surrounding spaces are not
recognized. Update the services parsing in the servicesSpecified branch to trim
each token before checking supportedServicesMap, or reuse the shared parser used
elsewhere in this PR, and keep exclude_services trimming behavior consistent in
dnssimple.Services/options handling.

In `@pkg/providers/heroku/heroku.go`:
- Around line 41-56: The service allowlist handling in Heroku metadata parsing
is inconsistent because the `services` entries are not trimmed while
`exclude_services` entries are; update the `services` loop in the Heroku
provider so each value is normalized with trimming before checking
`supportedServicesMap`, or switch the block to the shared schema parser used
elsewhere. Make sure `servicesSpecified` still honors explicit filters in
`Services()` and that names like `app, other` resolve correctly regardless of
whitespace.

In `@pkg/providers/k8s/kubernetes.go`:
- Around line 72-88: The Kubernetes provider’s explicit services parsing in the
constructor still uses raw strings from strings.Split, so space-prefixed entries
like " ingress" fail to match supportedServicesMap. Update the services handling
in kubernetes.go to trim each token before lookup, keeping it aligned with the
shared schema parser and the Services()/filtering behavior. Use the existing
services map setup and the options.GetMetadata("services") branch as the place
to normalize values before adding them.

In `@pkg/providers/linode/linode.go`:
- Around line 50-65: The service allowlist parsing in the Linode provider does
not trim whitespace before checking supported entries, so comma-separated values
in the services metadata can be skipped. Update the services handling in
linode.go where options.GetMetadata("services") is processed so each token is
normalized with trimming before the supportedServicesMap lookup, matching the
exclude_services behavior and the intended Services()/filter semantics.

In `@pkg/providers/scaleway/scaleway.go`:
- Around line 37-52: The services allowlist parsing in Scaleway should match the
trimming behavior used by exclude_services and the schema helper. Update the
services handling in the Scaleway provider’s metadata parsing so the loop in the
Services()/options path trims each split token before checking
supportedServicesMap and adding to services, keeping filter behavior consistent
with the rest of the stack.

In `@pkg/providers/vercel/vercel.go`:
- Around line 33-45: The services selection in the vercel provider should not
rely on GetMetadata’s boolean return to detect presence, because an explicit
empty value is being treated as missing and triggers the full Services fallback.
Update the logic in the vercel provider’s metadata parsing to check raw key
presence separately from the resolved value, then only default to Services when
the key is truly absent. Keep the supportedServicesMap filtering behavior intact
so explicit service filtering is honored.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b55ec4a-4af2-476a-9c39-6000ed4ec9c3

📥 Commits

Reviewing files that changed from the base of the PR and between 4dee5ca and d73f61b.

📒 Files selected for processing (21)
  • pkg/providers/alibaba/alibaba.go
  • pkg/providers/arvancloud/arvancloud.go
  • pkg/providers/aws/aws.go
  • pkg/providers/azure/azure.go
  • pkg/providers/cloudflare/cloudflare.go
  • pkg/providers/custom/custom.go
  • pkg/providers/digitalocean/digitalocean.go
  • pkg/providers/dnssimple/dnssimple.go
  • pkg/providers/gcp/gcp.go
  • pkg/providers/heroku/heroku.go
  • pkg/providers/hetzner/hetzner.go
  • pkg/providers/k8s/kubernetes.go
  • pkg/providers/linode/linode.go
  • pkg/providers/namecheap/namecheap.go
  • pkg/providers/openstack/openstack.go
  • pkg/providers/ovh/ovh.go
  • pkg/providers/scaleway/scaleway.go
  • pkg/providers/terraform/terraform.go
  • pkg/providers/vercel/vercel.go
  • pkg/schema/schema.go
  • pkg/schema/schema_test.go
🚧 Files skipped from review as they are similar to previous changes (10)
  • pkg/providers/ovh/ovh.go
  • pkg/providers/namecheap/namecheap.go
  • pkg/providers/terraform/terraform.go
  • pkg/providers/cloudflare/cloudflare.go
  • pkg/schema/schema_test.go
  • pkg/providers/openstack/openstack.go
  • pkg/providers/hetzner/hetzner.go
  • pkg/providers/azure/azure.go
  • pkg/schema/schema.go
  • pkg/providers/gcp/gcp.go

Addressed CodeRabbit review feedback: stopped flattening per-provider YAML exclude_services options into shared global state in NewRunner, preserving provider-specific YAML exclusions unless explicitly overridden by the CLI flag.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Add exclude_services support

1 participant