types

package
v0.52.0 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: 8 Imported by: 0

Documentation

Overview

Package types provides common type definitions used across the GitOps Reverser.

Index

Examples

Constants

View Source
const ClusterScopeSegment = "_cluster"

ClusterScopeSegment is what stands in the namespace position for a cluster-scoped resource: an illegal Kubernetes namespace name (DNS-1123 forbids "_"), so it can never collide with a real namespace and reads unambiguously as "not a namespace" — unlike a bare "cluster", which is itself a legal namespace name.

It is one constant rather than a literal per renderer because every surface that names a resource's scope must name it identically: the built-in Git path (ToGitPath), the {namespace} placement variable, and a commit message's .Namespace. There is no second, scope-aware spelling of any of the three — one concept, one word.

Variables

This section is empty.

Functions

func CanonicalLabelSelector added in v0.50.0

func CanonicalLabelSelector(selector *metav1.LabelSelector) (string, error)

CanonicalLabelSelector validates a rule's objectSelector and returns its canonical string: the selector's identity for the LIST/WATCH request, the collection key, the watch cursor, resync coalescing, render fidelity and retention.

Nil and empty both select everything and yield "". That is spelled out here because metav1.LabelSelectorAsSelector reads nil as "nothing", which on a mirror would be a sweep of every document in scope.

The normalization is syntactic, never a Boolean simplification: matchLabels equality becomes a singleton In, In/NotIn values are sorted and deduplicated, duplicate requirements collapse, and requirements sort by their whole (key, operator, values) tuple. labels.Selector.String alone is not enough: its sort compares keys only, so `team in (a,b),team notin (b)` and its reverse would be two identities for one selection, and a reordered rule would restart its watch.

func ValidateObjectSelectors added in v0.50.0

func ValidateObjectSelectors(selectors []*metav1.LabelSelector) error

ValidateObjectSelectors checks a rule's spec.rules[].objectSelector values, in order, and returns an error naming the first that does not parse. The rule compiler refuses a rule on it.

Types

type CollectionKey added in v0.50.0

type CollectionKey struct {
	// Group is the API group, empty for the core group.
	Group string
	// Resource is the plural resource name, e.g. "configmaps".
	Resource string
	// Namespace restricts the collection to one namespace. Empty is a genuinely cluster-wide
	// (all-namespaces) collection, never a replacement for a named namespace on the same type:
	// collapsing the two widened the named rule's stream to every namespace its credential could
	// read. The two overlap, so one GitTarget cannot select both.
	Namespace string
	// LabelSelector is the canonical label selector (see CanonicalLabelSelector) the API server
	// selects the collection with. Empty selects every object.
	LabelSelector string
}

CollectionKey identifies one resource collection of one cluster: a type, optionally one namespace, and the label selector the API server applies to it. One key is one LIST/WATCH request. It is the shared identity of a target-watch stream, its resume cursor, the render-fidelity scope that stream reports into, and the resync its snapshot queues.

The selector names the collection, not the Git objects it owns

The sweep boundary is STRUCTURAL: group, resource, namespace (see Matches). A selected snapshot owns every managed document of its type in its namespace scope, including documents the selector never matched, so a selector narrows what the mirror holds rather than which documents a sweep may reach. Two selectors over one boundary are two collections, and the rule resolver refuses a second collection over an overlapping scope of one GitTarget, so two snapshots never sweep each other's documents and no object reaches the target on two streams.

The version is deliberately absent

A collection is named by GROUP, RESOURCE and NAMESPACE, never by served version. The three identities above used to carry a full GroupVersionResource while the only thing that actually compared them — the sweep's Matches — ignored the version, so two collections differing only in served version were distinct keys but one sweep boundary. A key that does not round-trip to the scope it sweeps under is the one class of error that deletes user data, so the version was removed from the identity rather than added to the comparison.

This matches the identity Git already uses: ResourceIdentifier.ToGitPath is versionless, so a storage-version bump moves no file. A collection whose identity changed with the served version would sweep a boundary that the files inside it do not share.

The served version is still needed — to open a watch, to render a reconcile commit message — but it travels as DATA on whatever carries the collection, never as part of the key.

func CollectionKeyFor added in v0.50.0

func CollectionKeyFor(gvr schema.GroupVersionResource, namespace string) CollectionKey

CollectionKeyFor builds a collection key from a served GVR and a namespace, dropping the version. It is the single conversion from "the version we happen to be serving" to "the slice we manage", so no call site has to remember that the version is not identity.

func (CollectionKey) Matches added in v0.50.0

func (c CollectionKey) Matches(ri ResourceIdentifier) bool

Matches reports whether a resolved resource identity falls inside this collection's sweep boundary. An empty Namespace matches every namespace for the type; neither the version nor the label selector is compared, for the reasons given on the type.

func (CollectionKey) Overlaps added in v0.50.0

func (c CollectionKey) Overlaps(other CollectionKey) bool

Overlaps reports whether two collections' sweep boundaries can hold the same object: the same type, and the same namespace or one of them all namespaces. The selector is not compared, since the boundary is structural.

func (CollectionKey) String added in v0.50.0

func (c CollectionKey) String() string

String renders the collection for logs, map keys and status messages: "configmaps in team-a", "deployments.apps" (cluster-wide), "secrets in team-a selecting tier=x".

type OperationType added in v0.50.0

type OperationType string

OperationType classifies one observed change to an object: its creation, an update, or its deletion. It tags watch events and audit verbs alike, so both paths agree on what happened. It is not a selection switch: every selected resource collection is observed through its whole lifecycle, and the GitTarget's prune mode decides what a deletion does to Git.

const (
	// OperationCreate tags an object's creation.
	OperationCreate OperationType = "CREATE"
	// OperationUpdate tags a change to an existing object.
	OperationUpdate OperationType = "UPDATE"
	// OperationDelete tags an object's deletion.
	OperationDelete OperationType = "DELETE"
)

type ResourceIdentifier

type ResourceIdentifier struct {
	Group     string // e.g., "apps", "" for core resources
	Version   string // e.g., "v1"
	Resource  string // Plural form, e.g., "deployments", "pods"
	Namespace string // Empty string for cluster-scoped resources
	Name      string // Resource name
}

ResourceIdentifier encapsulates all information needed to uniquely identify a Kubernetes resource. Its Key() is the fully-qualified REST-style identity ({group}/{version}/{resource}/{namespace}/{name}); its ToGitPath() is the versionless, namespace-first Git storage path (see that method).

func NewResourceIdentifier

func NewResourceIdentifier(group, version, resource, namespace, name string) ResourceIdentifier

NewResourceIdentifier creates a ResourceIdentifier from explicit parts. Useful for watch-based ingestion where we know group/version/resource.

func (ResourceIdentifier) IsClusterScoped

func (r ResourceIdentifier) IsClusterScoped() bool

IsClusterScoped returns true if the resource is cluster-scoped.

func (ResourceIdentifier) Key

func (r ResourceIdentifier) Key() string

Key returns a stable, fully-qualified identifier suitable for map keys and deduplication.

The exact string is a public contract. Tools built around GitOps Reverser key their own rows on this identity and join them against ours, so a consumer that cannot import this package (it lives under internal/) reimplements the format from this comment. Changing any byte of it is a breaking change rather than a refactor, and TestResourceIdentifier_Key_GoldenFormat is the gate that turns such a change into a decision instead of a silent split.

namespaced:      "{group}/{version}/{resource}/{namespace}/{name}"
cluster-scoped:  "{group}/{version}/{resource}/{name}"

Two rules a reimplementation has to get right, and they pull in opposite directions:

  • A cluster-scoped resource DROPS the namespace segment; it does not emit an empty one. Always joining five parts yields "…/clusterroles//admin", which never joins.
  • A core-group resource has an EMPTY group segment, which it does emit, so the key leads with "/".

The four shapes, which are the four cases of the golden test:

apps/v1/deployments/prod/api                        namespaced, grouped
rbac.authorization.k8s.io/v1/clusterroles/admin     cluster-scoped, grouped
/v1/secrets/prod/db                                 namespaced, core group
/v1/nodes/node-1                                    cluster-scoped, core group

Key versus ToGitPath: which one is "the same resource"

Key includes Version and ResourceIdentifier.ToGitPath deliberately excludes it, so the two disagree about whether a preferred-version bump is the same object. The decision, recorded at both methods: Key is the API-side identity — correct for in-process map keys, deduplication and logs, where every participant observes one version at a time — and the versionless, namespace-first path is the DURABLE identity of the object, which is why a storage-version bump moves no file in Git.

A join that must survive a storage-version bump is therefore keyed on the versionless identity, not on Key. Consumers holding rows across releases should drop the version segment (the second) rather than treat "apps/v1/deployments/prod/api" and "apps/v2/deployments/prod/api" as two resources.

Example

ExampleResourceIdentifier_Key shows the four shapes of the key format, including the two empty-segment rules that pull in opposite directions.

namespaced := ResourceIdentifier{
	Group: "apps", Version: "v1", Resource: "deployments", Namespace: "prod", Name: "api",
}
clusterScoped := ResourceIdentifier{
	Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterroles", Name: "admin",
}
coreNamespaced := ResourceIdentifier{
	Version: "v1", Resource: "secrets", Namespace: "prod", Name: "db",
}
coreClusterScoped := ResourceIdentifier{
	Version: "v1", Resource: "nodes", Name: "node-1",
}

fmt.Println(namespaced.Key())
fmt.Println(clusterScoped.Key())     // no empty namespace segment
fmt.Println(coreNamespaced.Key())    // empty group: a leading "/"
fmt.Println(coreClusterScoped.Key()) // both rules at once
Output:
apps/v1/deployments/prod/api
rbac.authorization.k8s.io/v1/clusterroles/admin
/v1/secrets/prod/db
/v1/nodes/node-1

func (ResourceIdentifier) NamespaceOrCluster added in v0.46.0

func (r ResourceIdentifier) NamespaceOrCluster() string

NamespaceOrCluster is the resource's namespace, or ClusterScopeSegment when it is cluster-scoped. A cluster-scoped resource HAS a scope name; it is simply not a namespace.

func (ResourceIdentifier) String

func (r ResourceIdentifier) String() string

String returns a human-readable representation.

func (ResourceIdentifier) ToGitPath

func (r ResourceIdentifier) ToGitPath() string

ToGitPath states the built-in Git file path for a new resource by hand. Writers do not call it: they render manifestanalyzer.BuiltinPlacementTemplate, and a test pins the two byte for byte, so this is the readable reference for the shape rather than a second implementation: {namespace-or-cluster}/{group}/{resource}/{name}.yaml. The scope segment leads (a real namespace, or the literal "_cluster" for a cluster-scoped resource) so a repository reads namespace-first, the way a human browses it; the API group is omitted for core resources, and the API version is deliberately left out — the operator writes one version per object, so a version segment adds noise and would churn the path on a preferred-version bump. It is only the last rung for a NEW document: a declared placement or the folder's one kustomize root answers first, and an existing document is always edited in place at its current location (match-first), so changing this shape never moves a file that is already in Git. See docs/layout/new-file-placement-rules.md.

That omitted version is the other half of the decision recorded at ResourceIdentifier.Key: this versionless identity is the durable one — the object stays the same object across a preferred-version bump — while Key is the API-side identity and splits on that bump. Neither is wrong; they answer different questions, and a caller joining data that outlives a release wants this one.

Example

ExampleResourceIdentifier_ToGitPath contrasts the two identity functions on one object: the key carries the API version, the path deliberately does not.

deployment := ResourceIdentifier{
	Group: "apps", Version: "v1", Resource: "deployments", Namespace: "prod", Name: "api",
}
node := ResourceIdentifier{Version: "v1", Resource: "nodes", Name: "node-1"}

fmt.Println(deployment.Key())
fmt.Println(deployment.ToGitPath())
fmt.Println(node.Key())
fmt.Println(node.ToGitPath()) // cluster-scoped resources live under "_cluster"
Output:
apps/v1/deployments/prod/api
prod/apps/deployments/api.yaml
/v1/nodes/node-1
_cluster/nodes/node-1.yaml

type ResourceReference

type ResourceReference struct {
	Name      string
	Namespace string
	UID       string
}

ResourceReference references a Kubernetes resource by name and namespace. Provides a clean, reusable type for referencing GitDestinations and other resources.

UID, when set, identifies the specific object generation. It is deliberately excluded from String/Key/Equal so in-memory bookkeeping stays keyed by namespace/name; it scopes durable Redis keys (e.g. watch cursors) so a recreated GitTarget never inherits a deleted predecessor's state.

func NewResourceReference

func NewResourceReference(name, namespace string) ResourceReference

NewResourceReference creates a new resource reference.

func (ResourceReference) Equal

func (r ResourceReference) Equal(other ResourceReference) bool

Equal checks if two references are equal.

func (ResourceReference) IsZero

func (r ResourceReference) IsZero() bool

IsZero returns true if this is an empty reference.

func (ResourceReference) Key

func (r ResourceReference) Key() string

Key returns a string key suitable for map lookups: "namespace/name".

Not to be confused with ResourceIdentifier.Key, which is the fully-qualified "{group}/{version}/{resource}/{namespace}/{name}" identity of a watched object. This one names a GitTarget-like object by reference and carries no group, version or resource.

func (ResourceReference) String

func (r ResourceReference) String() string

String returns "namespace/name" format.

func (ResourceReference) WithUID

WithUID returns a copy of the reference carrying the given object UID.

type SensitiveResourcePolicy

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

SensitiveResourcePolicy classifies resource types that must use the encrypted Git write path. Core Kubernetes Secrets are always sensitive.

func ParseSensitiveResourcePolicy

func ParseSensitiveResourcePolicy(additional string) (SensitiveResourcePolicy, error)

ParseSensitiveResourcePolicy builds a policy from comma-separated additional entries in resource or group/resource form.

func (SensitiveResourcePolicy) Entries

func (p SensitiveResourcePolicy) Entries() []string

Entries returns the built-in and additional sensitive resource types in flag form.

func (SensitiveResourcePolicy) IsSensitive

func (p SensitiveResourcePolicy) IsSensitive(group, resource string) bool

IsSensitive reports whether group/resource must use the encrypted Git write path.

Jump to

Keyboard shortcuts

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