Skip to content

Add controller-reference subject owner adapter - #1557

Open
nadaverell wants to merge 3 commits into
mainfrom
nadav/rad-418-subject-parent-parity
Open

nadaverell wants to merge 3 commits into
mainfrom
nadav/rad-418-subject-parent-parity

Conversation

@nadaverell

@nadaverell nadaverell commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Status and program context

Ready for review as an independent foundation. No production consumer uses this resolver yet.

The GPU, batch, and AI/ML breadth work exposed a shared prerequisite: Radar cannot compose controller-generated resources across Topology, Applications, Issues, Timeline, and MCP while owner identity is only Kind + namespace + name. This PR is the P0.1c subject-parity foundation for resolving Kubernetes controller ownership with exact API-group identity. Controller-native contexts and drilldowns such as JobSet are separate verticals.

Summary

  • add a pure, group-aware ControllerOwnerResolver over injected exact-resource lookup and exact group/kind scope resolution
  • follow only Kubernetes controller references, preserving authoritative group, kind, and owner name while deriving namespace from known resource scope
  • fail closed when a namespaced child's controller scope is unknown instead of fabricating a namespaced or cluster-scoped identity
  • add a parity corpus for Deployment, CronJob, Rollout, JobSet, RayService, CloudNativePG, Strimzi, and Crossplane ownership chains
  • pin partial-cache behavior: a child may identify an unobserved controller when its scope is known, but the walk stops there

Dependency and merge map

  • This PR targets main and is independently mergeable.
  • Rebased onto current main. Everything this PR referenced has since merged (#1558, #1559, #1560, the JobSet stack), along with #1868, which moved identity helpers into pkg/resourceid. The resolver now uses resourceid.GroupFromAPIVersion.
  • #1560 is separate exact-resource, Topology, and Applications identity work. It does not consume or wire this owner resolver; reviewers should not infer that Add controller-reference subject owner adapter #1557 is production-connected through Make topology and application identity API-group-aware #1560.
  • It does not block the JobSet stack #1552 -> #1562 -> #1561.
  • A later production-adapter PR must wire the scope callback to group-aware API discovery and migrate consumers one at a time. This PR deliberately does not make that global switch.

Review focus

  • controller references only: never follow non-controller owner references or broad topology management edges
  • exact API group and Kind preservation across multi-hop chains
  • scope resolution for namespaced children whose controller may be namespaced or cluster-scoped
  • fail-closed behavior when scope is unknown, and bounded behavior when an identified parent is not cached
  • parity fixtures for existing integrations, not only the new GPU ecosystem

Deliberate boundaries

This PR does not switch a production consumer, expand operator allowlists, follow broad topology management edges, or aggregate root-level Issues. The Strimzi fixture intentionally stops at StrimziPodSet: current Strimzi creates the KafkaNodePool reference with controller=false, so following it would violate the contract.

Scope and terminal hardening

  • A cluster-scoped child whose controller owner is known to be namespaced resolves to no parent. The garbage collector treats that owner as unresolvable.
  • Only the core-group Node is the static-pod terminal. A custom Node kind from another API group collapses like any other controller.

Known gaps for the production-adapter PR

  • Owner UID is not validated. Ref carries no UID. If a Pod still references deleted Job A and a new Job with the same name exists, the walk follows the new Job to that Job's root. The adapter needs to carry the owner UID (resourceid.OwnerReference keeps it) and check it at each hop.
  • Operator anchor. Used as both OwnerResolver and DefaultOperatorRoots.Owners, this full controller walk goes past the operator CR before the hook runs. CNPG and similar subjects then anchor as owner_collapsed, never operator_cr. The first consumer must decide where the operator boundary sits and test the whole Subject, including Anchor.
  • ScopeForKind still classifies by Kind alone.

Source revalidation

Verification

  • (cd pkg && go test ./subject ./resourceid)
  • go build ./... and (cd pkg && go build ./...)
  • go test ./internal/cloudinstall
  • git diff --check
  • Mutation check: reverting either new guard fails its regression test

Visual testing was skipped because this has no rendered UI path or production consumer change.

Part of RAD-418.


Note

Low Risk
New isolated resolver with tests only; the small ResolveSubject Node guard change is unlikely to affect current callers that mostly use overlay resolution, not owner walks.

Overview
Introduces ControllerOwnerResolver, a Tier-1 OwnerResolver that walks only ownerReferences with controller=true via injected object lookup. Parent refs keep the exact API group (from GroupFromAPIVersion), kind, and owner name; namespace is inferred from an IsNamespaced(group, kind) callback. For namespaced children, resolution fails closed when owner scope is unknown; cluster-scoped children reject a known namespaced controller.

Adds a broad parity test corpus (Deployment, CronJob, Rollout, JobSet, Ray, CNPG, Strimzi, Crossplane) covering multi-hop ResolveSubject collapse, partial cache (stop at unobserved parent), and edge cases (non-controller owners, incomplete refs, core vs custom Node).

ResolveSubject now treats Node as a terminal anchor only for the core API group (Group == ""), so a CRD kind named Node can still collapse up the controller chain. Package docs and the OwnerResolver contract are updated to describe object-backed vs heuristic behavior. No production wiring in this PR—the resolver is foundation-only.

Reviewed by Cursor Bugbot for commit 35754e0. Bugbot is set up for automated code reviews on this repo. Configure here.

@nadaverell
nadaverell requested a review from hisco as a code owner August 31, 2026 01:22

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit be830d5. Configure here.

Comment thread pkg/subject/controller_owner.go
Use resourceid.GroupFromAPIVersion after the identity centralization,
reject a known-namespaced controller owner of a cluster-scoped child, and
treat only the core-group Node as the static-pod terminal.
@nadaverell
nadaverell force-pushed the nadav/rad-418-subject-parent-parity branch from d7bdf26 to 35754e0 Compare September 29, 2026 23:53
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.

1 participant