providerclaims

package
v0.2.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package providerclaims is the one answer to "which permission claims does a tenant's APIBinding to a provider's export carry".

A provider declares what it needs once, in CatalogEntry.spec.requires; codegen stamps the same list onto its APIExport. kcp, however, acts only on the claims the tenant's own binding lists, and the binding is written by the hub's Enable flow — once. This package holds the policy that keeps the two in step, and the reconciler that applies it whenever either side changes, so a provider that grows a requirement does not need every tenant to re-enable it.

The policy, in one place:

  • A requirement that names no provider (a platform builtin, a core kind) is the provider's own machinery; the tenant consented to the provider, so the hub accepts it on their behalf.
  • A requirement that names another provider is a composition: a claim on somebody else's kinds. It is Accepted only where the workspace's Grant records that consent, and Rejected otherwise — never silently granted.
  • A claim the binding already holds Rejected stays Rejected (the writer in pkg/hub/kcp enforces this), and an existing claim keeps its selector.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConsentedCompositions

func ConsentedCompositions(grant *tenancyv1alpha1.Grant) map[string]bool

ConsentedCompositions reads the compositions a Grant records as accepted, keyed by Key(group, resource).

func Desired

func Desired(prov providers.Provider, grant *tenancyv1alpha1.Grant) []kcp.ProviderClaim

Desired is the claim set the hub keeps on a tenant's binding to prov's export: every requirement the provider declares, with the provider's own requirements Accepted and compositions Accepted only where grant records the workspace's consent. grant may be nil (no consent recorded).

Own requirements are accepted for platform and org-owned providers alike: an org-owned provider is registered by the Org's own admins, who already hold admin in every workspace of that Org, so a claim they declare widens nothing they could not grant directly. AGENTS.md §5.1 records that decision.

A composition the grant consents to is marked Consented, so the merge in pkg/hub/kcp knows the Rejected it may be replacing was the hub's own placeholder, not a tenant's decision.

func Key

func Key(group, resource string) string

Key identifies a claim by what identifies it on a binding: group and resource. Verbs and selectors ride along with the declaration.

func RequiredClaims

RequiredClaims renders spec.requires as the binding's permission claims, one per declared coordinate, Accepted as isAccepted says. These are the same claims provider-sdk/cmd/apiexportgen puts on the generated APIExport, so the binding lists exactly what the export declares.

A verb coordinate ("instances/exec") is claimed whole: the verb IS the capability, and which HTTP method it uses — which is what kcp maps onto an RBAC verb — is the serving provider's transport detail, so the claim spells every verb.

func SetupWithManager

func SetupWithManager(mgr mcmanager.Manager, clusters ClusterNamer, ops BindingOps, registry ProviderLookup, grants GrantReader) error

SetupWithManager wires the reconciler into mgr. clusters is the manager's multicluster provider (its engaged cluster set), grants may be nil.

Types

type BindingOps

type BindingOps interface {
	// EnsureCoreBindingClaims brings the hub's own `railgrid` binding in the
	// cluster to the embedded core export's claim set.
	EnsureCoreBindingClaims(ctx context.Context, clusterName, bindingName string) (bool, error)
	// ReconcileProviderBindingClaims merges claims onto a provider binding
	// under the rules documented on kcp.Bootstrapper.ReacceptProviderAPIBindingClaims.
	ReconcileProviderBindingClaims(ctx context.Context, clusterName, bindingName string, claims []kcp.ProviderClaim) (bool, error)
	// ResolveClusterPath returns a logical cluster's workspace path.
	ResolveClusterPath(ctx context.Context, clusterName string) (string, error)
}

BindingOps is the slice of the kcp Bootstrapper the reconciler writes through. Reads come from the core.railgrid.ai virtual workspace, which serves APIBindings read-only; every write goes to the workspace by its logical cluster with the hub's own credential.

type ClusterNamer

type ClusterNamer interface {
	ClusterNames() []multicluster.ClusterName
}

ClusterNamer lists the logical clusters a multicluster provider currently engages. apiexportprovider.Provider.Clusters satisfies it.

type GrantReader

type GrantReader interface {
	Get(ctx context.Context, key hubaccess.GrantKey) (*tenancyv1alpha1.Grant, error)
}

GrantReader reads the consent a workspace recorded for a provider. *hubaccess.Store satisfies it; nil means no grant store is wired and no composition is ever accepted by this reconciler.

type ProviderLookup

type ProviderLookup interface {
	Get(name string) (providers.Provider, bool)
	GetForOrg(orgUUID, name string) (providers.Provider, bool)
	OnRequirementsChange(fn providers.RequirementsListener) (unregister func())
}

ProviderLookup is the registry view the reconciler needs: resolve the provider behind an export reference, and learn when requirements change.

type Reconciler

type Reconciler struct {
	// contains filtered or unexported fields
}

Reconciler keeps every tenant APIBinding's accepted permission claims in lockstep with what the bound export declares today.

It runs on the core.railgrid.ai multicluster manager: every tenant workspace binds that export, and the export claims apis.kcp.io/apibindings, so its virtual workspace serves every APIBinding in every tenant workspace that accepted the claim. Two kinds of binding are reconciled, and nothing else:

  • the hub's own `railgrid` binding to core.railgrid.ai, brought to the embedded export's claim set. This is also how the apibindings claim itself reaches workspaces enabled before it existed: kcp serves an export's own bindings through its virtual workspace regardless of acceptance, so the reconciler sees `railgrid` first, accepts the claim, and only then sees the provider bindings beside it.
  • a tenant's binding to a provider's export, brought to the claim set Desired derives from the provider's current spec.requires and the workspace's Grant.

Triggers are the binding events themselves and, through the registry's requirements listener, a CatalogEntry whose spec.requires changed, which fans out to every binding of that export the manager can see. There is no timer and no fleet walk: a workspace the manager has not engaged is one that does not hold the core binding, and so holds nothing to reconcile.

func (*Reconciler) Reconcile

func (r *Reconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error)

Reconcile fetches the binding through the virtual workspace and hands it to reconcileBinding.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL