admission

package
v0.7.2 Latest Latest
Warning

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

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

Documentation

Overview

Package admission is the control-plane admission framework (ADR-0063): a two-phase pipeline (mutate-all → validate-all) of single-purpose Admissions run on every resource write, after authz and before the store. It generalizes the former inline obj.Validate() admit step (ADR-0018) and opens the cross-resource/Delete extension point (ADR-0064 links consume it).

It is a near-leaf: it imports api/types, internal/auth, api/fault only — it nests under internal/controlplane but must NOT import its parent package (no cycle).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Members added in v0.4.0

func Members(ctx context.Context, r StoreReader, ns v1.NamespaceName, group v1.ResourceGroupName) ([]v1.Object, error)

Members returns the members of ResourceGroup group in ns (ADR-0170 Decision 7): every object of a namespaced kind other than ResourceGroup, in ns, whose metadata.resourceGroup is group and that no controller owns (a controlled child goes with its owner). Platform-written records (WorkflowRuns, Invocations) count.

Types

type Admission

type Admission interface {
	// Name identifies the admission in errors and ordering (stable, kebab-case).
	Name() string
	// Phase is Mutating or Validating.
	Phase() Phase
	// Handles reports whether this admission applies to the given GVK + operation.
	Handles(gvk v1.GroupVersionKind, op Operation) bool
	// Admit reviews req and returns the (possibly-mutated) object, or a fault error denying the write.
	Admit(ctx context.Context, req Request) (v1.Object, error)
}

Admission reviews a write before it is persisted. Deterministic and side-effect-free. A Validating admission returns req.Object on allow, or a fault error (Invalid/Forbidden/Conflict/PayloadTooLarge) on deny. A Mutating admission returns the object to carry forward, or a fault error.

func NewBucketDeletionProtectionAdmission

func NewBucketDeletionProtectionAdmission(r StoreReader, p BlobProber) Admission

NewBucketDeletionProtectionAdmission returns the Validating admission that protects Bucket data (ADR-0080). On Delete: Conflict if any Function.spec.blob names the bucket OR any prefix still holds objects. On Update: Conflict if a prefix removed from spec.prefixes[] is still named by some Function.spec.blob OR still holds objects. (Clone of kvstore-deletion-protection, scanning spec.blob.) The prober is optional — a nil prober skips the data-emptiness check (binding-protection still applies).

func NewBucketQuotaAdmission

func NewBucketQuotaAdmission(r StoreReader, maxPerNamespace int) Admission

NewBucketQuotaAdmission returns the Validating admission that rejects creating a Bucket when its namespace already holds maxPerNamespace buckets (ADR-0080 bucket-count quota). maxPerNamespace ≤ 0 disables the quota.

func NewKVStoreDeletionProtectionAdmission

func NewKVStoreDeletionProtectionAdmission(r StoreReader, p KVProber) Admission

NewKVStoreDeletionProtectionAdmission returns the Validating admission that protects KVStore data (ADR-0073). On Delete: Conflict if any Function.spec.kv names the store OR it still holds keys. On Update: Conflict if a table removed from spec.tables[] is still named by some Function.spec.kv, or if an added table still holds the data of its removed namesake (not yet reclaimed by the reconciler, which only diffs the current spec against the live data). (Clone of link-deletion-protection, scanning spec.kv.)

func NewKVStoreQuotaAdmission

func NewKVStoreQuotaAdmission(r StoreReader, maxPerNamespace int) Admission

NewKVStoreQuotaAdmission returns the Validating admission that rejects creating a KVStore when its namespace already holds maxPerNamespace stores (ADR-0072 store-count quota). maxPerNamespace ≤ 0 disables the quota.

func NewLinkDeletionProtectionAdmission

func NewLinkDeletionProtectionAdmission(r StoreReader) Admission

NewLinkDeletionProtectionAdmission returns the Validating admission that rejects deleting a Function that is another Function's link target (ADR-0064). It reads Request.Old.

func NewLinkValidityAdmission

func NewLinkValidityAdmission(r StoreReader) Admission

NewLinkValidityAdmission returns the Validating admission that enforces ADR-0064's cross-resource link rules on Create/Update: every link target exists in the namespace, and the namespace link graph stays acyclic with the applied function (a self-link is a degenerate cycle).

func NewPolicyValidityAdmission

func NewPolicyValidityAdmission() Admission

NewPolicyValidityAdmission returns the Validating admission that enforces ADR-0074's Policy rules on a Policy Create/Update: spec.cedar PARSES as Cedar and references only the curated actions + entity types (kv::read/kv::write; Function/KVStore/KVTable), and its scopes name no entity of another namespace (ADR-0177). An un-parseable, off-schema or foreign-namespace Policy is rejected (fault.Invalid) before it reaches the metastore — so the cedar driver can rely on every stored Policy compiling. (Shape cloned from the link/KV validity admissions.)

func NewResourceGroupDeletionProtectionAdmission added in v0.4.0

func NewResourceGroupDeletionProtectionAdmission(r StoreReader) Admission

NewResourceGroupDeletionProtectionAdmission returns the Validating admission that refuses deleting a ResourceGroup while it has a member (ADR-0170 Decision 7), naming up to five members and the count.

func NewSitePrefixImmutableAdmission

func NewSitePrefixImmutableAdmission() Admission

NewSitePrefixImmutableAdmission returns the Validating admission that rejects any change to spec.prefix on Update. The reconciler only ever adds prefixes to the Bucket, so a changed prefix would orphan the old one with its objects (ADR-0139 Decision §7). It needs no dependencies — Old and Object are both on the Request — and it never consults Old.Status, which an apply wipes.

func NewValidateAdmission

func NewValidateAdmission() Admission

NewValidateAdmission returns the built-in Validating admission that runs obj.Validate() for every kind on Create and Update.

func NewWorkflowRunContractAdmission

func NewWorkflowRunContractAdmission(r workflowGetter) Admission

NewWorkflowRunContractAdmission returns the Validating admission that checks a WorkflowRun's spec.input against its parent Workflow's CACHED status.contract.input (ADR-0098) — zero registry I/O. A parent that is absent or not-yet-Ready (no cached contract) is allowed: the engine's run-start gate is the backstop, and a dangling spec.workflow is the run reconciler's concern.

func NewWorkflowRunPayloadAdmission

func NewWorkflowRunPayloadAdmission(limit int64) Admission

NewWorkflowRunPayloadAdmission returns the Validating admission that rejects a WorkflowRun whose spec.input exceeds the payload cap (ADR-0094: run payloads are size-bounded control-plane metadata; larger data travels by reference on the blob substrate). limit ≤ 0 disables the cap.

func NewWorkflowRunSpecImmutableAdmission added in v0.2.1

func NewWorkflowRunSpecImmutableAdmission() Admission

NewWorkflowRunSpecImmutableAdmission returns the Validating admission that rejects an Update changing a WorkflowRun's spec.workflow, spec.input or spec.replay. The engine runs a run's spec once, so a second run applied under an existing name is rejected (ADR-0094 duplicate-run-name-rejected) instead of replacing the record of what ran; spec.paused and spec.cancel stay mutable.

type BlobProber

type BlobProber interface {
	// HasAny reports whether any object exists under the prefix of the namespace's bucket.
	HasAny(ctx context.Context, ns v1.NamespaceName, bucket v1.ObjectName, prefix string) (bool, error)
}

BlobProber probes whether a Bucket prefix holds any objects (ADR-0080): the deletion-protection admission uses it to block deleting a bucket (or removing a prefix) that still holds data. Declared HERE (like KVProber/StoreReader) so the admission package stays a near-leaf; the wiring resolves the Bucket to the substrate view the s3gateway writes, so the key layout has one owner. Optional — a nil prober skips the data-emptiness check (binding-protection still applies).

type KVProber

type KVProber interface {
	// HasAny reports whether any key exists under prefix.
	HasAny(ctx context.Context, prefix string) (bool, error)
}

KVProber probes whether a KVStore holds any keys (ADR-0072): the deletion-protection admission uses it to block deleting a store that still holds data. Declared HERE (like StoreReader) so the admission package stays a near-leaf; the wiring adapts the kvstore driver's List to it.

type NamespaceReading added in v0.4.0

type NamespaceReading interface {
	ReadsNamespace() bool
}

NamespaceReading marks an admission that needs the namespace's admission lock (ADR-0147): two concurrent writes it admits could store a state no sequential order of them allows. The control plane holds the lock from the Old fetch through the store write.

type Operation

type Operation string

Operation is the resource write being admitted.

const (
	Create Operation = "create"
	Update Operation = "update"
	Delete Operation = "delete"
)

type Phase

type Phase int

Phase orders an admission: all Mutating run (threading the object), then all Validating.

const (
	// Mutating admissions may return a changed object; they run first.
	Mutating Phase = iota
	// Validating admissions are read-only checks; they run on the final object.
	Validating
)

type Pipeline

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

Pipeline runs the registered admissions for a write: all Mutating (threading the object), then all Validating. Construct once at server start with NewPipeline; it is read-only thereafter.

func NewPipeline

func NewPipeline(admissions ...Admission) *Pipeline

NewPipeline registers admissions, partitioning by Phase; registration order within a phase is preserved (it is the deterministic tie-break).

func (*Pipeline) Admit

func (p *Pipeline) Admit(ctx context.Context, req Request) (v1.Object, error)

Admit runs all Mutating admissions (threading req.Object — each may transform it), then all Validating ones (each sees the final object), skipping any whose Handles is false. The first fault error short-circuits. Returns the final (possibly-mutated) object.

func (*Pipeline) Handles

func (p *Pipeline) Handles(gvk v1.GroupVersionKind, op Operation) bool

Handles reports whether any registered admission applies to (gvk, op) — lets a caller skip an Old-object fetch on Delete when nothing admits deletes.

func (*Pipeline) ReadsNamespace added in v0.4.0

func (p *Pipeline) ReadsNamespace(gvk v1.GroupVersionKind, op Operation) bool

ReadsNamespace reports whether any admission handling (gvk, op) implements NamespaceReading and returns true: the write must hold its namespace's admission lock (ADR-0147).

type Request

type Request struct {
	Operation Operation
	GVK       v1.GroupVersionKind
	Object    v1.Object
	Old       v1.Object
	Identity  auth.Identity
}

Request is one admission review. Object is the incoming desired object (nil on Delete); Old is the stored object (nil on Create; set on Update/Delete). GVK is the route's kind (authoritative, not body-derived). Identity is the authenticated caller (authz already passed).

type StoreReader

type StoreReader interface {
	List(ctx context.Context, gvk v1.GroupVersionKind, ns v1.NamespaceName) ([]v1.Object, error)
}

StoreReader is the read-only store view a cross-resource admission needs. It is a subset of store.Store declared here so the admission package stays a near-leaf (the wiring adapts the real store.Store to this interface).

Jump to

Keyboard shortcuts

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