Skip to content

GenericChange Kubernetes notifications can lose subject.namespace and be routed to the wrong sink #2044

@akhasanshin

Description

@akhasanshin

Description

When Robusta creates a default finding for Kubernetes change events, it uses the aggregation key GenericChange but does not populate the finding subject.

Because sink routing uses finding.subject.namespace, these notifications may end up with namespace == "None" in the scope/grouping layer and can be sent to the wrong sink.

This is especially visible when users configure Slack sinks with routing rules like:

  • one sink for namespace: production
  • another sink that explicitly includes namespace: "None"

In that setup, a Kubernetes resource that actually belongs to production may still be routed to the "None" sink if the finding was created through the default GenericChange path.

Actual Behavior

A Kubernetes change notification is sent with:

  • aggregation_key = GenericChange
  • namespace = None
  • missing or undefined grouped labels such as app=(undefined)

As a result, sink scope matching may route the notification incorrectly.

Expected Behavior

Default findings created for Kubernetes change events should preserve the Kubernetes subject metadata, including:

  • subject.name
  • subject.namespace
  • subject.labels
  • subject.annotations
  • source = KUBERNETES_API_SERVER

This ensures sink routing and Slack grouping use the actual resource namespace instead of "None".

Root Cause

K8sBaseChangeEvent.create_default_finding() creates a Finding with only:

  • title
  • aggregation_key = "GenericChange"

but without:

  • subject=self.get_subject()
  • source=self.get_source()

Later, routing relies on finding.attribute_map["namespace"], which is derived from finding.subject.namespace. Since the subject is missing, namespace becomes "None".

Proposed Fix

Update the default finding creation for Kubernetes change events to include the event subject and source.

Suggested change:

return Finding(
    title=title,
    aggregation_key="GenericChange",
    subject=self.get_subject(),
    source=self.get_source(),
)

Impact

This bug can cause:

  • incorrect sink routing
  • incorrect Slack grouping by namespace
  • confusing summaries showing namespace: None
  • alerts from production workloads appearing in fallback or infra channels

Reproduction Idea

Configure two Slack sinks:

  • one with scope.include: namespace: production
  • one with scope.include: namespace: "None"

Trigger a Kubernetes change event that goes through the default GenericChange path.
Observe that the notification may be routed to the "None" sink even though the resource actually belongs to production.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions