diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6eeb22e..68edcf3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,37 +10,37 @@ jobs: ci: runs-on: ubuntu-latest steps: - - name: Checkout seam-core + - name: Checkout seam uses: actions/checkout@v4 with: - path: seam-core + path: seam - name: Set up Go uses: actions/setup-go@v5 with: - go-version-file: seam-core/go.mod + go-version-file: seam/go.mod cache: true - name: Build - working-directory: seam-core + working-directory: seam run: make build - name: Lint - working-directory: seam-core + working-directory: seam run: | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest golangci-lint run --timeout 5m ./... - name: Unit tests - working-directory: seam-core + working-directory: seam run: make test-unit - name: Integration tests - working-directory: seam-core + working-directory: seam run: make test-integration - name: e2e tests - working-directory: seam-core + working-directory: seam run: | E2E_OUT=$(go test ./test/e2e/... -v 2>&1 || true) SKIPPED=$(echo "$E2E_OUT" | grep -c '\[SKIPPED\]\|S\[' || echo 0) diff --git a/CLAUDE.md b/CLAUDE.md index 241f00b..664cd36 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,15 +1,29 @@ -## seam-core: Operational Constraints -> Read ~/ontai/CLAUDE.md first. The constraints below extend the root constitutional document. +## seam: Operational Constraints + +Read `~/ontai/CLAUDE.md` first. The constraints below extend the root constitutional document. + +--- ### Schema authority -Primary: docs/seam-core-schema.md -Supporting: ~/ontai/domain-core/docs/domain-core-schema.md (DomainLineageIndex schema owner) + +Primary reference: `docs/seam-schema.md` + +`docs/seam-schema.md` is the authoritative field-level specification for every CRD type declared in this repository and for the shared library packages in `pkg/`. Read it in full before any CRD change or shared library change. Source files are the ground truth for field shapes; the schema doc reflects them and must be kept in sync. + +--- ### Invariants -SC-INV-001 -- seam-core owns all cross-operator CRD definitions under infrastructure.ontai.dev. The complete set of seam-core-owned types is: InfrastructureLineageIndex, InfrastructureRunnerConfig, InfrastructurePackReceipt, InfrastructureClusterPack, InfrastructurePackExecution, InfrastructurePackInstance, InfrastructurePackBuild, InfrastructureTalosCluster, DriftSignal, InfrastructurePolicy, InfrastructureProfile. Reconcilers for these CRDs live in the operator repos that own the domain logic, not in seam-core. -SC-INV-002 -- RunnerConfig and all cross-operator CRD type migrations to seam-core are complete as of Phase 2B (2026-04-25). No further governed migration sessions are required. The old API groups runner.ontai.dev and infra.ontai.dev are superseded. All new CRD work goes directly into seam-core under infrastructure.ontai.dev. -SC-INV-003 -- seam-core CRD manifests are installed before all operators. No operator reaches Running state on a cluster that has not applied the seam-core CRD bundle first. + +SC-INV-001 -- seam owns all cross-operator CRD definitions under seam.ontai.dev. The complete set of seam-owned types is: LineageRecord, RunnerConfig, DriftSignal, SeamMembership. Reconcilers for these CRDs live in the operator repos that own the domain logic, not in seam. + +SC-INV-002 -- All new CRD work goes directly into seam under seam.ontai.dev. No new type is declared outside this repository without an explicit Governor directive. + +SC-INV-003 -- seam CRD manifests are installed before all operators. No operator reaches Running state on a cluster that has not applied the seam CRD bundle first. + +--- ### Session protocol additions -Step 4a -- Read docs/seam-core-schema.md in full before any CRD or shared library change. -Step 4b -- Any change to the creation rationale vocabulary (the Go constant enumeration owned by seam-core) requires a PR and Platform Governor review. No operator may extend the enumeration unilaterally. (root Section 14 Decision 5) + +Step 4a -- Read `docs/seam-schema.md` in full before any CRD or shared library change. + +Step 4b -- Any change to the `CreationRationale` vocabulary (the Go constant enumeration in `pkg/lineage/rationale.go`) requires a PR and Platform Governor review. No operator may extend the enumeration unilaterally. (root Section 14 Decision 5) diff --git a/README.md b/README.md index ce2ecf3..fdb520f 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,82 @@ -# seam-core +# seam -**Seam Core - Cross-operator CRD definitions and shared library** -**API Group:** `infrastructure.ontai.dev` +API group: `seam.ontai.dev` ---- - -## What this repository is - -`seam-core` declares the cross-operator CRD types shared across the Seam platform -and owns the shared library packages imported by all operators and both Compiler -and Conductor binaries. - -No operator or binary in the Seam stack is deployed from this repository. -`seam-core` is a schema controller and library repository. +seam owns the cross-operator CRD type definitions and shared library packages for the ONT platform. No operator binary is deployed from this repository. seam installs its CRD manifests before all operators reach Running state on any cluster (SC-INV-003). --- -## CRDs +## CRD types -| Kind | API Group | Role | -|---|---|---| -| `InfrastructureLineageIndex` | `infrastructure.ontai.dev` | Sealed causal chain index for infrastructure declarations | -| `SeamMembership` | `infrastructure.ontai.dev` | Domain membership record linking a principal to a target cluster | +All four types are under `seam.ontai.dev/v1alpha1`. ---- - -## Shared packages +| Kind | Short name | Scope | Authoring principal | +|---|---|---|---| +| LineageRecord | lr | Namespaced | LineageController (controller-authored exclusively) | +| RunnerConfig | rc | Namespaced | platform operator (operator-generated, never human-authored) | +| DriftSignal | ds | Namespaced | conductor role=tenant | +| SeamMembership | sm | Namespaced | human / GitOps | -| Package | Role | -|---|---| -| `pkg/lineage` | `CreationRationale` enumeration and lineage record construction helpers | -| `pkg/conditions` | Shared condition type constants used across all Seam CRDs | -| `pkg/e2e` | End-to-end test helpers (not imported in production code) | +Schema reference: [docs/seam-schema.md](docs/seam-schema.md) --- -## InfrastructureLineageIndex +## Shared packages -`InfrastructureLineageIndex` is the concrete instantiation of the -`DomainLineageIndex` abstract pattern from `domain-core`. One instance is created -per root declaration, never one per derived object. This is the **Lineage Index -Pattern**. +### `pkg/lineage` -Key properties: -- `spec.rootBinding` is immutable after creation. The admission webhook rejects any - UPDATE that modifies this section. -- `spec.descendantRegistry` is monotonically growing. Entries are appended, never - modified or removed. -- Controller-authored exclusively. Writes from any principal other than the - designated controller service account are rejected at admission. +Defines the `SealedCausalChain` type embedded in every Seam-managed CRD spec. Defines `CreationRationale`, the compile-time controlled vocabulary for why a derived object was created. Provides `SetDescendantLabels` for operators to mark derived objects at creation time. No operator extends this vocabulary unilaterally -- new values require a seam PR and Platform Governor review. ---- +Import path: `github.com/ontai-dev/seam/pkg/lineage` -## SeamMembership +### `pkg/conditions` -`SeamMembership` records that a principal (identified by a Kubernetes service account -reference) has been admitted to a target cluster domain. The reconciler in `guardian` -owns this record. +Defines condition type and reason string constants for all ONT operators. This package is the single source of truth for every condition type and reason used across guardian, platform, dispatcher, and conductor. Operators import these constants rather than declaring their own strings. -Admission requires: -1. The referenced `RBACProfile` exists and has `provisioned=true`. -2. The `domainIdentityRef` in the `RBACProfile` matches the `principalRef`. +Import path: `github.com/ontai-dev/seam/pkg/conditions` --- -## CreationRationale vocabulary - -The `pkg/lineage` package exports the `CreationRationale` enumeration. This is the -compile-time controlled vocabulary for why a root declaration was created. All -operators and both binaries import this enumeration. New values require a Pull -Request to this repository and a Platform Governor review. +## Building -Current values: -- `ClusterProvision` -- `ClusterDecommission` -- `SecurityEnforcement` -- `PackExecution` -- `VirtualizationFulfillment` -- `ConductorAssignment` -- `VortexBinding` +Compile all packages: ---- +``` +make build +``` -## Building +Generate deep-copy methods and CRD manifests: -```sh -go build ./... +``` +make generate ``` -There is no deployable binary in this repository. The build target confirms that -all packages compile cleanly. +Requires `controller-gen` on PATH or at `~/go/bin/controller-gen`. --- ## Testing -```sh -go test ./... -``` +Unit tests: ---- +``` +make test-unit +``` -## Schema reference +End-to-end tests require `MGMT_KUBECONFIG` to be set. All e2e specs skip automatically when the variable is absent: -- `docs/seam-core-schema.md` - Full API contract and field definitions +``` +make e2e +``` --- ## Status -Alpha. Deployed and tested on management cluster (ccs-mgmt). -Tenant cluster onboarding is not yet verified end to end. -See [docs/seam-core-schema.md](./docs/seam-core-schema.md) -for current capability and known gaps. - -CRDs are deployed and reconciling on the live management cluster. -The schema specification is published at: -https://schema.ontai.dev/v1alpha1/ - -## Contributing - -Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull -request. Every new reconciliation behavior requires a written -specification and senior engineer sign-off before any code is -written. +Alpha. API group `seam.ontai.dev/v1alpha1`. No type in this group has graduated to beta. -File issues at https://github.com/ontai-dev/seam-core/issues. -For security issues contact security@ontai.dev directly. +Issues: https://github.com/ontai-dev/seam/issues --- -*seam-core - Seam Core Schema Controller and Shared Library* -*Apache License, Version 2.0* +seam - Seam Cross-Operator CRD Definitions and Shared Library / Apache License, Version 2.0 diff --git a/api/v1alpha1/clusterpack_types.go b/api/v1alpha1/clusterpack_types.go deleted file mode 100644 index 52c78d9..0000000 --- a/api/v1alpha1/clusterpack_types.go +++ /dev/null @@ -1,194 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/ontai-dev/seam-core/pkg/lineage" -) - -// InfrastructureLifecyclePolicy controls artifact retention behavior. -// wrapper-schema.md §3 ClusterPack spec.lifecyclePolicies. -type InfrastructureLifecyclePolicy struct { - // RetainOnDeletion controls whether the OCI artifact is retained when the - // ClusterPack CR is deleted. Default: true (artifact retained). - // +optional - // +kubebuilder:default=true - RetainOnDeletion bool `json:"retainOnDeletion,omitempty"` -} - -// InfrastructurePackRegistryRef identifies the OCI artifact for a ClusterPack. -type InfrastructurePackRegistryRef struct { - // URL is the OCI registry URL including image name. - URL string `json:"url"` - - // Digest is the OCI image digest (e.g., sha256:abc123...). Immutable after creation. - Digest string `json:"digest"` -} - -// InfrastructurePackExecutionStage is a single stage in the pack execution order. -type InfrastructurePackExecutionStage struct { - // Name is the stage name. Must be one of: rbac, storage, stateful, stateless. - // +kubebuilder:validation:Enum=rbac;storage;stateful;stateless - Name string `json:"name"` - - // Manifests is the list of manifest names to apply in this stage. - // +optional - Manifests []string `json:"manifests,omitempty"` -} - -// InfrastructurePackProvenance records build-time metadata for audit and traceability. -type InfrastructurePackProvenance struct { - // BuildID is the CI/CD build identifier that produced this pack. - // +optional - BuildID string `json:"buildID,omitempty"` - - // BuildTimestamp is when the pack artifact was produced. - // +optional - BuildTimestamp *metav1.Time `json:"buildTimestamp,omitempty"` - - // SourceRef is the git reference (commit SHA or tag) from which the pack was built. - // +optional - SourceRef string `json:"sourceRef,omitempty"` -} - -// InfrastructureClusterPackSpec defines the desired state of an InfrastructureClusterPack. -// All fields are immutable after creation. wrapper-schema.md §3. -type InfrastructureClusterPackSpec struct { - // Version is the semantic version of this pack. Immutable after creation. - Version string `json:"version"` - - // RegistryRef identifies the OCI artifact for this pack. Immutable after creation. - RegistryRef InfrastructurePackRegistryRef `json:"registryRef"` - - // Checksum is the content-addressed checksum of the full artifact manifest set. - // +optional - Checksum string `json:"checksum,omitempty"` - - // RBACDigest is the OCI digest of the RBAC layer of this ClusterPack artifact. - // Contains ServiceAccount, Role, ClusterRole, RoleBinding, ClusterRoleBinding manifests. - // +optional - RBACDigest string `json:"rbacDigest,omitempty"` - - // WorkloadDigest is the OCI digest of the workload layer of this ClusterPack artifact. - // Applied after guardian RBACProfile reaches provisioned=true. wrapper-schema.md §4. - // +optional - WorkloadDigest string `json:"workloadDigest,omitempty"` - - // ClusterScopedDigest is the OCI digest of the cluster-scoped non-RBAC layer. - // Applied after guardian RBAC intake and before workload manifests. wrapper-schema.md §4. - // +optional - ClusterScopedDigest string `json:"clusterScopedDigest,omitempty"` - - // SourceBuildRef is an opaque reference to the build that produced this pack. Informational. - // +optional - SourceBuildRef string `json:"sourceBuildRef,omitempty"` - - // ExecutionOrder defines the ordered stages in which pack manifests are applied. - // +optional - ExecutionOrder []InfrastructurePackExecutionStage `json:"executionOrder,omitempty"` - - // Provenance records build-time metadata for audit and traceability. - // +optional - Provenance *InfrastructurePackProvenance `json:"provenance,omitempty"` - - // BasePackName is the logical pack name shared across versions (e.g., "nginx-ingress"). - // +optional - BasePackName string `json:"basePackName,omitempty"` - - // TargetClusters is the list of cluster names to which this ClusterPack should be delivered. - // +optional - TargetClusters []string `json:"targetClusters,omitempty"` - - // ChartVersion is the version of the Helm chart used to compile this pack. - // +optional - ChartVersion string `json:"chartVersion,omitempty"` - - // ChartURL is the URL of the Helm chart repository used to compile this pack. - // +optional - ChartURL string `json:"chartURL,omitempty"` - - // ChartName is the name of the Helm chart used to compile this pack. - // +optional - ChartName string `json:"chartName,omitempty"` - - // HelmVersion is the version of the Helm SDK used to render this pack. - // +optional - HelmVersion string `json:"helmVersion,omitempty"` - - // ValuesFile is the path to the values file used during pack compilation. - // For Helm packs: the user-supplied values file merged with chart defaults at render time. - // For kustomize/raw packs: the overlay or patch file applied during the external build. - // Informational -- recorded so admins can trace which customization produced this artifact. - // +optional - ValuesFile string `json:"valuesFile,omitempty"` - - // LifecyclePolicies controls artifact retention behavior. - // +optional - LifecyclePolicies *InfrastructureLifecyclePolicy `json:"lifecyclePolicies,omitempty"` - - // Lineage is the sealed causal chain record for this root declaration. - // Authored once at object creation time and immutable thereafter. - // seam-core-schema.md §5, CLAUDE.md §14 Decision 1. - // +optional - Lineage *lineage.SealedCausalChain `json:"lineage,omitempty"` - - // RollbackToRevision instructs the wrapper to restore this ClusterPack to the - // artifact version deployed at POR revision N-1. When set, the ClusterPackReconciler - // reads PreviousClusterPackVersion/PreviousRBACDigest/PreviousWorkloadDigest from - // the current POR, patches spec.version and spec.*Digest to those values, removes - // the spec-checksum-snapshot annotation, and clears this field. Only one-step - // rollback (to revision N-1) is supported per invocation. Set to 0 to disable. - // Governor-controlled only. wrapper-schema.md §6.2. seam-core-schema.md §7.8. - // +optional - RollbackToRevision int64 `json:"rollbackToRevision,omitempty"` -} - -// InfrastructureClusterPackStatus is the observed state of an InfrastructureClusterPack. -type InfrastructureClusterPackStatus struct { - // Signed indicates whether the conductor signing loop has signed this pack. - // +optional - Signed bool `json:"signed,omitempty"` - - // PackSignature is the base64-encoded Ed25519 signature produced by the management cluster conductor. - // +optional - PackSignature string `json:"packSignature,omitempty"` - - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions is the list of status conditions for this ClusterPack. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=icp -// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=".spec.version" -// +kubebuilder:printcolumn:name="Signed",type=boolean,JSONPath=".status.signed" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructureClusterPack is the seam-core CRD for pack registration. -// Records an OCI artifact that has been compiled and is ready for runtime delivery. -// Spec is immutable after creation. wrapper-schema.md §3. -type InfrastructureClusterPack struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructureClusterPackSpec `json:"spec,omitempty"` - Status InfrastructureClusterPackStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructureClusterPackList contains a list of InfrastructureClusterPack. -type InfrastructureClusterPackList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructureClusterPack `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructureClusterPack{}, &InfrastructureClusterPackList{}) -} diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index 43c923b..81b6e70 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,10 +1,10 @@ -// Package v1alpha1 contains API types for the infrastructure.ontai.dev/v1alpha1 API group. +// Package v1alpha1 contains API types for the seam.ontai.dev/v1alpha1 API group. // // This package is the Kubernetes API contract for seam-core. All CRD types that // seam-core owns are registered here. Breaking changes require a version bump // and coordination with all operators that reference these types. // -// +groupName=infrastructure.ontai.dev +// +groupName=seam.ontai.dev // +kubebuilder:object:generate=true package v1alpha1 @@ -15,8 +15,8 @@ import ( var ( // GroupVersion is the group and version for all types in this package. - // API group: infrastructure.ontai.dev. INV-008 — this value is ground truth. - GroupVersion = schema.GroupVersion{Group: "infrastructure.ontai.dev", Version: "v1alpha1"} + // API group: seam.ontai.dev. INV-008 — this value is ground truth. MIGRATION-3.8. + GroupVersion = schema.GroupVersion{Group: "seam.ontai.dev", Version: "v1alpha1"} // SchemeBuilder is used to add Go types to the Kubernetes runtime scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1alpha1/infrastructurelineageindex_types.go b/api/v1alpha1/infrastructurelineageindex_types.go index 5954095..b74ca4e 100644 --- a/api/v1alpha1/infrastructurelineageindex_types.go +++ b/api/v1alpha1/infrastructurelineageindex_types.go @@ -1,285 +1,2 @@ -// Package v1alpha1 InfrastructureLineageIndex is the infrastructure domain -// instantiation of DomainLineageIndex from core.ontai.dev. See seam-core-schema.md -// §3 and domain-core-schema.md for the full design rationale. -// -// The InfrastructureLineageController (LineageController) manages the lifecycle -// of InfrastructureLineageIndex CRs. It is the sole principal permitted to create -// or update these instances — per CLAUDE.md §14 Decision 3. +// Tombstone: types migrated to lineagerecord_types.go (MIGRATION-3.8). package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - - "github.com/ontai-dev/seam-core/pkg/conditions" - "github.com/ontai-dev/seam-core/pkg/lineage" -) - -// ConditionTypeLineageSynced and ReasonLineageControllerAbsent are re-exported from -// pkg/conditions as the canonical source of truth. seam-core-schema.md §7 -// Declaration 5. Consumers should prefer importing pkg/conditions directly. Gap 31. -const ( - ConditionTypeLineageSynced = conditions.ConditionTypeLineageSynced - ReasonLineageControllerAbsent = conditions.ReasonLineageControllerAbsent -) - -// InfrastructureLineageIndexRootBinding records the root declaration that anchors -// this lineage index. All fields are immutable after admission. -type InfrastructureLineageIndexRootBinding struct { - // RootKind is the kind of the root declaration (e.g., TalosCluster, PackExecution). - RootKind string `json:"rootKind"` - - // RootName is the name of the root declaration. - RootName string `json:"rootName"` - - // RootNamespace is the namespace of the root declaration. - RootNamespace string `json:"rootNamespace"` - - // RootUID is the UID of the root declaration at time of index creation. - RootUID types.UID `json:"rootUID"` - - // RootObservedGeneration is the metadata.generation of the root declaration - // when this index was created. - RootObservedGeneration int64 `json:"rootObservedGeneration"` - - // DeclaringPrincipal is the identity of the human operator or automation - // principal that applied the root declaration CR. Stamped by the admission - // webhook via annotation infrastructure.ontai.dev/declaring-principal at - // CREATE time. Immutable after rootBinding is sealed. - // +optional - DeclaringPrincipal string `json:"declaringPrincipal,omitempty"` -} - -// DescendantEntry records a single derived object in the lineage index. -// Entries are appended monotonically. An entry is never modified or removed -// except by the retention enforcement loop (which removes stale entries after -// the retention window elapses). -type DescendantEntry struct { - // Group is the API group of the derived object (e.g., platform.ontai.dev). - Group string `json:"group"` - - // Version is the API version of the derived object (e.g., v1alpha1). - Version string `json:"version"` - - // Kind is the kind of the derived object. - Kind string `json:"kind"` - - // Name is the name of the derived object. - Name string `json:"name"` - - // Namespace is the namespace of the derived object. - Namespace string `json:"namespace"` - - // UID is the UID of the derived object. - UID types.UID `json:"uid"` - - // SeamOperator is the name of the Seam Operator that created this derived - // object (e.g., platform, guardian, wrapper, conductor). - SeamOperator string `json:"seamOperator"` - - // CreationRationale is the reason this derived object was created, drawn from - // the Seam Core controlled vocabulary (pkg/lineage.CreationRationale). - // - // +kubebuilder:validation:Enum=ClusterProvision;ClusterDecommission;SecurityEnforcement;PackExecution;VirtualizationFulfillment;ConductorAssignment;VortexBinding - CreationRationale lineage.CreationRationale `json:"creationRationale"` - - // RootGenerationAtCreation is the metadata.generation of the root declaration - // at the time this derived object was created. - RootGenerationAtCreation int64 `json:"rootGenerationAtCreation"` - - // CreatedAt is the time this descendant entry was appended to the registry. - // Used by the retention enforcement loop to determine when a stale entry - // (referenced object no longer exists) has exceeded its retention window. - // - // +optional - CreatedAt *metav1.Time `json:"createdAt,omitempty"` - - // ActorRef is the identity propagated from rootBinding.declaringPrincipal. - // Every derived object entry carries the initiating human principal from the - // root of its causal chain. Immutable. - // +optional - ActorRef string `json:"actorRef,omitempty"` -} - -// InfrastructurePolicyBindingStatus records the InfrastructurePolicy and -// InfrastructureProfile bound to the root declaration at last evaluation. -type InfrastructurePolicyBindingStatus struct { - // DomainPolicyRef is the name of the InfrastructurePolicy bound to the root - // declaration. - // +optional - DomainPolicyRef string `json:"domainPolicyRef,omitempty"` - - // DomainProfileRef is the name of the InfrastructureProfile bound to the - // root declaration. - // +optional - DomainProfileRef string `json:"domainProfileRef,omitempty"` - - // PolicyGenerationAtLastEvaluation is the metadata.generation of the bound - // InfrastructurePolicy at the time of the last policy evaluation cycle. - // +optional - PolicyGenerationAtLastEvaluation int64 `json:"policyGenerationAtLastEvaluation,omitempty"` - - // DriftDetected is true if the controller detected drift between the expected - // state derived from the InfrastructurePolicy and the observed state of - // derived objects at the last evaluation. - // +optional - DriftDetected bool `json:"driftDetected,omitempty"` -} - -// OutcomeType is the terminal lifecycle classification for a derived object. -// -// +kubebuilder:validation:Enum=Succeeded;Failed;Drifted;Superseded -type OutcomeType string - -const ( - OutcomeTypeSucceeded OutcomeType = "Succeeded" - OutcomeTypeFailed OutcomeType = "Failed" - OutcomeTypeDrifted OutcomeType = "Drifted" - OutcomeTypeSuperseded OutcomeType = "Superseded" -) - -// OutcomeEntry records the terminal outcome for a derived object tracked in -// DescendantRegistry. Entries are appended by LineageController when a terminal -// condition is observed. Entries are never modified or removed. -type OutcomeEntry struct { - // DerivedObjectUID is the UID matching a derived object entry in DescendantRegistry. - DerivedObjectUID types.UID `json:"derivedObjectUID"` - - // OutcomeType is the terminal classification of the derived object lifecycle. - OutcomeType OutcomeType `json:"outcomeType"` - - // OutcomeTimestamp is the time when the terminal condition was observed. - OutcomeTimestamp metav1.Time `json:"outcomeTimestamp"` - - // OutcomeRef is the name of the OperationResult ConfigMap or terminal condition - // reason that produced this outcome classification. Optional. - // +optional - OutcomeRef string `json:"outcomeRef,omitempty"` - - // OutcomeDetail is a brief human-readable summary of the outcome written by - // LineageController from the terminal condition message. Optional. - // +optional - OutcomeDetail string `json:"outcomeDetail,omitempty"` -} - -// LineageRetentionPolicy declares how stale descendant entries and the index itself -// are collected when the root declaration or its derived objects are deleted. -type LineageRetentionPolicy struct { - // DescendantRetentionDays is the number of days a stale descendant entry is - // retained after its referenced object is confirmed not-found in the API server. - // After this window elapses the LineageController prunes the entry from the - // DescendantRegistry. - // - // Defaults to 30. Minimum is 1. - // - // +optional - // +kubebuilder:default=30 - // +kubebuilder:validation:Minimum=1 - DescendantRetentionDays int32 `json:"descendantRetentionDays,omitempty"` - - // DeleteWithRoot controls whether this InfrastructureLineageIndex is garbage - // collected when its root declaration is deleted. When true the LineageController - // adds an ownerReference from the index to the root declaration, causing - // Kubernetes garbage collection to cascade deletion automatically. - // - // Defaults to true. - // - // +optional - // +kubebuilder:default=true - DeleteWithRoot bool `json:"deleteWithRoot"` -} - -// InfrastructureLineageIndexSpec is the spec of an InfrastructureLineageIndex. -type InfrastructureLineageIndexSpec struct { - // RootBinding records the root declaration that anchors this lineage index. - // Immutable after admission. The admission webhook rejects any update that - // modifies a field in this section. - RootBinding InfrastructureLineageIndexRootBinding `json:"rootBinding"` - - // DomainRef references the DomainLineageIndex at core.ontai.dev that - // this InfrastructureLineageIndex instantiates. This is the formal - // traceability link from the infrastructure domain to the domain core. - // Format: {name}.{group} — e.g. "infrastructure.core.ontai.dev" - // Set by the InfrastructureLineageController on creation. Validated by the - // admission webhook: when present, must equal "infrastructure.core.ontai.dev". - // +kubebuilder:validation:Optional - DomainRef string `json:"domainRef,omitempty"` - - // DescendantRegistry is the list of all objects derived from the root - // declaration. Appended monotonically as new derived objects are created. - // Entries are never modified or removed. - // +optional - DescendantRegistry []DescendantEntry `json:"descendantRegistry,omitempty"` - - // PolicyBindingStatus records the InfrastructurePolicy and InfrastructureProfile - // bound to the root declaration at last evaluation. - // +optional - PolicyBindingStatus *InfrastructurePolicyBindingStatus `json:"policyBindingStatus,omitempty"` - - // OutcomeRegistry is the append-only registry of terminal outcomes for derived - // objects tracked in DescendantRegistry. Entries are appended by LineageController - // when a terminal condition is observed on a tracked derived object. Entries are - // never modified or removed. An outcomeRegistry entry supersedes but does not - // replace its corresponding DescendantRegistry entry. - // +optional - OutcomeRegistry []OutcomeEntry `json:"outcomeRegistry,omitempty"` - - // RetentionPolicy declares garbage collection behavior for this index and its - // stale descendant entries. If absent, controller defaults apply - // (descendantRetentionDays=30, deleteWithRoot=true). - // - // +optional - RetentionPolicy *LineageRetentionPolicy `json:"retentionPolicy,omitempty"` -} - -// InfrastructureLineageIndexStatus is the observed state of an -// InfrastructureLineageIndex. -type InfrastructureLineageIndexStatus struct { - // ObservedGeneration is the last generation of the InfrastructureLineageIndex - // that the controller has processed. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions holds the standard Kubernetes condition array for this resource. - // +optional - // +listType=map - // +listMapKey=type - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=ili -// +kubebuilder:printcolumn:name="RootKind",type=string,JSONPath=`.spec.rootBinding.rootKind` -// +kubebuilder:printcolumn:name="RootName",type=string,JSONPath=`.spec.rootBinding.rootName` -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` - -// InfrastructureLineageIndex is the sealed causal chain index for a root -// declaration in the Seam infrastructure domain. It instantiates the abstract -// DomainLineageIndex schema from core.ontai.dev. -// -// One InfrastructureLineageIndex is created per root declaration by the -// InfrastructureLineageController. All derived objects carry a reference to their -// root's index; they do not carry their own index instances. -// Lineage Index Pattern — seam-core-schema.md §3. -// Controller-authored exclusively — CLAUDE.md §14 Decision 3. -type InfrastructureLineageIndex struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructureLineageIndexSpec `json:"spec,omitempty"` - Status InfrastructureLineageIndexStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructureLineageIndexList contains a list of InfrastructureLineageIndex. -type InfrastructureLineageIndexList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructureLineageIndex `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructureLineageIndex{}, &InfrastructureLineageIndexList{}) -} diff --git a/api/v1alpha1/lineagerecord_types.go b/api/v1alpha1/lineagerecord_types.go new file mode 100644 index 0000000..e292b51 --- /dev/null +++ b/api/v1alpha1/lineagerecord_types.go @@ -0,0 +1,248 @@ +// Package v1alpha1 LineageRecord is the infrastructure domain sealed causal chain +// index. Renamed from InfrastructureLineageIndex (MIGRATION-3.8). +// +// The LineageController manages the lifecycle of LineageRecord CRs. It is the +// sole principal permitted to create or update these instances per CLAUDE.md +// Decision 3. +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/ontai-dev/seam/pkg/conditions" + "github.com/ontai-dev/seam/pkg/lineage" +) + +// ConditionTypeLineageSynced and ReasonLineageControllerAbsent are re-exported from +// pkg/conditions as the canonical source of truth. seam-core-schema.md §7 +// Declaration 5. Consumers should prefer importing pkg/conditions directly. +const ( + ConditionTypeLineageSynced = conditions.ConditionTypeLineageSynced + ReasonLineageControllerAbsent = conditions.ReasonLineageControllerAbsent +) + +// LineageRecordRootBinding records the root declaration that anchors this +// lineage record. All fields are immutable after admission. +type LineageRecordRootBinding struct { + // RootKind is the kind of the root declaration (e.g., TalosCluster, PackDelivery). + RootKind string `json:"rootKind"` + + // RootName is the name of the root declaration. + RootName string `json:"rootName"` + + // RootNamespace is the namespace of the root declaration. + RootNamespace string `json:"rootNamespace"` + + // RootUID is the UID of the root declaration at time of record creation. + RootUID types.UID `json:"rootUID"` + + // RootObservedGeneration is the metadata.generation of the root declaration + // when this record was created. + RootObservedGeneration int64 `json:"rootObservedGeneration"` + + // DeclaringPrincipal is the identity of the human operator or automation + // principal that applied the root declaration CR. Stamped by the admission + // webhook via annotation infrastructure.ontai.dev/declaring-principal at + // CREATE time. Immutable after rootBinding is sealed. + // +optional + DeclaringPrincipal string `json:"declaringPrincipal,omitempty"` +} + +// DescendantEntry records a single derived object in the lineage record. +// Entries are appended monotonically. An entry is never modified or removed +// except by the retention enforcement loop. +type DescendantEntry struct { + // Group is the API group of the derived object (e.g., platform.ontai.dev). + Group string `json:"group"` + + // Version is the API version of the derived object (e.g., v1alpha1). + Version string `json:"version"` + + // Kind is the kind of the derived object. + Kind string `json:"kind"` + + // Name is the name of the derived object. + Name string `json:"name"` + + // Namespace is the namespace of the derived object. + Namespace string `json:"namespace"` + + // UID is the UID of the derived object. + UID types.UID `json:"uid"` + + // SeamOperator is the name of the Seam Operator that created this derived object. + SeamOperator string `json:"seamOperator"` + + // CreationRationale is the reason this derived object was created, drawn from + // the Seam Core controlled vocabulary (pkg/lineage.CreationRationale). + // + // +kubebuilder:validation:Enum=ClusterProvision;ClusterDecommission;SecurityEnforcement;PackExecution;VirtualizationFulfillment;ConductorAssignment;VortexBinding + CreationRationale lineage.CreationRationale `json:"creationRationale"` + + // RootGenerationAtCreation is the metadata.generation of the root declaration + // at the time this derived object was created. + RootGenerationAtCreation int64 `json:"rootGenerationAtCreation"` + + // CreatedAt is the time this descendant entry was appended to the registry. + // +optional + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + + // ActorRef is the identity propagated from rootBinding.declaringPrincipal. + // +optional + ActorRef string `json:"actorRef,omitempty"` +} + +// InfrastructurePolicyBindingStatus records the InfrastructurePolicy and +// InfrastructureProfile bound to the root declaration at last evaluation. +type InfrastructurePolicyBindingStatus struct { + // DomainPolicyRef is the name of the InfrastructurePolicy bound to the root declaration. + // +optional + DomainPolicyRef string `json:"domainPolicyRef,omitempty"` + + // DomainProfileRef is the name of the InfrastructureProfile bound to the root declaration. + // +optional + DomainProfileRef string `json:"domainProfileRef,omitempty"` + + // PolicyGenerationAtLastEvaluation is the metadata.generation of the bound + // InfrastructurePolicy at the time of the last policy evaluation cycle. + // +optional + PolicyGenerationAtLastEvaluation int64 `json:"policyGenerationAtLastEvaluation,omitempty"` + + // DriftDetected is true if drift was detected at the last evaluation. + // +optional + DriftDetected bool `json:"driftDetected,omitempty"` +} + +// OutcomeType is the terminal lifecycle classification for a derived object. +// +// +kubebuilder:validation:Enum=Succeeded;Failed;Drifted;Superseded +type OutcomeType string + +const ( + OutcomeTypeSucceeded OutcomeType = "Succeeded" + OutcomeTypeFailed OutcomeType = "Failed" + OutcomeTypeDrifted OutcomeType = "Drifted" + OutcomeTypeSuperseded OutcomeType = "Superseded" +) + +// OutcomeEntry records the terminal outcome for a derived object tracked in +// DescendantRegistry. Entries are appended by LineageController when a terminal +// condition is observed. Entries are never modified or removed. +type OutcomeEntry struct { + // DerivedObjectUID is the UID matching a derived object entry in DescendantRegistry. + DerivedObjectUID types.UID `json:"derivedObjectUID"` + + // OutcomeType is the terminal classification of the derived object lifecycle. + OutcomeType OutcomeType `json:"outcomeType"` + + // OutcomeTimestamp is the time when the terminal condition was observed. + OutcomeTimestamp metav1.Time `json:"outcomeTimestamp"` + + // OutcomeRef is the name of the OperationResult or terminal condition reason. + // +optional + OutcomeRef string `json:"outcomeRef,omitempty"` + + // OutcomeDetail is a brief human-readable summary of the outcome. + // +optional + OutcomeDetail string `json:"outcomeDetail,omitempty"` +} + +// LineageRetentionPolicy declares how stale descendant entries and the record +// itself are collected when the root declaration or its derived objects are deleted. +type LineageRetentionPolicy struct { + // DescendantRetentionDays is the number of days a stale descendant entry is + // retained after its referenced object is confirmed not-found. + // + // Defaults to 30. Minimum is 1. + // + // +optional + // +kubebuilder:default=30 + // +kubebuilder:validation:Minimum=1 + DescendantRetentionDays int32 `json:"descendantRetentionDays,omitempty"` + + // DeleteWithRoot controls whether this LineageRecord is garbage collected when + // its root declaration is deleted. + // + // Defaults to true. + // + // +optional + // +kubebuilder:default=true + DeleteWithRoot bool `json:"deleteWithRoot"` +} + +// LineageRecordSpec is the spec of a LineageRecord. +type LineageRecordSpec struct { + // RootBinding records the root declaration that anchors this lineage record. + // Immutable after admission. + RootBinding LineageRecordRootBinding `json:"rootBinding"` + + // DomainRef references the DomainLineageIndex at core.ontai.dev that + // this LineageRecord instantiates. + // +kubebuilder:validation:Optional + DomainRef string `json:"domainRef,omitempty"` + + // DescendantRegistry is the list of all objects derived from the root + // declaration. Appended monotonically. + // +optional + DescendantRegistry []DescendantEntry `json:"descendantRegistry,omitempty"` + + // PolicyBindingStatus records the bound policy and profile at last evaluation. + // +optional + PolicyBindingStatus *InfrastructurePolicyBindingStatus `json:"policyBindingStatus,omitempty"` + + // OutcomeRegistry is the append-only registry of terminal outcomes for derived + // objects tracked in DescendantRegistry. + // +optional + OutcomeRegistry []OutcomeEntry `json:"outcomeRegistry,omitempty"` + + // RetentionPolicy declares garbage collection behavior. + // +optional + RetentionPolicy *LineageRetentionPolicy `json:"retentionPolicy,omitempty"` +} + +// LineageRecordStatus is the observed state of a LineageRecord. +type LineageRecordStatus struct { + // ObservedGeneration is the last generation processed by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions holds the standard Kubernetes condition array. + // +optional + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Namespaced,shortName=lr +// +kubebuilder:printcolumn:name="RootKind",type=string,JSONPath=`.spec.rootBinding.rootKind` +// +kubebuilder:printcolumn:name="RootName",type=string,JSONPath=`.spec.rootBinding.rootName` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` + +// LineageRecord is the sealed causal chain index for a root declaration in the +// Seam infrastructure domain. Renamed from InfrastructureLineageIndex (MIGRATION-3.8). +// +// One LineageRecord is created per root declaration by the LineageController. +// Controller-authored exclusively -- CLAUDE.md Decision 3. +type LineageRecord struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec LineageRecordSpec `json:"spec,omitempty"` + Status LineageRecordStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// LineageRecordList contains a list of LineageRecord. +type LineageRecordList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LineageRecord `json:"items"` +} + +func init() { + SchemeBuilder.Register(&LineageRecord{}, &LineageRecordList{}) +} diff --git a/api/v1alpha1/packbuild_types.go b/api/v1alpha1/packbuild_types.go deleted file mode 100644 index 0734f66..0000000 --- a/api/v1alpha1/packbuild_types.go +++ /dev/null @@ -1,112 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// InfrastructurePackBuildCategory is the compilation category for a pack. -// +kubebuilder:validation:Enum=helm;kustomize;raw -type InfrastructurePackBuildCategory string - -const ( - InfrastructurePackBuildCategoryHelm InfrastructurePackBuildCategory = "helm" - InfrastructurePackBuildCategoryKustomize InfrastructurePackBuildCategory = "kustomize" - InfrastructurePackBuildCategoryRaw InfrastructurePackBuildCategory = "raw" -) - -// InfrastructurePackHelmSource describes a Helm chart source for pack compilation. -type InfrastructurePackHelmSource struct { - // URL is the full URL to the Helm chart tarball (.tgz). - URL string `json:"url"` - - // Chart is the chart name used for rendering context. - Chart string `json:"chart"` - - // Version is the chart version string. - Version string `json:"version"` - - // ValuesFile is the path to a YAML values file. Optional. - // +optional - ValuesFile string `json:"valuesFile,omitempty"` -} - -// InfrastructurePackKustomizeSource describes a Kustomize source for pack compilation. -type InfrastructurePackKustomizeSource struct { - // Path is the path to the kustomization root directory. - Path string `json:"path"` -} - -// InfrastructurePackRawSource describes a raw manifest source for pack compilation. -type InfrastructurePackRawSource struct { - // Path is the path to the directory containing raw YAML manifests. - Path string `json:"path"` -} - -// InfrastructurePackBuildSpec defines the desired state of an InfrastructurePackBuild. -// Compiler input specification. Read by the Compiler at compile time; never applied to a cluster as a CR. -// conductor-schema.md §7. -type InfrastructurePackBuildSpec struct { - // ComponentName is the name of the component being compiled. - ComponentName string `json:"componentName"` - - // Category declares the compilation category. Must be one of: helm, kustomize, raw. - // +kubebuilder:validation:Enum=helm;kustomize;raw - Category InfrastructurePackBuildCategory `json:"category"` - - // HelmSource describes the Helm chart source. Required when category=helm. - // +optional - HelmSource *InfrastructurePackHelmSource `json:"helmSource,omitempty"` - - // KustomizeSource describes the Kustomize source. Required when category=kustomize. - // +optional - KustomizeSource *InfrastructurePackKustomizeSource `json:"kustomizeSource,omitempty"` - - // RawSource describes the raw manifest source. Required when category=raw. - // +optional - RawSource *InfrastructurePackRawSource `json:"rawSource,omitempty"` - - // TargetClusters is the list of cluster names to which the compiled pack should be delivered. - // +optional - TargetClusters []string `json:"targetClusters,omitempty"` -} - -// InfrastructurePackBuildStatus is the observed state of an InfrastructurePackBuild. -type InfrastructurePackBuildStatus struct { - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions is the list of status conditions for this PackBuild. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=ipb -// +kubebuilder:printcolumn:name="Category",type=string,JSONPath=".spec.category" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructurePackBuild is the seam-core CRD for compiler input specification. -// Compiler reads this at compile time; never applied to a cluster as a live CR. -// conductor-schema.md §7. -type InfrastructurePackBuild struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructurePackBuildSpec `json:"spec,omitempty"` - Status InfrastructurePackBuildStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructurePackBuildList contains a list of InfrastructurePackBuild. -type InfrastructurePackBuildList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructurePackBuild `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructurePackBuild{}, &InfrastructurePackBuildList{}) -} diff --git a/api/v1alpha1/packexecution_types.go b/api/v1alpha1/packexecution_types.go deleted file mode 100644 index 2214c8f..0000000 --- a/api/v1alpha1/packexecution_types.go +++ /dev/null @@ -1,103 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/ontai-dev/seam-core/pkg/lineage" -) - -// InfrastructureClusterPackRef identifies a specific ClusterPack by name and version. -// wrapper-schema.md §3 PackExecution spec.clusterPackRef. -type InfrastructureClusterPackRef struct { - // Name is the name of the ClusterPack CR. - // +kubebuilder:validation:MinLength=1 - Name string `json:"name"` - - // Version is the expected version of the ClusterPack. Guards against name reuse. - // +kubebuilder:validation:MinLength=1 - Version string `json:"version"` -} - -// InfrastructurePackExecutionSpec defines the desired state of an InfrastructurePackExecution. -// wrapper-schema.md §3. -type InfrastructurePackExecutionSpec struct { - // ClusterPackRef identifies the ClusterPack to deploy. - ClusterPackRef InfrastructureClusterPackRef `json:"clusterPackRef"` - - // TargetClusterRef is the name of the target cluster to deliver the pack to. - TargetClusterRef string `json:"targetClusterRef"` - - // AdmissionProfileRef is the name of the RBACProfile governing this execution. - // +optional - AdmissionProfileRef string `json:"admissionProfileRef,omitempty"` - - // ChartVersion is the Helm chart version for this execution. Carried from ClusterPack. - // +optional - ChartVersion string `json:"chartVersion,omitempty"` - - // ChartURL is the Helm chart repository URL. Carried from ClusterPack. - // +optional - ChartURL string `json:"chartURL,omitempty"` - - // ChartName is the Helm chart name. Carried from ClusterPack. - // +optional - ChartName string `json:"chartName,omitempty"` - - // HelmVersion is the Helm SDK version used to render the pack. Carried from ClusterPack. - // +optional - HelmVersion string `json:"helmVersion,omitempty"` - - // Lineage is the sealed causal chain record for this root declaration. Immutable after creation. - // +optional - Lineage *lineage.SealedCausalChain `json:"lineage,omitempty"` -} - -// InfrastructurePackExecutionStatus is the observed state of an InfrastructurePackExecution. -type InfrastructurePackExecutionStatus struct { - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // JobName is the name of the pack-deploy Kueue Job submitted for this execution. - // +optional - JobName string `json:"jobName,omitempty"` - - // OperationResultRef is the name of the PackOperationResult CR written after - // successful pack-deploy Job completion. - // +optional - OperationResultRef string `json:"operationResultRef,omitempty"` - - // Conditions is the list of status conditions for this PackExecution. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=ipe -// +kubebuilder:printcolumn:name="Pack",type=string,JSONPath=".spec.clusterPackRef.name" -// +kubebuilder:printcolumn:name="Target",type=string,JSONPath=".spec.targetClusterRef" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructurePackExecution is the seam-core CRD for a runtime pack delivery request. -// wrapper-schema.md §3. -type InfrastructurePackExecution struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructurePackExecutionSpec `json:"spec,omitempty"` - Status InfrastructurePackExecutionStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructurePackExecutionList contains a list of InfrastructurePackExecution. -type InfrastructurePackExecutionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructurePackExecution `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructurePackExecution{}, &InfrastructurePackExecutionList{}) -} diff --git a/api/v1alpha1/packinstance_types.go b/api/v1alpha1/packinstance_types.go deleted file mode 100644 index b87e968..0000000 --- a/api/v1alpha1/packinstance_types.go +++ /dev/null @@ -1,148 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// InfrastructureDriftPolicy controls how dependency drift is handled. -// wrapper-schema.md §3 PackInstance spec.dependencyPolicy.onDrift. -type InfrastructureDriftPolicy string - -const ( - // InfrastructureDriftPolicyBlock stops all further pack ops on this cluster - // when a dependency PackInstance reports Drifted=True. - InfrastructureDriftPolicyBlock InfrastructureDriftPolicy = "Block" - - // InfrastructureDriftPolicyWarn emits a warning event when a dependency - // PackInstance reports Drifted=True but does not block further pack ops. - InfrastructureDriftPolicyWarn InfrastructureDriftPolicy = "Warn" - - // InfrastructureDriftPolicyIgnore takes no action when a dependency - // PackInstance reports Drifted=True. - InfrastructureDriftPolicyIgnore InfrastructureDriftPolicy = "Ignore" -) - -// InfrastructureDependencyPolicy defines behavior when a dependency PackInstance reports drift. -// wrapper-schema.md §3 PackInstance spec.dependencyPolicy. -type InfrastructureDependencyPolicy struct { - // OnDrift controls how this PackInstance responds when a declared dependency - // PackInstance reports Drifted=True. - // +kubebuilder:validation:Enum=Block;Warn;Ignore - // +kubebuilder:default=Warn - OnDrift InfrastructureDriftPolicy `json:"onDrift,omitempty"` -} - -// InfrastructureDeployedResourceRef records a single Kubernetes resource applied -// by the pack-deploy job. Used by the PackInstance deletion handler to clean up -// deployed workload when the ClusterPack is deleted. wrapper-schema.md §3. -type InfrastructureDeployedResourceRef struct { - // APIVersion is the Kubernetes apiVersion (e.g., apps/v1, v1). - APIVersion string `json:"apiVersion"` - - // Kind is the Kubernetes resource Kind (e.g., Deployment, Namespace). - Kind string `json:"kind"` - - // Namespace is the resource namespace. Empty for cluster-scoped resources. - // +optional - Namespace string `json:"namespace,omitempty"` - - // Name is the resource name. - Name string `json:"name"` -} - -// InfrastructurePackInstanceSpec defines the desired state of an InfrastructurePackInstance. -// wrapper-schema.md §3. -type InfrastructurePackInstanceSpec struct { - // ClusterPackRef is the name of the ClusterPack CR this instance tracks. - ClusterPackRef string `json:"clusterPackRef"` - - // Version is the pack version delivered to the target cluster. - Version string `json:"version"` - - // TargetClusterRef is the name of the target cluster this instance is installed on. - TargetClusterRef string `json:"targetClusterRef"` - - // DependsOn is the list of pack base names that must be Delivered before this instance. - // +optional - DependsOn []string `json:"dependsOn,omitempty"` - - // DependencyPolicy defines behavior when a dependency reports drift. - // +optional - DependencyPolicy *InfrastructureDependencyPolicy `json:"dependencyPolicy,omitempty"` - - // ChartVersion is the Helm chart version for this instance. Carried from ClusterPack. - // +optional - ChartVersion string `json:"chartVersion,omitempty"` - - // ChartURL is the Helm chart repository URL. Carried from ClusterPack. - // +optional - ChartURL string `json:"chartURL,omitempty"` - - // ChartName is the Helm chart name. Carried from ClusterPack. - // +optional - ChartName string `json:"chartName,omitempty"` - - // HelmVersion is the Helm SDK version used to render the pack. Carried from ClusterPack. - // +optional - HelmVersion string `json:"helmVersion,omitempty"` -} - -// InfrastructurePackInstanceStatus is the observed state of an InfrastructurePackInstance. -type InfrastructurePackInstanceStatus struct { - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // DeliveredAt records when the pack was most recently confirmed delivered. - // +optional - DeliveredAt *metav1.Time `json:"deliveredAt,omitempty"` - - // DriftSummary is a human-readable summary of the current drift state. - // +optional - DriftSummary string `json:"driftSummary,omitempty"` - - // UpgradeDirection records the version transition direction for the last deployment. - // Initial: first deployment. Upgrade: newer version. Rollback: older version. Redeploy: same version. - // +optional - // +kubebuilder:validation:Enum=Initial;Upgrade;Rollback;Redeploy - UpgradeDirection string `json:"upgradeDirection,omitempty"` - - // DeployedResources is the list of Kubernetes resources applied by the pack-deploy job. - // Used by the PackInstance deletion handler for cleanup. - // +optional - DeployedResources []InfrastructureDeployedResourceRef `json:"deployedResources,omitempty"` - - // Conditions is the list of status conditions for this PackInstance. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=ipi -// +kubebuilder:printcolumn:name="Pack",type=string,JSONPath=".spec.clusterPackRef" -// +kubebuilder:printcolumn:name="Target",type=string,JSONPath=".spec.targetClusterRef" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructurePackInstance is the seam-core CRD recording the delivered state of a pack on a cluster. -// wrapper-schema.md §3. -type InfrastructurePackInstance struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructurePackInstanceSpec `json:"spec,omitempty"` - Status InfrastructurePackInstanceStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructurePackInstanceList contains a list of InfrastructurePackInstance. -type InfrastructurePackInstanceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructurePackInstance `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructurePackInstance{}, &InfrastructurePackInstanceList{}) -} diff --git a/api/v1alpha1/packoperationresult_types.go b/api/v1alpha1/packoperationresult_types.go deleted file mode 100644 index 453b212..0000000 --- a/api/v1alpha1/packoperationresult_types.go +++ /dev/null @@ -1,235 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// PackOperationResultStatus constants mirror runnerlib.ResultStatus. Defined -// here to avoid importing conductor into seam-core (would create a cycle). - -// PackResultStatus is the terminal status of a pack-deploy capability execution. -// +kubebuilder:validation:Enum=Succeeded;Failed -type PackResultStatus string - -const ( - PackResultSucceeded PackResultStatus = "Succeeded" - PackResultFailed PackResultStatus = "Failed" -) - -// PackUpgradeDirection records the version transition direction for a PackInstance. -// +kubebuilder:validation:Enum=Initial;Upgrade;Rollback;Redeploy -type PackUpgradeDirection string - -const ( - PackUpgradeDirectionInitial PackUpgradeDirection = "Initial" - PackUpgradeDirectionUpgrade PackUpgradeDirection = "Upgrade" - PackUpgradeDirectionRollback PackUpgradeDirection = "Rollback" - PackUpgradeDirectionRedeploy PackUpgradeDirection = "Redeploy" -) - -// PackOperationDeployedResource records a single Kubernetes resource applied -// during a pack-deploy execution. -type PackOperationDeployedResource struct { - // APIVersion is the Kubernetes apiVersion (e.g., apps/v1, v1). - APIVersion string `json:"apiVersion"` - - // Kind is the Kubernetes resource Kind (e.g., Deployment, Namespace). - Kind string `json:"kind"` - - // Namespace is the resource namespace. Empty for cluster-scoped resources. - // +optional - Namespace string `json:"namespace,omitempty"` - - // Name is the resource name. - Name string `json:"name"` -} - -// PackOperationArtifact is a structured reference to an artifact produced -// by a pack-deploy execution. Never contains raw artifact content. -type PackOperationArtifact struct { - // Name is a logical identifier for this artifact. - Name string `json:"name"` - - // Kind declares the artifact type. One of: ConfigMap, Secret, OCIImage, S3Object. - // +kubebuilder:validation:Enum=ConfigMap;Secret;OCIImage;S3Object - Kind string `json:"kind"` - - // Reference is the fully qualified reference for the artifact kind. - Reference string `json:"reference"` - - // Checksum is the content-addressed checksum. Format: sha256:. - // +optional - Checksum string `json:"checksum,omitempty"` -} - -// PackOperationStepResult is the execution result for one step within a -// multi-step capability. -type PackOperationStepResult struct { - // Name is the step identifier within the capability. - Name string `json:"name"` - - // Status is the terminal status of this step. - // +kubebuilder:validation:Enum=Succeeded;Failed - Status PackResultStatus `json:"status"` - - // StartedAt is the time this step began execution. - // +optional - StartedAt *metav1.Time `json:"startedAt,omitempty"` - - // CompletedAt is the time this step finished execution. - // +optional - CompletedAt *metav1.Time `json:"completedAt,omitempty"` - - // Message provides additional context about the step outcome. - // +optional - Message string `json:"message,omitempty"` -} - -// PackOperationFailureReason is a structured failure description. -type PackOperationFailureReason struct { - // Category classifies the failure domain. - // +kubebuilder:validation:Enum=ValidationFailure;CapabilityUnavailable;ExecutionFailure;ExternalDependencyFailure;InvariantViolation;LicenseViolation;StorageUnavailable - Category string `json:"category"` - - // Reason is a human-readable description of the specific failure. - Reason string `json:"reason"` - - // FailedStep is the name of the step that failed. Empty for single-step capabilities. - // +optional - FailedStep string `json:"failedStep,omitempty"` -} - -// PackOperationResultSpec is the complete result document written by the -// Conductor execute-mode Job before exit. Written by conductor; read by wrapper. -// seam-core-schema.md §8, Decision 11. -type PackOperationResultSpec struct { - // Revision is the monotonically increasing revision counter for this pack operation - // sequence. Incremented each time a new result supersedes the previous one. The - // single-active-revision pattern ensures exactly one PackOperationResult exists per - // ClusterPack operation sequence at any time. - Revision int64 `json:"revision"` - - // PreviousRevisionRef is the name of the PackOperationResult CR that was deleted when - // this revision was written. Enables chain reconstruction for the full operation history. - // Absent for revision 1 (no predecessor). - // +optional - PreviousRevisionRef string `json:"previousRevisionRef,omitempty"` - - // TalosClusterOperationResultRef is reserved for future cross-reference to a - // TalosCluster-scoped OperationResult. Stub field; not populated by any current - // controller. - // +optional - TalosClusterOperationResultRef string `json:"talosClusterOperationResultRef,omitempty"` - - // PackExecutionRef is the name of the PackExecution CR that triggered this operation. - // +optional - PackExecutionRef string `json:"packExecutionRef,omitempty"` - - // ClusterPackRef is the name of the ClusterPack CR that was deployed. - // +optional - ClusterPackRef string `json:"clusterPackRef,omitempty"` - - // TargetClusterRef is the name of the target cluster this operation ran against. - // +optional - TargetClusterRef string `json:"targetClusterRef,omitempty"` - - // Capability is the name of the Conductor capability that produced this result. - Capability string `json:"capability"` - - // Phase identifies the RunnerConfig phase this result belongs to. - // +optional - Phase string `json:"phase,omitempty"` - - // Status is the terminal status of the capability execution. - // +kubebuilder:validation:Enum=Succeeded;Failed - Status PackResultStatus `json:"status"` - - // StartedAt is the time the capability execution began. - // +optional - StartedAt *metav1.Time `json:"startedAt,omitempty"` - - // CompletedAt is the time the capability execution finished. - // +optional - CompletedAt *metav1.Time `json:"completedAt,omitempty"` - - // FailureReason is populated when Status is Failed. Nil on success. - // +optional - FailureReason *PackOperationFailureReason `json:"failureReason,omitempty"` - - // DeployedResources is the list of Kubernetes resources applied during this - // execution. Populated by pack-deploy on success. Used by PackInstanceReconciler - // for deletion cleanup. - // +optional - DeployedResources []PackOperationDeployedResource `json:"deployedResources,omitempty"` - - // Artifacts is the list of artifacts produced by this execution. - // +optional - Artifacts []PackOperationArtifact `json:"artifacts,omitempty"` - - // Steps contains individual step results for multi-step capabilities. - // +optional - Steps []PackOperationStepResult `json:"steps,omitempty"` - - // ClusterPackVersion is the ClusterPack spec.version deployed in this operation. - // Populated by the Conductor executor at write time. Rollback anchor: the wrapper - // reads this field from the target POR revision to restore when spec.rollbackToRevision - // is set. Superseded PORs are retained with ontai.dev/superseded=true label to - // enable N-step rollback. seam-core-schema.md §7.8. - // +optional - ClusterPackVersion string `json:"clusterPackVersion,omitempty"` - - // RBACDigest is the OCI digest of the RBAC layer deployed in this operation. - // Copied from ClusterPack.spec.rbacDigest at deploy time. Rollback anchor. - // +optional - RBACDigest string `json:"rbacDigest,omitempty"` - - // WorkloadDigest is the OCI digest of the workload layer deployed in this operation. - // Copied from ClusterPack.spec.workloadDigest at deploy time. Rollback anchor. - // +optional - WorkloadDigest string `json:"workloadDigest,omitempty"` - -} - -// PackOperationResultStatus is the observed state of a PackOperationResult. -// Currently empty; reserved for future controller-set conditions. -type PackOperationResultStatus struct { - // ObservedGeneration is the last generation processed by any consumer. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=por -// +kubebuilder:printcolumn:name="Capability",type=string,JSONPath=`.spec.capability` -// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.spec.status` -// +kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=`.spec.targetClusterRef` -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` - -// PackOperationResult is the immutable result record written by the Conductor -// execute-mode Job after a pack-deploy capability completes. It replaces the -// ConfigMap output channel, providing a versioned, richly-typed CR that the -// wrapper PackExecutionReconciler reads to advance PackExecution status and -// that the lineagesink can consume as additional data. One PackOperationResult -// per PackExecution, created in namespace seam-tenant-{clusterName}. -// seam-core-schema.md §8, Decision 11. -type PackOperationResult struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackOperationResultSpec `json:"spec,omitempty"` - Status PackOperationResultStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// PackOperationResultList contains a list of PackOperationResult. -type PackOperationResultList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PackOperationResult `json:"items"` -} - -func init() { - SchemeBuilder.Register(&PackOperationResult{}, &PackOperationResultList{}) -} diff --git a/api/v1alpha1/packreceipt_types.go b/api/v1alpha1/packreceipt_types.go deleted file mode 100644 index 81671f6..0000000 --- a/api/v1alpha1/packreceipt_types.go +++ /dev/null @@ -1,132 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// PackReceiptDeployedResource records a single Kubernetes resource that was applied -// to the tenant cluster as part of a pack-deploy Job. Used by conductor role=tenant -// to detect drift between declared and actual cluster state. -// CLUSTERPACK-BL-VERSION-CLEANUP. conductor-schema.md. -type PackReceiptDeployedResource struct { - // APIVersion is the full API version string (e.g., "apps/v1"). - APIVersion string `json:"apiVersion"` - - // Kind is the resource kind (e.g., "Deployment"). - Kind string `json:"kind"` - - // Namespace is the namespace the resource was applied to. Empty for cluster-scoped resources. - // +optional - Namespace string `json:"namespace,omitempty"` - - // Name is the resource name. - Name string `json:"name"` -} - -// InfrastructurePackReceiptSpec defines the desired state of an InfrastructurePackReceipt. -// Written by the packinstance pull loop on the tenant cluster conductor after -// Ed25519 signature verification. INV-026. conductor-schema.md. -type InfrastructurePackReceiptSpec struct { - // PackInstanceRef is the name of the PackInstance CR this receipt acknowledges. - // +optional - PackInstanceRef string `json:"packInstanceRef,omitempty"` - - // SignatureRef is the name of the signed artifact Secret on the management cluster - // (seam-pack-signed-{cluster}-{packInstance}) from which this receipt was derived. - // +optional - SignatureRef string `json:"signatureRef,omitempty"` - - // ClusterPackRef is the name of the ClusterPack CR this receipt acknowledges. - ClusterPackRef string `json:"clusterPackRef"` - - // TargetClusterRef is the name of the cluster this receipt was generated on. - TargetClusterRef string `json:"targetClusterRef"` - - // RBACDigest is the OCI digest of the RBAC layer. Carried from ClusterPack for audit. - // +optional - RBACDigest string `json:"rbacDigest,omitempty"` - - // WorkloadDigest is the OCI digest of the workload layer. Carried from ClusterPack. - // +optional - WorkloadDigest string `json:"workloadDigest,omitempty"` - - // ChartVersion is the Helm chart version. Carried from ClusterPack. - // +optional - ChartVersion string `json:"chartVersion,omitempty"` - - // ChartURL is the Helm chart repository URL. Carried from ClusterPack. - // +optional - ChartURL string `json:"chartURL,omitempty"` - - // ChartName is the Helm chart name. Carried from ClusterPack. - // +optional - ChartName string `json:"chartName,omitempty"` - - // HelmVersion is the Helm SDK version. Carried from ClusterPack. - // +optional - HelmVersion string `json:"helmVersion,omitempty"` - - // DeployedResources is the inventory of Kubernetes resources applied to the tenant cluster - // during the pack-deploy Job. Conductor role=tenant uses this list to detect drift by - // verifying each resource still exists with the expected state. - // CLUSTERPACK-BL-VERSION-CLEANUP, conductor-schema.md. - // +optional - DeployedResources []PackReceiptDeployedResource `json:"deployedResources,omitempty"` -} - -// InfrastructurePackReceiptStatus is the observed state of an InfrastructurePackReceipt. -// Written by the packinstance pull loop after signature verification. INV-026. -type InfrastructurePackReceiptStatus struct { - // Verified indicates whether the Ed25519 signature on the PackInstance artifact - // was successfully verified against the management cluster's public key. INV-026. - // +optional - Verified bool `json:"verified,omitempty"` - - // Signature is the base64-encoded Ed25519 signature from the signed artifact Secret. - // Stored for auditability and idempotency checking. INV-026. - // +optional - Signature string `json:"signature,omitempty"` - - // VerificationFailedReason is set when Verified=false and describes the - // specific verification failure (e.g., "Ed25519 signature verification failed (INV-026)"). - // +optional - VerificationFailedReason string `json:"verificationFailedReason,omitempty"` - - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions is the list of status conditions for this PackReceipt. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=ipr -// +kubebuilder:printcolumn:name="Pack",type=string,JSONPath=".spec.clusterPackRef" -// +kubebuilder:printcolumn:name="Verified",type=boolean,JSONPath=".status.verified" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructurePackReceipt is the seam-core CRD for pack delivery acknowledgement on a tenant cluster. -// Written by conductor agent after signature verification. INV-026. -type InfrastructurePackReceipt struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructurePackReceiptSpec `json:"spec,omitempty"` - Status InfrastructurePackReceiptStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructurePackReceiptList contains a list of InfrastructurePackReceipt. -type InfrastructurePackReceiptList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructurePackReceipt `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructurePackReceipt{}, &InfrastructurePackReceiptList{}) -} diff --git a/api/v1alpha1/runnerconfig_types.go b/api/v1alpha1/runnerconfig_types.go index 0a47df7..ab79b4c 100644 --- a/api/v1alpha1/runnerconfig_types.go +++ b/api/v1alpha1/runnerconfig_types.go @@ -101,10 +101,10 @@ type RunnerConfigStepResult struct { Message string `json:"message,omitempty"` } -// InfrastructureRunnerConfigSpec is the operator-generated operational contract for a +// RunnerConfigSpec is the operator-generated operational contract for a // specific cluster. Generated at runtime by platform using the runner shared library. // Never human-authored. INV-009, INV-010. conductor-schema.md. -type InfrastructureRunnerConfigSpec struct { +type RunnerConfigSpec struct { // ClusterRef is the name of the TalosCluster this RunnerConfig is authoritative for. ClusterRef string `json:"clusterRef"` @@ -137,9 +137,9 @@ type InfrastructureRunnerConfigSpec struct { SelfOperation bool `json:"selfOperation,omitempty"` } -// InfrastructureRunnerConfigStatus is written exclusively by the Conductor agent leader. +// RunnerConfigStatus is written exclusively by the Conductor agent leader. // CR-INV-006. -type InfrastructureRunnerConfigStatus struct { +type RunnerConfigStatus struct { // Capabilities is the self-declared capability manifest emitted by the Conductor agent on startup. // CR-INV-005. // +optional @@ -176,30 +176,30 @@ type InfrastructureRunnerConfigStatus struct { // +kubebuilder:object:root=true // +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=irc +// +kubebuilder:resource:scope=Namespaced,shortName=rc // +kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=".spec.clusterRef" // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" -// InfrastructureRunnerConfig is the seam-core CRD for Conductor agent runtime configuration. +// RunnerConfig is the seam-core CRD for Conductor agent runtime configuration. // Owned by seam-core; authored exclusively by the platform operator. INV-009. // conductor-schema.md. -type InfrastructureRunnerConfig struct { +type RunnerConfig struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec InfrastructureRunnerConfigSpec `json:"spec,omitempty"` - Status InfrastructureRunnerConfigStatus `json:"status,omitempty"` + Spec RunnerConfigSpec `json:"spec,omitempty"` + Status RunnerConfigStatus `json:"status,omitempty"` } // +kubebuilder:object:root=true -// InfrastructureRunnerConfigList contains a list of InfrastructureRunnerConfig. -type InfrastructureRunnerConfigList struct { +// RunnerConfigList contains a list of RunnerConfig. +type RunnerConfigList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructureRunnerConfig `json:"items"` + Items []RunnerConfig `json:"items"` } func init() { - SchemeBuilder.Register(&InfrastructureRunnerConfig{}, &InfrastructureRunnerConfigList{}) + SchemeBuilder.Register(&RunnerConfig{}, &RunnerConfigList{}) } diff --git a/api/v1alpha1/taloscluster_types.go b/api/v1alpha1/taloscluster_types.go deleted file mode 100644 index f0aeff2..0000000 --- a/api/v1alpha1/taloscluster_types.go +++ /dev/null @@ -1,288 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/ontai-dev/seam-core/pkg/lineage" -) - -// InfrastructureTalosClusterMode declares whether the cluster is bootstrapped or imported. -// +kubebuilder:validation:Enum=bootstrap;import -type InfrastructureTalosClusterMode string - -const ( - InfrastructureTalosClusterModeBootstrap InfrastructureTalosClusterMode = "bootstrap" - InfrastructureTalosClusterModeImport InfrastructureTalosClusterMode = "import" -) - -// InfrastructureTalosClusterRole declares the role of the cluster in the Seam topology. -// Mandatory on mode=import. -// +kubebuilder:validation:Enum=management;tenant -type InfrastructureTalosClusterRole string - -const ( - InfrastructureTalosClusterRoleManagement InfrastructureTalosClusterRole = "management" - InfrastructureTalosClusterRoleTenant InfrastructureTalosClusterRole = "tenant" -) - -// InfrastructureTalosClusterOrigin records how the cluster came to exist. -// +kubebuilder:validation:Enum=bootstrapped;imported -type InfrastructureTalosClusterOrigin string - -const ( - InfrastructureTalosClusterOriginBootstrapped InfrastructureTalosClusterOrigin = "bootstrapped" - InfrastructureTalosClusterOriginImported InfrastructureTalosClusterOrigin = "imported" -) - -// InfrastructureProvider declares the infrastructure provider backing a TalosCluster. -// +kubebuilder:validation:Enum=native;capi;screen -type InfrastructureProvider string - -const ( - // InfrastructureProviderNative is the default provider. The operator manages - // cluster lifecycle directly: management cluster via a bootstrap Conductor Job - // (capi.enabled=false), target clusters via the CAPI path (capi.enabled=true). - InfrastructureProviderNative InfrastructureProvider = "native" - - // InfrastructureProviderCAPI is an explicit alias for the CAPI-backed target - // cluster path. Functionally equivalent to InfrastructureProviderNative when - // spec.capi.enabled=true. Reserved for future explicit-provider semantics. - InfrastructureProviderCAPI InfrastructureProvider = "capi" - - // InfrastructureProviderScreen is reserved for the future Screen operator (INV-021). - // No implementation until a Governor-approved ADR. When observed, the reconciler - // sets ScreenProviderNotImplemented=True and halts. - InfrastructureProviderScreen InfrastructureProvider = "screen" -) - -// InfrastructureLocalObjectRef is a reference to a Kubernetes object by name and namespace. -type InfrastructureLocalObjectRef struct { - // Name is the object name. - Name string `json:"name"` - - // Namespace is the object namespace. May be empty for cluster-scoped objects. - // +optional - Namespace string `json:"namespace,omitempty"` -} - -// InfrastructureCAPICiliumPackRef is a reference to the cluster-specific Cilium ClusterPack. -// The pack is pre-compiled on the workstation and is cluster-endpoint-specific. -// platform-schema.md §2.3. -type InfrastructureCAPICiliumPackRef struct { - // Name is the ClusterPack CR name for the Cilium pack. - Name string `json:"name"` - - // Version is the ClusterPack version string. - Version string `json:"version"` -} - -// InfrastructureCAPIWorkerPool declares a worker node pool for a CAPI-managed target cluster. -// Each pool maps to a MachineDeployment + SeamInfrastructureMachineTemplate. -type InfrastructureCAPIWorkerPool struct { - // Name is the pool identifier. Used as the MachineDeployment name suffix. - Name string `json:"name"` - - // Replicas is the desired number of worker nodes in this pool. - // +optional - Replicas int32 `json:"replicas,omitempty"` - - // SeamInfrastructureMachineNames lists the SeamInfrastructureMachine CR names - // pre-provisioned for this pool. One per node. - // +optional - SeamInfrastructureMachineNames []string `json:"seamInfrastructureMachineNames,omitempty"` -} - -// InfrastructureCAPIControlPlaneConfig declares the control plane configuration for a CAPI -// target cluster. -type InfrastructureCAPIControlPlaneConfig struct { - // Replicas is the desired number of control plane nodes. - // +optional - Replicas int32 `json:"replicas,omitempty"` -} - -// InfrastructureCAPIConfig holds CAPI integration settings for a target cluster. -// Only consulted when capi.enabled=true. platform-schema.md §5. -type InfrastructureCAPIConfig struct { - // Enabled determines whether this TalosCluster uses the CAPI path. - // True for all target clusters. False for the management cluster. - Enabled bool `json:"enabled"` - - // TalosVersion is the Talos version to use for TalosConfigTemplate and - // CABPT machineconfig generation. Required when Enabled=true. - // +optional - TalosVersion string `json:"talosVersion,omitempty"` - - // KubernetesVersion is the Kubernetes version for TalosControlPlane. - // Required when Enabled=true. - // +optional - KubernetesVersion string `json:"kubernetesVersion,omitempty"` - - // ControlPlane holds control plane configuration. Required when Enabled=true. - // +optional - ControlPlane *InfrastructureCAPIControlPlaneConfig `json:"controlPlane,omitempty"` - - // Workers is the list of worker node pools. - // +optional - Workers []InfrastructureCAPIWorkerPool `json:"workers,omitempty"` - - // CiliumPackRef references the cluster-specific Cilium ClusterPack. - // Applied as the first pack after the CAPI cluster reaches Running state. - // Required when Enabled=true. platform-schema.md §2.3. - // +optional - CiliumPackRef *InfrastructureCAPICiliumPackRef `json:"ciliumPackRef,omitempty"` -} - -// InfrastructureTalosClusterSpec is the declared desired state of an InfrastructureTalosCluster. -// platform-schema.md §4. -// +kubebuilder:validation:XValidation:rule="self.mode != 'import' || (has(self.role) && self.role != '')",message="role is required when mode is import" -type InfrastructureTalosClusterSpec struct { - // Mode declares whether this cluster is bootstrapped from scratch or imported. - // +kubebuilder:validation:Enum=bootstrap;import - Mode InfrastructureTalosClusterMode `json:"mode"` - - // Role declares the cluster role in the Seam topology. Mandatory on mode=import. - // +kubebuilder:validation:Enum=management;tenant - // +optional - Role InfrastructureTalosClusterRole `json:"role,omitempty"` - - // TalosVersion is the Talos OS version for this cluster. Used by Conductor to select - // a compatible runner image. INV-012. - // +optional - TalosVersion string `json:"talosVersion,omitempty"` - - // KubernetesVersion is the Kubernetes version for this cluster. Set from - // bootstrap.kubernetesVersion or derived automatically from the Talos version - // support matrix when not explicitly provided. When spec.versionUpgrade=true, - // setting this field drives an UpgradeTypeKubernetes UpgradePolicy. Setting - // both talosVersion and kubernetesVersion drives an UpgradeTypeStack policy - // (sequential Talos then Kubernetes upgrade via a single Conductor Job). - // +optional - KubernetesVersion string `json:"kubernetesVersion,omitempty"` - - // VersionUpgrade, when set to true, triggers a cluster-level rolling upgrade. - // The upgrade type is derived from which version fields are set: - // - talosVersion only: UpgradeTypeTalos (Talos OS upgrade) - // - kubernetesVersion only: UpgradeTypeKubernetes (k8s upgrade, Talos unchanged) - // - both: UpgradeTypeStack (sequential Talos then k8s upgrade) - // The platform reconciler creates an UpgradePolicy CR automatically. Individual - // node operations, etcd maintenance, and other day-2 operations are not affected. - // For management clusters, the Conductor executor upgrades the leader node last - // and the platform operator releases its lease before the leader node reboots. - // +optional - VersionUpgrade bool `json:"versionUpgrade,omitempty"` - - // ClusterEndpoint is the cluster VIP or primary API endpoint IP. Required on mode=import. - // Optional for bootstrap mode (endpoint derived from bootstrap Job output). - // +optional - ClusterEndpoint string `json:"clusterEndpoint,omitempty"` - - // NodeAddresses is the list of node IPs belonging to this cluster. Used by - // DSNSReconciler to populate A records in the seam DNS zone. platform-schema.md §5. - // +optional - NodeAddresses []string `json:"nodeAddresses,omitempty"` - - // CAPI holds CAPI integration settings. When absent, the cluster uses direct bootstrap. - // +optional - CAPI *InfrastructureCAPIConfig `json:"capi,omitempty"` - - // InfrastructureProvider declares the infrastructure provider backing this cluster. - // Defaults to native when absent. The only reserved future value is screen (INV-021). - // +kubebuilder:validation:Enum=native;capi;screen - // +kubebuilder:default=native - // +optional - InfrastructureProvider InfrastructureProvider `json:"infrastructureProvider,omitempty"` - - // KubeconfigSecretRef is the name of the Secret containing the kubeconfig for this cluster. - // Required on mode=import. Not used when CAPI manages the cluster lifecycle. - // +optional - KubeconfigSecretRef string `json:"kubeconfigSecretRef,omitempty"` - - // TalosconfigSecretRef is the name of the Secret containing the talosconfig for this cluster. - // +optional - TalosconfigSecretRef string `json:"talosconfigSecretRef,omitempty"` - - // Lineage is the sealed causal chain record for this root declaration. Immutable after creation. - // +optional - Lineage *lineage.SealedCausalChain `json:"lineage,omitempty"` - - // PkiRotationThresholdDays is the number of days before cert expiry at which - // the TalosCluster reconciler auto-creates a PKIRotation CR. Default 0 means - // use the platform operator built-in default (30 days). platform-schema.md §13. - // +optional - // +kubebuilder:default=30 - // +kubebuilder:validation:Minimum=1 - PkiRotationThresholdDays int32 `json:"pkiRotationThresholdDays,omitempty"` - - // HardeningProfileRef references a HardeningProfile CR to apply at bootstrap. - // ONT-native: platform creates a NodeMaintenance with operation=hardening-apply and - // label ontai.dev/hardening-trigger=bootstrap in seam-tenant-{cluster} after Ready. - // CAPI: MachineConfigPatches and SysctlParams are merged into TalosConfigTemplate at - // provisioning time. platform-schema.md §11. - // +optional - HardeningProfileRef *InfrastructureLocalObjectRef `json:"hardeningProfileRef,omitempty"` -} - -// InfrastructureTalosClusterStatus is the observed state of an InfrastructureTalosCluster. -type InfrastructureTalosClusterStatus struct { - // ObservedGeneration is the generation most recently reconciled. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Origin records how this cluster came under Seam governance. - // +optional - Origin InfrastructureTalosClusterOrigin `json:"origin,omitempty"` - - // ObservedTalosVersion is the Talos version last confirmed running by a successful - // day-2 upgrade operation (UpgradePolicy). The platform reconciler uses this to - // prevent spec.talosVersion from regressing the cluster below its current version. - // Set after each successful talos-upgrade or stack-upgrade UpgradePolicy. - // +optional - ObservedTalosVersion string `json:"observedTalosVersion,omitempty"` - - // CAPIClusterRef is a reference to the owned CAPI Cluster object in the tenant - // namespace. Only set for CAPI-managed clusters (capi.enabled=true). - // +optional - CAPIClusterRef *InfrastructureLocalObjectRef `json:"capiClusterRef,omitempty"` - - // Conditions is the list of status conditions for this TalosCluster. - // +optional - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // PkiExpiryDate is the earliest certificate expiry across the talosconfig and - // kubeconfig Secrets for this cluster. Set by the TalosCluster reconciler. - // When this date approaches spec.pkiRotationThresholdDays, a PKIRotation CR - // is created automatically. platform-schema.md §13. - // +optional - PkiExpiryDate *metav1.Time `json:"pkiExpiryDate,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=itc -// +kubebuilder:printcolumn:name="Mode",type=string,JSONPath=".spec.mode" -// +kubebuilder:printcolumn:name="Role",type=string,JSONPath=".spec.role" -// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=".status.conditions[?(@.type==\"Ready\")].status" -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" - -// InfrastructureTalosCluster is the seam-core CRD for a Talos cluster under Seam governance. -// platform-schema.md §4. Decision H. -type InfrastructureTalosCluster struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructureTalosClusterSpec `json:"spec,omitempty"` - Status InfrastructureTalosClusterStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructureTalosClusterList contains a list of InfrastructureTalosCluster. -type InfrastructureTalosClusterList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructureTalosCluster `json:"items"` -} - -func init() { - SchemeBuilder.Register(&InfrastructureTalosCluster{}, &InfrastructureTalosClusterList{}) -} diff --git a/api/v1alpha1/talosclusteroperationresult_types.go b/api/v1alpha1/talosclusteroperationresult_types.go deleted file mode 100644 index 7eddeff..0000000 --- a/api/v1alpha1/talosclusteroperationresult_types.go +++ /dev/null @@ -1,147 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// TalosClusterResultStatus is the terminal status of a TalosCluster day-2 operation. -// +kubebuilder:validation:Enum=Succeeded;Failed -type TalosClusterResultStatus string - -const ( - TalosClusterResultSucceeded TalosClusterResultStatus = "Succeeded" - TalosClusterResultFailed TalosClusterResultStatus = "Failed" -) - -// TalosClusterOperationFailureReason is a structured failure description for -// a day-2 operation that reached a terminal Failed state. -type TalosClusterOperationFailureReason struct { - // Category classifies the failure domain. - // +kubebuilder:validation:Enum=ValidationFailure;CapabilityUnavailable;ExecutionFailure;ExternalDependencyFailure;InvariantViolation - Category string `json:"category"` - - // Reason is a human-readable description of the failure. - Reason string `json:"reason"` -} - -// TalosClusterOperationRecord is a single day-2 operation record within one -// talosVersion revision. Multiple records accumulate in the parent TCOR as -// operations are performed against the cluster. -type TalosClusterOperationRecord struct { - // Capability is the conductor capability that produced this record. - Capability string `json:"capability"` - - // JobRef is the Kubernetes Job name that produced this record. - // The platform reconciler uses this to correlate the record with the Job it submitted. - JobRef string `json:"jobRef"` - - // Status is the terminal status of the capability execution. - // +kubebuilder:validation:Enum=Succeeded;Failed - Status TalosClusterResultStatus `json:"status"` - - // Message provides a human-readable summary of the outcome. - // +optional - Message string `json:"message,omitempty"` - - // StartedAt is the time the capability execution began. - // +optional - StartedAt *metav1.Time `json:"startedAt,omitempty"` - - // CompletedAt is the time the capability execution finished. - // +optional - CompletedAt *metav1.Time `json:"completedAt,omitempty"` - - // FailureReason is populated when Status is Failed. Nil on success. - // +optional - FailureReason *TalosClusterOperationFailureReason `json:"failureReason,omitempty"` -} - -// InfrastructureTalosClusterOperationResultSpec is the accumulated day-2 operation -// history for one cluster, scoped to the current talosVersion revision. -// -// One CR per cluster. Created by the platform operator when the cluster tenant -// namespace is provisioned. Named by the cluster name. Lives in seam-tenant-{clusterRef}. -// -// When the cluster talosVersion is upgraded, the current revision is archived to -// the GraphQuery DB and a new revision begins: Revision increments, TalosVersion -// is updated, and Operations is cleared. -// -// conductor-schema.md §8, seam-core-schema.md §TCOR. -type InfrastructureTalosClusterOperationResultSpec struct { - // ClusterRef is the name of the InfrastructureTalosCluster this result accumulates. - ClusterRef string `json:"clusterRef"` - - // TalosVersion is the cluster talosVersion for the current active revision. - // Matches InfrastructureTalosCluster.spec.talosVersion at the time this revision began. - TalosVersion string `json:"talosVersion"` - - // Revision is the monotonic revision counter. Starts at 1. Increments on each - // talosVersion upgrade. Each revision holds the operations performed during that - // version epoch. Archived revisions are stored in the GraphQuery DB. - // +kubebuilder:default=1 - Revision int64 `json:"revision"` - - // Operations is the map of day-2 operation records for the current revision, - // keyed by Kubernetes Job name (OPERATION_RESULT_CR). Map keying enables - // O(1) lookup by the platform reconciler and clean serialization when - // archiving the revision to the GraphQuery DB. - // +optional - Operations map[string]TalosClusterOperationRecord `json:"operations,omitempty"` - - // OperationCount is the count of records in Operations for the current revision. - // Maintained by the writer alongside Operations so kubectl can display it - // as an integer column. Updated atomically with every Operations write. - // json tag intentionally omits omitempty so the writer always serializes 0; - // the printcolumn then renders "0" rather than blank on zero-operation revisions. - // +optional - OperationCount int64 `json:"operationCount"` -} - -// InfrastructureTalosClusterOperationResultStatus is the observed state. -// Currently empty; reserved for future conditions. -type InfrastructureTalosClusterOperationResultStatus struct { - // ObservedGeneration is the last generation observed by any consumer. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=tcor -// +kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=`.spec.clusterRef` -// +kubebuilder:printcolumn:name="TalosVersion",type=string,JSONPath=`.spec.talosVersion` -// +kubebuilder:printcolumn:name="Revision",type=integer,JSONPath=`.spec.revision` -// +kubebuilder:printcolumn:name="Ops",type=integer,JSONPath=`.spec.operationCount` -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` - -// InfrastructureTalosClusterOperationResult accumulates the day-2 operation history -// for one cluster. One CR per cluster, created when the platform operator provisions -// the cluster tenant namespace. Operations are appended by the Conductor execute-mode -// Job. On talosVersion upgrade, the current revision is archived to the GraphQuery DB -// and a new revision epoch begins. -// -// Named by the cluster name. Lives in seam-tenant-{clusterRef}. -// conductor-schema.md §8, seam-core-schema.md §TCOR. -type InfrastructureTalosClusterOperationResult struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InfrastructureTalosClusterOperationResultSpec `json:"spec,omitempty"` - Status InfrastructureTalosClusterOperationResultStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InfrastructureTalosClusterOperationResultList contains a list of results. -type InfrastructureTalosClusterOperationResultList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InfrastructureTalosClusterOperationResult `json:"items"` -} - -func init() { - SchemeBuilder.Register( - &InfrastructureTalosClusterOperationResult{}, - &InfrastructureTalosClusterOperationResultList{}, - ) -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 72248c9..c58d428 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -5,7 +5,6 @@ package v1alpha1 import ( - "github.com/ontai-dev/seam-core/pkg/lineage" "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -143,1121 +142,7 @@ func (in *DriftSignalStatus) DeepCopy() *DriftSignalStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureCAPICiliumPackRef) DeepCopyInto(out *InfrastructureCAPICiliumPackRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureCAPICiliumPackRef. -func (in *InfrastructureCAPICiliumPackRef) DeepCopy() *InfrastructureCAPICiliumPackRef { - if in == nil { - return nil - } - out := new(InfrastructureCAPICiliumPackRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureCAPIConfig) DeepCopyInto(out *InfrastructureCAPIConfig) { - *out = *in - if in.ControlPlane != nil { - in, out := &in.ControlPlane, &out.ControlPlane - *out = new(InfrastructureCAPIControlPlaneConfig) - **out = **in - } - if in.Workers != nil { - in, out := &in.Workers, &out.Workers - *out = make([]InfrastructureCAPIWorkerPool, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.CiliumPackRef != nil { - in, out := &in.CiliumPackRef, &out.CiliumPackRef - *out = new(InfrastructureCAPICiliumPackRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureCAPIConfig. -func (in *InfrastructureCAPIConfig) DeepCopy() *InfrastructureCAPIConfig { - if in == nil { - return nil - } - out := new(InfrastructureCAPIConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureCAPIControlPlaneConfig) DeepCopyInto(out *InfrastructureCAPIControlPlaneConfig) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureCAPIControlPlaneConfig. -func (in *InfrastructureCAPIControlPlaneConfig) DeepCopy() *InfrastructureCAPIControlPlaneConfig { - if in == nil { - return nil - } - out := new(InfrastructureCAPIControlPlaneConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureCAPIWorkerPool) DeepCopyInto(out *InfrastructureCAPIWorkerPool) { - *out = *in - if in.SeamInfrastructureMachineNames != nil { - in, out := &in.SeamInfrastructureMachineNames, &out.SeamInfrastructureMachineNames - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureCAPIWorkerPool. -func (in *InfrastructureCAPIWorkerPool) DeepCopy() *InfrastructureCAPIWorkerPool { - if in == nil { - return nil - } - out := new(InfrastructureCAPIWorkerPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureClusterPack) DeepCopyInto(out *InfrastructureClusterPack) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureClusterPack. -func (in *InfrastructureClusterPack) DeepCopy() *InfrastructureClusterPack { - if in == nil { - return nil - } - out := new(InfrastructureClusterPack) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureClusterPack) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureClusterPackList) DeepCopyInto(out *InfrastructureClusterPackList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructureClusterPack, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureClusterPackList. -func (in *InfrastructureClusterPackList) DeepCopy() *InfrastructureClusterPackList { - if in == nil { - return nil - } - out := new(InfrastructureClusterPackList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureClusterPackList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureClusterPackRef) DeepCopyInto(out *InfrastructureClusterPackRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureClusterPackRef. -func (in *InfrastructureClusterPackRef) DeepCopy() *InfrastructureClusterPackRef { - if in == nil { - return nil - } - out := new(InfrastructureClusterPackRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureClusterPackSpec) DeepCopyInto(out *InfrastructureClusterPackSpec) { - *out = *in - out.RegistryRef = in.RegistryRef - if in.ExecutionOrder != nil { - in, out := &in.ExecutionOrder, &out.ExecutionOrder - *out = make([]InfrastructurePackExecutionStage, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Provenance != nil { - in, out := &in.Provenance, &out.Provenance - *out = new(InfrastructurePackProvenance) - (*in).DeepCopyInto(*out) - } - if in.TargetClusters != nil { - in, out := &in.TargetClusters, &out.TargetClusters - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.LifecyclePolicies != nil { - in, out := &in.LifecyclePolicies, &out.LifecyclePolicies - *out = new(InfrastructureLifecyclePolicy) - **out = **in - } - if in.Lineage != nil { - in, out := &in.Lineage, &out.Lineage - *out = new(lineage.SealedCausalChain) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureClusterPackSpec. -func (in *InfrastructureClusterPackSpec) DeepCopy() *InfrastructureClusterPackSpec { - if in == nil { - return nil - } - out := new(InfrastructureClusterPackSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureClusterPackStatus) DeepCopyInto(out *InfrastructureClusterPackStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureClusterPackStatus. -func (in *InfrastructureClusterPackStatus) DeepCopy() *InfrastructureClusterPackStatus { - if in == nil { - return nil - } - out := new(InfrastructureClusterPackStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureDependencyPolicy) DeepCopyInto(out *InfrastructureDependencyPolicy) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureDependencyPolicy. -func (in *InfrastructureDependencyPolicy) DeepCopy() *InfrastructureDependencyPolicy { - if in == nil { - return nil - } - out := new(InfrastructureDependencyPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureDeployedResourceRef) DeepCopyInto(out *InfrastructureDeployedResourceRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureDeployedResourceRef. -func (in *InfrastructureDeployedResourceRef) DeepCopy() *InfrastructureDeployedResourceRef { - if in == nil { - return nil - } - out := new(InfrastructureDeployedResourceRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLifecyclePolicy) DeepCopyInto(out *InfrastructureLifecyclePolicy) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLifecyclePolicy. -func (in *InfrastructureLifecyclePolicy) DeepCopy() *InfrastructureLifecyclePolicy { - if in == nil { - return nil - } - out := new(InfrastructureLifecyclePolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLineageIndex) DeepCopyInto(out *InfrastructureLineageIndex) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLineageIndex. -func (in *InfrastructureLineageIndex) DeepCopy() *InfrastructureLineageIndex { - if in == nil { - return nil - } - out := new(InfrastructureLineageIndex) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureLineageIndex) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLineageIndexList) DeepCopyInto(out *InfrastructureLineageIndexList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructureLineageIndex, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLineageIndexList. -func (in *InfrastructureLineageIndexList) DeepCopy() *InfrastructureLineageIndexList { - if in == nil { - return nil - } - out := new(InfrastructureLineageIndexList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureLineageIndexList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLineageIndexRootBinding) DeepCopyInto(out *InfrastructureLineageIndexRootBinding) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLineageIndexRootBinding. -func (in *InfrastructureLineageIndexRootBinding) DeepCopy() *InfrastructureLineageIndexRootBinding { - if in == nil { - return nil - } - out := new(InfrastructureLineageIndexRootBinding) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLineageIndexSpec) DeepCopyInto(out *InfrastructureLineageIndexSpec) { - *out = *in - out.RootBinding = in.RootBinding - if in.DescendantRegistry != nil { - in, out := &in.DescendantRegistry, &out.DescendantRegistry - *out = make([]DescendantEntry, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.PolicyBindingStatus != nil { - in, out := &in.PolicyBindingStatus, &out.PolicyBindingStatus - *out = new(InfrastructurePolicyBindingStatus) - **out = **in - } - if in.OutcomeRegistry != nil { - in, out := &in.OutcomeRegistry, &out.OutcomeRegistry - *out = make([]OutcomeEntry, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.RetentionPolicy != nil { - in, out := &in.RetentionPolicy, &out.RetentionPolicy - *out = new(LineageRetentionPolicy) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLineageIndexSpec. -func (in *InfrastructureLineageIndexSpec) DeepCopy() *InfrastructureLineageIndexSpec { - if in == nil { - return nil - } - out := new(InfrastructureLineageIndexSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLineageIndexStatus) DeepCopyInto(out *InfrastructureLineageIndexStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLineageIndexStatus. -func (in *InfrastructureLineageIndexStatus) DeepCopy() *InfrastructureLineageIndexStatus { - if in == nil { - return nil - } - out := new(InfrastructureLineageIndexStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureLocalObjectRef) DeepCopyInto(out *InfrastructureLocalObjectRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureLocalObjectRef. -func (in *InfrastructureLocalObjectRef) DeepCopy() *InfrastructureLocalObjectRef { - if in == nil { - return nil - } - out := new(InfrastructureLocalObjectRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackBuild) DeepCopyInto(out *InfrastructurePackBuild) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackBuild. -func (in *InfrastructurePackBuild) DeepCopy() *InfrastructurePackBuild { - if in == nil { - return nil - } - out := new(InfrastructurePackBuild) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackBuild) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackBuildList) DeepCopyInto(out *InfrastructurePackBuildList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructurePackBuild, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackBuildList. -func (in *InfrastructurePackBuildList) DeepCopy() *InfrastructurePackBuildList { - if in == nil { - return nil - } - out := new(InfrastructurePackBuildList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackBuildList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackBuildSpec) DeepCopyInto(out *InfrastructurePackBuildSpec) { - *out = *in - if in.HelmSource != nil { - in, out := &in.HelmSource, &out.HelmSource - *out = new(InfrastructurePackHelmSource) - **out = **in - } - if in.KustomizeSource != nil { - in, out := &in.KustomizeSource, &out.KustomizeSource - *out = new(InfrastructurePackKustomizeSource) - **out = **in - } - if in.RawSource != nil { - in, out := &in.RawSource, &out.RawSource - *out = new(InfrastructurePackRawSource) - **out = **in - } - if in.TargetClusters != nil { - in, out := &in.TargetClusters, &out.TargetClusters - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackBuildSpec. -func (in *InfrastructurePackBuildSpec) DeepCopy() *InfrastructurePackBuildSpec { - if in == nil { - return nil - } - out := new(InfrastructurePackBuildSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackBuildStatus) DeepCopyInto(out *InfrastructurePackBuildStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackBuildStatus. -func (in *InfrastructurePackBuildStatus) DeepCopy() *InfrastructurePackBuildStatus { - if in == nil { - return nil - } - out := new(InfrastructurePackBuildStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackExecution) DeepCopyInto(out *InfrastructurePackExecution) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackExecution. -func (in *InfrastructurePackExecution) DeepCopy() *InfrastructurePackExecution { - if in == nil { - return nil - } - out := new(InfrastructurePackExecution) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackExecution) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackExecutionList) DeepCopyInto(out *InfrastructurePackExecutionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructurePackExecution, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackExecutionList. -func (in *InfrastructurePackExecutionList) DeepCopy() *InfrastructurePackExecutionList { - if in == nil { - return nil - } - out := new(InfrastructurePackExecutionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackExecutionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackExecutionSpec) DeepCopyInto(out *InfrastructurePackExecutionSpec) { - *out = *in - out.ClusterPackRef = in.ClusterPackRef - if in.Lineage != nil { - in, out := &in.Lineage, &out.Lineage - *out = new(lineage.SealedCausalChain) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackExecutionSpec. -func (in *InfrastructurePackExecutionSpec) DeepCopy() *InfrastructurePackExecutionSpec { - if in == nil { - return nil - } - out := new(InfrastructurePackExecutionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackExecutionStage) DeepCopyInto(out *InfrastructurePackExecutionStage) { - *out = *in - if in.Manifests != nil { - in, out := &in.Manifests, &out.Manifests - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackExecutionStage. -func (in *InfrastructurePackExecutionStage) DeepCopy() *InfrastructurePackExecutionStage { - if in == nil { - return nil - } - out := new(InfrastructurePackExecutionStage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackExecutionStatus) DeepCopyInto(out *InfrastructurePackExecutionStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackExecutionStatus. -func (in *InfrastructurePackExecutionStatus) DeepCopy() *InfrastructurePackExecutionStatus { - if in == nil { - return nil - } - out := new(InfrastructurePackExecutionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackHelmSource) DeepCopyInto(out *InfrastructurePackHelmSource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackHelmSource. -func (in *InfrastructurePackHelmSource) DeepCopy() *InfrastructurePackHelmSource { - if in == nil { - return nil - } - out := new(InfrastructurePackHelmSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackInstance) DeepCopyInto(out *InfrastructurePackInstance) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackInstance. -func (in *InfrastructurePackInstance) DeepCopy() *InfrastructurePackInstance { - if in == nil { - return nil - } - out := new(InfrastructurePackInstance) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackInstance) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackInstanceList) DeepCopyInto(out *InfrastructurePackInstanceList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructurePackInstance, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackInstanceList. -func (in *InfrastructurePackInstanceList) DeepCopy() *InfrastructurePackInstanceList { - if in == nil { - return nil - } - out := new(InfrastructurePackInstanceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackInstanceList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackInstanceSpec) DeepCopyInto(out *InfrastructurePackInstanceSpec) { - *out = *in - if in.DependsOn != nil { - in, out := &in.DependsOn, &out.DependsOn - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.DependencyPolicy != nil { - in, out := &in.DependencyPolicy, &out.DependencyPolicy - *out = new(InfrastructureDependencyPolicy) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackInstanceSpec. -func (in *InfrastructurePackInstanceSpec) DeepCopy() *InfrastructurePackInstanceSpec { - if in == nil { - return nil - } - out := new(InfrastructurePackInstanceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackInstanceStatus) DeepCopyInto(out *InfrastructurePackInstanceStatus) { - *out = *in - if in.DeliveredAt != nil { - in, out := &in.DeliveredAt, &out.DeliveredAt - *out = (*in).DeepCopy() - } - if in.DeployedResources != nil { - in, out := &in.DeployedResources, &out.DeployedResources - *out = make([]InfrastructureDeployedResourceRef, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackInstanceStatus. -func (in *InfrastructurePackInstanceStatus) DeepCopy() *InfrastructurePackInstanceStatus { - if in == nil { - return nil - } - out := new(InfrastructurePackInstanceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackKustomizeSource) DeepCopyInto(out *InfrastructurePackKustomizeSource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackKustomizeSource. -func (in *InfrastructurePackKustomizeSource) DeepCopy() *InfrastructurePackKustomizeSource { - if in == nil { - return nil - } - out := new(InfrastructurePackKustomizeSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackProvenance) DeepCopyInto(out *InfrastructurePackProvenance) { - *out = *in - if in.BuildTimestamp != nil { - in, out := &in.BuildTimestamp, &out.BuildTimestamp - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackProvenance. -func (in *InfrastructurePackProvenance) DeepCopy() *InfrastructurePackProvenance { - if in == nil { - return nil - } - out := new(InfrastructurePackProvenance) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackRawSource) DeepCopyInto(out *InfrastructurePackRawSource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackRawSource. -func (in *InfrastructurePackRawSource) DeepCopy() *InfrastructurePackRawSource { - if in == nil { - return nil - } - out := new(InfrastructurePackRawSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackReceipt) DeepCopyInto(out *InfrastructurePackReceipt) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackReceipt. -func (in *InfrastructurePackReceipt) DeepCopy() *InfrastructurePackReceipt { - if in == nil { - return nil - } - out := new(InfrastructurePackReceipt) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackReceipt) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackReceiptList) DeepCopyInto(out *InfrastructurePackReceiptList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructurePackReceipt, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackReceiptList. -func (in *InfrastructurePackReceiptList) DeepCopy() *InfrastructurePackReceiptList { - if in == nil { - return nil - } - out := new(InfrastructurePackReceiptList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructurePackReceiptList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackReceiptSpec) DeepCopyInto(out *InfrastructurePackReceiptSpec) { - *out = *in - if in.DeployedResources != nil { - in, out := &in.DeployedResources, &out.DeployedResources - *out = make([]PackReceiptDeployedResource, len(*in)) - copy(*out, *in) - } -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackReceiptDeployedResource) DeepCopyInto(out *PackReceiptDeployedResource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackReceiptDeployedResource. -func (in *PackReceiptDeployedResource) DeepCopy() *PackReceiptDeployedResource { - if in == nil { - return nil - } - out := new(PackReceiptDeployedResource) - in.DeepCopyInto(out) - return out -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackReceiptSpec. -func (in *InfrastructurePackReceiptSpec) DeepCopy() *InfrastructurePackReceiptSpec { - if in == nil { - return nil - } - out := new(InfrastructurePackReceiptSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackReceiptStatus) DeepCopyInto(out *InfrastructurePackReceiptStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackReceiptStatus. -func (in *InfrastructurePackReceiptStatus) DeepCopy() *InfrastructurePackReceiptStatus { - if in == nil { - return nil - } - out := new(InfrastructurePackReceiptStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePackRegistryRef) DeepCopyInto(out *InfrastructurePackRegistryRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePackRegistryRef. -func (in *InfrastructurePackRegistryRef) DeepCopy() *InfrastructurePackRegistryRef { - if in == nil { - return nil - } - out := new(InfrastructurePackRegistryRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructurePolicyBindingStatus) DeepCopyInto(out *InfrastructurePolicyBindingStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePolicyBindingStatus. -func (in *InfrastructurePolicyBindingStatus) DeepCopy() *InfrastructurePolicyBindingStatus { - if in == nil { - return nil - } - out := new(InfrastructurePolicyBindingStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureRunnerConfig) DeepCopyInto(out *InfrastructureRunnerConfig) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureRunnerConfig. -func (in *InfrastructureRunnerConfig) DeepCopy() *InfrastructureRunnerConfig { - if in == nil { - return nil - } - out := new(InfrastructureRunnerConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureRunnerConfig) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureRunnerConfigList) DeepCopyInto(out *InfrastructureRunnerConfigList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructureRunnerConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureRunnerConfigList. -func (in *InfrastructureRunnerConfigList) DeepCopy() *InfrastructureRunnerConfigList { - if in == nil { - return nil - } - out := new(InfrastructureRunnerConfigList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureRunnerConfigList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureRunnerConfigSpec) DeepCopyInto(out *InfrastructureRunnerConfigSpec) { - *out = *in - if in.Phases != nil { - in, out := &in.Phases, &out.Phases - *out = make([]RunnerPhaseConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Steps != nil { - in, out := &in.Steps, &out.Steps - *out = make([]RunnerConfigStep, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.OperationalHistory != nil { - in, out := &in.OperationalHistory, &out.OperationalHistory - *out = make([]RunnerOperationalHistoryEntry, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.MaintenanceTargetNodes != nil { - in, out := &in.MaintenanceTargetNodes, &out.MaintenanceTargetNodes - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureRunnerConfigSpec. -func (in *InfrastructureRunnerConfigSpec) DeepCopy() *InfrastructureRunnerConfigSpec { - if in == nil { - return nil - } - out := new(InfrastructureRunnerConfigSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureRunnerConfigStatus) DeepCopyInto(out *InfrastructureRunnerConfigStatus) { - *out = *in - if in.Capabilities != nil { - in, out := &in.Capabilities, &out.Capabilities - *out = make([]RunnerCapabilityEntry, len(*in)) - copy(*out, *in) - } - if in.StepResults != nil { - in, out := &in.StepResults, &out.StepResults - *out = make([]RunnerConfigStepResult, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureRunnerConfigStatus. -func (in *InfrastructureRunnerConfigStatus) DeepCopy() *InfrastructureRunnerConfigStatus { - if in == nil { - return nil - } - out := new(InfrastructureRunnerConfigStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosCluster) DeepCopyInto(out *InfrastructureTalosCluster) { +func (in *LineageRecord) DeepCopyInto(out *LineageRecord) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1265,18 +150,18 @@ func (in *InfrastructureTalosCluster) DeepCopyInto(out *InfrastructureTalosClust in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosCluster. -func (in *InfrastructureTalosCluster) DeepCopy() *InfrastructureTalosCluster { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRecord. +func (in *LineageRecord) DeepCopy() *LineageRecord { if in == nil { return nil } - out := new(InfrastructureTalosCluster) + out := new(LineageRecord) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureTalosCluster) DeepCopyObject() runtime.Object { +func (in *LineageRecord) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1284,31 +169,31 @@ func (in *InfrastructureTalosCluster) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterList) DeepCopyInto(out *InfrastructureTalosClusterList) { +func (in *LineageRecordList) DeepCopyInto(out *LineageRecordList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]InfrastructureTalosCluster, len(*in)) + *out = make([]LineageRecord, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterList. -func (in *InfrastructureTalosClusterList) DeepCopy() *InfrastructureTalosClusterList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRecordList. +func (in *LineageRecordList) DeepCopy() *LineageRecordList { if in == nil { return nil } - out := new(InfrastructureTalosClusterList) + out := new(LineageRecordList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureTalosClusterList) DeepCopyObject() runtime.Object { +func (in *LineageRecordList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1316,144 +201,63 @@ func (in *InfrastructureTalosClusterList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterOperationResult) DeepCopyInto(out *InfrastructureTalosClusterOperationResult) { +func (in *LineageRecordRootBinding) DeepCopyInto(out *LineageRecordRootBinding) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterOperationResult. -func (in *InfrastructureTalosClusterOperationResult) DeepCopy() *InfrastructureTalosClusterOperationResult { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRecordRootBinding. +func (in *LineageRecordRootBinding) DeepCopy() *LineageRecordRootBinding { if in == nil { return nil } - out := new(InfrastructureTalosClusterOperationResult) + out := new(LineageRecordRootBinding) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureTalosClusterOperationResult) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterOperationResultList) DeepCopyInto(out *InfrastructureTalosClusterOperationResultList) { +func (in *LineageRecordSpec) DeepCopyInto(out *LineageRecordSpec) { *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InfrastructureTalosClusterOperationResult, len(*in)) + out.RootBinding = in.RootBinding + if in.DescendantRegistry != nil { + in, out := &in.DescendantRegistry, &out.DescendantRegistry + *out = make([]DescendantEntry, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterOperationResultList. -func (in *InfrastructureTalosClusterOperationResultList) DeepCopy() *InfrastructureTalosClusterOperationResultList { - if in == nil { - return nil - } - out := new(InfrastructureTalosClusterOperationResultList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InfrastructureTalosClusterOperationResultList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c + if in.PolicyBindingStatus != nil { + in, out := &in.PolicyBindingStatus, &out.PolicyBindingStatus + *out = new(InfrastructurePolicyBindingStatus) + **out = **in } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterOperationResultSpec) DeepCopyInto(out *InfrastructureTalosClusterOperationResultSpec) { - *out = *in - if in.Operations != nil { - in, out := &in.Operations, &out.Operations - *out = make(map[string]TalosClusterOperationRecord, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() + if in.OutcomeRegistry != nil { + in, out := &in.OutcomeRegistry, &out.OutcomeRegistry + *out = make([]OutcomeEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) } } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterOperationResultSpec. -func (in *InfrastructureTalosClusterOperationResultSpec) DeepCopy() *InfrastructureTalosClusterOperationResultSpec { - if in == nil { - return nil - } - out := new(InfrastructureTalosClusterOperationResultSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterOperationResultStatus) DeepCopyInto(out *InfrastructureTalosClusterOperationResultStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterOperationResultStatus. -func (in *InfrastructureTalosClusterOperationResultStatus) DeepCopy() *InfrastructureTalosClusterOperationResultStatus { - if in == nil { - return nil - } - out := new(InfrastructureTalosClusterOperationResultStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterSpec) DeepCopyInto(out *InfrastructureTalosClusterSpec) { - *out = *in - if in.NodeAddresses != nil { - in, out := &in.NodeAddresses, &out.NodeAddresses - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.CAPI != nil { - in, out := &in.CAPI, &out.CAPI - *out = new(InfrastructureCAPIConfig) - (*in).DeepCopyInto(*out) - } - if in.Lineage != nil { - in, out := &in.Lineage, &out.Lineage - *out = new(lineage.SealedCausalChain) - **out = **in - } - if in.HardeningProfileRef != nil { - in, out := &in.HardeningProfileRef, &out.HardeningProfileRef - *out = new(InfrastructureLocalObjectRef) + if in.RetentionPolicy != nil { + in, out := &in.RetentionPolicy, &out.RetentionPolicy + *out = new(LineageRetentionPolicy) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterSpec. -func (in *InfrastructureTalosClusterSpec) DeepCopy() *InfrastructureTalosClusterSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRecordSpec. +func (in *LineageRecordSpec) DeepCopy() *LineageRecordSpec { if in == nil { return nil } - out := new(InfrastructureTalosClusterSpec) + out := new(LineageRecordSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfrastructureTalosClusterStatus) DeepCopyInto(out *InfrastructureTalosClusterStatus) { +func (in *LineageRecordStatus) DeepCopyInto(out *LineageRecordStatus) { *out = *in - if in.CAPIClusterRef != nil { - in, out := &in.CAPIClusterRef, &out.CAPIClusterRef - *out = new(InfrastructureLocalObjectRef) - **out = **in - } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]v1.Condition, len(*in)) @@ -1461,119 +265,54 @@ func (in *InfrastructureTalosClusterStatus) DeepCopyInto(out *InfrastructureTalo (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.PkiExpiryDate != nil { - in, out := &in.PkiExpiryDate, &out.PkiExpiryDate - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructureTalosClusterStatus. -func (in *InfrastructureTalosClusterStatus) DeepCopy() *InfrastructureTalosClusterStatus { - if in == nil { - return nil - } - out := new(InfrastructureTalosClusterStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LineageRetentionPolicy) DeepCopyInto(out *LineageRetentionPolicy) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRetentionPolicy. -func (in *LineageRetentionPolicy) DeepCopy() *LineageRetentionPolicy { - if in == nil { - return nil - } - out := new(LineageRetentionPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OutcomeEntry) DeepCopyInto(out *OutcomeEntry) { - *out = *in - in.OutcomeTimestamp.DeepCopyInto(&out.OutcomeTimestamp) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OutcomeEntry. -func (in *OutcomeEntry) DeepCopy() *OutcomeEntry { - if in == nil { - return nil - } - out := new(OutcomeEntry) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationArtifact) DeepCopyInto(out *PackOperationArtifact) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationArtifact. -func (in *PackOperationArtifact) DeepCopy() *PackOperationArtifact { - if in == nil { - return nil - } - out := new(PackOperationArtifact) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationDeployedResource) DeepCopyInto(out *PackOperationDeployedResource) { - *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationDeployedResource. -func (in *PackOperationDeployedResource) DeepCopy() *PackOperationDeployedResource { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRecordStatus. +func (in *LineageRecordStatus) DeepCopy() *LineageRecordStatus { if in == nil { return nil } - out := new(PackOperationDeployedResource) + out := new(LineageRecordStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationFailureReason) DeepCopyInto(out *PackOperationFailureReason) { +func (in *InfrastructurePolicyBindingStatus) DeepCopyInto(out *InfrastructurePolicyBindingStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationFailureReason. -func (in *PackOperationFailureReason) DeepCopy() *PackOperationFailureReason { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfrastructurePolicyBindingStatus. +func (in *InfrastructurePolicyBindingStatus) DeepCopy() *InfrastructurePolicyBindingStatus { if in == nil { return nil } - out := new(PackOperationFailureReason) + out := new(InfrastructurePolicyBindingStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationResult) DeepCopyInto(out *PackOperationResult) { +func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationResult. -func (in *PackOperationResult) DeepCopy() *PackOperationResult { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfig. +func (in *RunnerConfig) DeepCopy() *RunnerConfig { if in == nil { return nil } - out := new(PackOperationResult) + out := new(RunnerConfig) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackOperationResult) DeepCopyObject() runtime.Object { +func (in *RunnerConfig) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1581,31 +320,31 @@ func (in *PackOperationResult) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationResultList) DeepCopyInto(out *PackOperationResultList) { +func (in *RunnerConfigList) DeepCopyInto(out *RunnerConfigList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]PackOperationResult, len(*in)) + *out = make([]RunnerConfig, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationResultList. -func (in *PackOperationResultList) DeepCopy() *PackOperationResultList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfigList. +func (in *RunnerConfigList) DeepCopy() *RunnerConfigList { if in == nil { return nil } - out := new(PackOperationResultList) + out := new(RunnerConfigList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackOperationResultList) DeepCopyObject() runtime.Object { +func (in *RunnerConfigList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1613,84 +352,107 @@ func (in *PackOperationResultList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationResultSpec) DeepCopyInto(out *PackOperationResultSpec) { +func (in *RunnerConfigSpec) DeepCopyInto(out *RunnerConfigSpec) { *out = *in - if in.StartedAt != nil { - in, out := &in.StartedAt, &out.StartedAt - *out = (*in).DeepCopy() + if in.Phases != nil { + in, out := &in.Phases, &out.Phases + *out = make([]RunnerPhaseConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.CompletedAt != nil { - in, out := &in.CompletedAt, &out.CompletedAt - *out = (*in).DeepCopy() + if in.Steps != nil { + in, out := &in.Steps, &out.Steps + *out = make([]RunnerConfigStep, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.FailureReason != nil { - in, out := &in.FailureReason, &out.FailureReason - *out = new(PackOperationFailureReason) - **out = **in + if in.OperationalHistory != nil { + in, out := &in.OperationalHistory, &out.OperationalHistory + *out = make([]RunnerOperationalHistoryEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.DeployedResources != nil { - in, out := &in.DeployedResources, &out.DeployedResources - *out = make([]PackOperationDeployedResource, len(*in)) + if in.MaintenanceTargetNodes != nil { + in, out := &in.MaintenanceTargetNodes, &out.MaintenanceTargetNodes + *out = make([]string, len(*in)) copy(*out, *in) } - if in.Artifacts != nil { - in, out := &in.Artifacts, &out.Artifacts - *out = make([]PackOperationArtifact, len(*in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfigSpec. +func (in *RunnerConfigSpec) DeepCopy() *RunnerConfigSpec { + if in == nil { + return nil + } + out := new(RunnerConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RunnerConfigStatus) DeepCopyInto(out *RunnerConfigStatus) { + *out = *in + if in.Capabilities != nil { + in, out := &in.Capabilities, &out.Capabilities + *out = make([]RunnerCapabilityEntry, len(*in)) copy(*out, *in) } - if in.Steps != nil { - in, out := &in.Steps, &out.Steps - *out = make([]PackOperationStepResult, len(*in)) + if in.StepResults != nil { + in, out := &in.StepResults, &out.StepResults + *out = make([]RunnerConfigStepResult, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationResultSpec. -func (in *PackOperationResultSpec) DeepCopy() *PackOperationResultSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfigStatus. +func (in *RunnerConfigStatus) DeepCopy() *RunnerConfigStatus { if in == nil { return nil } - out := new(PackOperationResultSpec) + out := new(RunnerConfigStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationResultStatus) DeepCopyInto(out *PackOperationResultStatus) { +func (in *LineageRetentionPolicy) DeepCopyInto(out *LineageRetentionPolicy) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationResultStatus. -func (in *PackOperationResultStatus) DeepCopy() *PackOperationResultStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LineageRetentionPolicy. +func (in *LineageRetentionPolicy) DeepCopy() *LineageRetentionPolicy { if in == nil { return nil } - out := new(PackOperationResultStatus) + out := new(LineageRetentionPolicy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackOperationStepResult) DeepCopyInto(out *PackOperationStepResult) { +func (in *OutcomeEntry) DeepCopyInto(out *OutcomeEntry) { *out = *in - if in.StartedAt != nil { - in, out := &in.StartedAt, &out.StartedAt - *out = (*in).DeepCopy() - } - if in.CompletedAt != nil { - in, out := &in.CompletedAt, &out.CompletedAt - *out = (*in).DeepCopy() - } + in.OutcomeTimestamp.DeepCopyInto(&out.OutcomeTimestamp) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackOperationStepResult. -func (in *PackOperationStepResult) DeepCopy() *PackOperationStepResult { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OutcomeEntry. +func (in *OutcomeEntry) DeepCopy() *OutcomeEntry { if in == nil { return nil } - out := new(PackOperationStepResult) + out := new(OutcomeEntry) in.DeepCopyInto(out) return out } @@ -1893,45 +655,3 @@ func (in *SeamMembershipStatus) DeepCopy() *SeamMembershipStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TalosClusterOperationFailureReason) DeepCopyInto(out *TalosClusterOperationFailureReason) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TalosClusterOperationFailureReason. -func (in *TalosClusterOperationFailureReason) DeepCopy() *TalosClusterOperationFailureReason { - if in == nil { - return nil - } - out := new(TalosClusterOperationFailureReason) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TalosClusterOperationRecord) DeepCopyInto(out *TalosClusterOperationRecord) { - *out = *in - if in.StartedAt != nil { - in, out := &in.StartedAt, &out.StartedAt - *out = (*in).DeepCopy() - } - if in.CompletedAt != nil { - in, out := &in.CompletedAt, &out.CompletedAt - *out = (*in).DeepCopy() - } - if in.FailureReason != nil { - in, out := &in.FailureReason, &out.FailureReason - *out = new(TalosClusterOperationFailureReason) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TalosClusterOperationRecord. -func (in *TalosClusterOperationRecord) DeepCopy() *TalosClusterOperationRecord { - if in == nil { - return nil - } - out := new(TalosClusterOperationRecord) - in.DeepCopyInto(out) - return out -} diff --git a/cmd/seam-core/main.go b/cmd/seam-core/main.go index 153bdc3..8cc7b3c 100644 --- a/cmd/seam-core/main.go +++ b/cmd/seam-core/main.go @@ -22,10 +22,10 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" - idns "github.com/ontai-dev/seam-core/internal/dns" - "github.com/ontai-dev/seam-core/internal/webhook" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" + idns "github.com/ontai-dev/seam/internal/dns" + "github.com/ontai-dev/seam/internal/webhook" ) var scheme = runtime.NewScheme() diff --git a/config/crd/infrastructure.ontai.dev_driftsignals.yaml b/config/crd/infrastructure.ontai.dev_driftsignals.yaml index 51efb3d..afa6921 100644 --- a/config/crd/infrastructure.ontai.dev_driftsignals.yaml +++ b/config/crd/infrastructure.ontai.dev_driftsignals.yaml @@ -1,202 +1,2 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: driftsignals.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: DriftSignal - listKind: DriftSignalList - plural: driftsignals - shortNames: - - ds - singular: driftsignal - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.state - name: State - type: string - - jsonPath: .spec.correlationID - name: CorrelationID - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - DriftSignal is the seam-core CRD for the three-state drift acknowledgement chain. - Written by conductor role=tenant; acknowledged by conductor role=management. - Decision I. At-least-once delivery. Human-at-Boundary invariant enforced via - configurable escalation threshold and TerminalDrift Condition. conductor-schema.md. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - DriftSignalSpec defines the observed drift event written by conductor role=tenant. - Decision I. conductor-schema.md. - properties: - affectedCRRef: - description: AffectedCRRef is a typed reference to the CR that exhibited - drift. - properties: - group: - description: Group is the API group of the drifted CR. - type: string - kind: - description: Kind is the Kind of the drifted CR. - type: string - name: - description: Name is the name of the drifted CR. - type: string - namespace: - description: Namespace is the namespace of the drifted CR. Empty - for cluster-scoped resources. - type: string - required: - - group - - kind - - name - type: object - correctionJobRef: - description: |- - CorrectionJobRef is the name of the corrective Job created by the management cluster. - Populated when state transitions to queued. - type: string - correlationID: - description: |- - CorrelationID is a unique identifier for this drift event, used to deduplicate - signals across federation retries. Format: UUID v4. - type: string - driftReason: - description: DriftReason is a human-readable description of why drift - was detected. - type: string - escalationCounter: - description: |- - EscalationCounter is the number of times this signal has been re-emitted without - acknowledgement. Incremented by conductor role=tenant on each re-emit cycle. - When this counter reaches the configurable escalation threshold, conductor writes a - type=TerminalDrift Condition on the affected CR and stops re-emitting. Decision I. - format: int32 - type: integer - observedAt: - description: ObservedAt is the time the drift was first observed by - conductor role=tenant. - format: date-time - type: string - state: - allOf: - - enum: - - pending - - delivered - - queued - - confirmed - - enum: - - pending - - delivered - - queued - - confirmed - description: State is the current acknowledgement state of this drift - signal. Decision I. - type: string - required: - - affectedCRRef - - correlationID - - driftReason - - observedAt - - state - type: object - status: - description: DriftSignalStatus is the observed state of a DriftSignal. - Written by conductor role=management. - properties: - conditions: - description: Conditions is the list of status conditions for this - DriftSignal. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} +# Tombstone: DriftSignal migrated to seam.ontai.dev (MIGRATION-3.8). +# See seam.ontai.dev_driftsignals.yaml. diff --git a/config/crd/infrastructure.ontai.dev_infrastructureclusterpacks.yaml b/config/crd/infrastructure.ontai.dev_infrastructureclusterpacks.yaml deleted file mode 100644 index 3a05a27..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructureclusterpacks.yaml +++ /dev/null @@ -1,354 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructureclusterpacks.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureClusterPack - listKind: InfrastructureClusterPackList - plural: infrastructureclusterpacks - shortNames: - - icp - singular: infrastructureclusterpack - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.version - name: Version - type: string - - jsonPath: .status.signed - name: Signed - type: boolean - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructureClusterPack is the seam-core CRD for pack registration. - Records an OCI artifact that has been compiled and is ready for runtime delivery. - Spec is immutable after creation. wrapper-schema.md §3. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructureClusterPackSpec defines the desired state of an InfrastructureClusterPack. - All fields are immutable after creation. wrapper-schema.md §3. - properties: - basePackName: - description: BasePackName is the logical pack name shared across versions - (e.g., "nginx-ingress"). - type: string - chartName: - description: ChartName is the name of the Helm chart used to compile - this pack. - type: string - chartURL: - description: ChartURL is the URL of the Helm chart repository used - to compile this pack. - type: string - chartVersion: - description: ChartVersion is the version of the Helm chart used to - compile this pack. - type: string - checksum: - description: Checksum is the content-addressed checksum of the full - artifact manifest set. - type: string - clusterScopedDigest: - description: |- - ClusterScopedDigest is the OCI digest of the cluster-scoped non-RBAC layer. - Applied after guardian RBAC intake and before workload manifests. wrapper-schema.md §4. - type: string - executionOrder: - description: ExecutionOrder defines the ordered stages in which pack - manifests are applied. - items: - description: InfrastructurePackExecutionStage is a single stage - in the pack execution order. - properties: - manifests: - description: Manifests is the list of manifest names to apply - in this stage. - items: - type: string - type: array - name: - description: 'Name is the stage name. Must be one of: rbac, - storage, stateful, stateless.' - enum: - - rbac - - storage - - stateful - - stateless - type: string - required: - - name - type: object - type: array - helmVersion: - description: HelmVersion is the version of the Helm SDK used to render - this pack. - type: string - lifecyclePolicies: - description: LifecyclePolicies controls artifact retention behavior. - properties: - retainOnDeletion: - default: true - description: |- - RetainOnDeletion controls whether the OCI artifact is retained when the - ClusterPack CR is deleted. Default: true (artifact retained). - type: boolean - type: object - lineage: - description: |- - Lineage is the sealed causal chain record for this root declaration. - Authored once at object creation time and immutable thereafter. - seam-core-schema.md §5, CLAUDE.md §14 Decision 1. - properties: - creatingOperator: - description: |- - CreatingOperator identifies the Seam Operator that created this object. - This is a structured identity carrying the operator name and its deployed - version at creation time. - properties: - name: - description: |- - Name is the canonical name of the Seam Operator (e.g., platform, guardian, - wrapper, conductor). - type: string - version: - description: |- - Version is the deployed version of the operator at the time the object was - created (e.g., v1.26.5-r3). This allows audit tooling to correlate objects - with the operator version that produced them. - type: string - required: - - name - - version - type: object - creationRationale: - description: |- - CreationRationale is the reason this object was created, drawn from the - Seam Core controlled vocabulary defined in rationale.go. It is not a - free-text field. - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - type: string - rootGenerationAtCreation: - description: |- - RootGenerationAtCreation is the metadata.generation of the root declaration - at the time this object was created. Together with RootUID, it provides a - complete temporal anchor for the derivation record. - format: int64 - type: integer - rootKind: - description: |- - RootKind is the kind of the root declaration that caused this object to - exist (e.g., TalosCluster, PackExecution, RBACPolicy). - type: string - rootName: - description: RootName is the name of the root declaration. - type: string - rootNamespace: - description: RootNamespace is the namespace of the root declaration. - type: string - rootUID: - description: |- - RootUID is the UID of the root declaration at the time this object was - created. Used to verify that no root declaration replacement has occurred. - type: string - required: - - creatingOperator - - creationRationale - - rootGenerationAtCreation - - rootKind - - rootName - - rootNamespace - - rootUID - type: object - provenance: - description: Provenance records build-time metadata for audit and - traceability. - properties: - buildID: - description: BuildID is the CI/CD build identifier that produced - this pack. - type: string - buildTimestamp: - description: BuildTimestamp is when the pack artifact was produced. - format: date-time - type: string - sourceRef: - description: SourceRef is the git reference (commit SHA or tag) - from which the pack was built. - type: string - type: object - rbacDigest: - description: |- - RBACDigest is the OCI digest of the RBAC layer of this ClusterPack artifact. - Contains ServiceAccount, Role, ClusterRole, RoleBinding, ClusterRoleBinding manifests. - type: string - registryRef: - description: RegistryRef identifies the OCI artifact for this pack. - Immutable after creation. - properties: - digest: - description: Digest is the OCI image digest (e.g., sha256:abc123...). - Immutable after creation. - type: string - url: - description: URL is the OCI registry URL including image name. - type: string - required: - - digest - - url - type: object - rollbackToRevision: - description: |- - RollbackToRevision instructs the wrapper to restore this ClusterPack to the - artifact version deployed at POR revision N-1. When set, the ClusterPackReconciler - reads PreviousClusterPackVersion/PreviousRBACDigest/PreviousWorkloadDigest from - the current POR, patches spec.version and spec.*Digest to those values, removes - the spec-checksum-snapshot annotation, and clears this field. Only one-step - rollback (to revision N-1) is supported per invocation. Set to 0 to disable. - Governor-controlled only. wrapper-schema.md §6.2. seam-core-schema.md §7.8. - format: int64 - type: integer - sourceBuildRef: - description: SourceBuildRef is an opaque reference to the build that - produced this pack. Informational. - type: string - targetClusters: - description: TargetClusters is the list of cluster names to which - this ClusterPack should be delivered. - items: - type: string - type: array - valuesFile: - description: |- - ValuesFile is the path to the values file used during pack compilation. - For Helm packs: the user-supplied values file merged with chart defaults at render time. - For kustomize/raw packs: the overlay or patch file applied during the external build. - Informational -- recorded so admins can trace which customization produced this artifact. - type: string - version: - description: Version is the semantic version of this pack. Immutable - after creation. - type: string - workloadDigest: - description: |- - WorkloadDigest is the OCI digest of the workload layer of this ClusterPack artifact. - Applied after guardian RBACProfile reaches provisioned=true. wrapper-schema.md §4. - type: string - required: - - registryRef - - version - type: object - status: - description: InfrastructureClusterPackStatus is the observed state of - an InfrastructureClusterPack. - properties: - conditions: - description: Conditions is the list of status conditions for this - ClusterPack. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - packSignature: - description: PackSignature is the base64-encoded Ed25519 signature - produced by the management cluster conductor. - type: string - signed: - description: Signed indicates whether the conductor signing loop has - signed this pack. - type: boolean - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_infrastructurelineageindices.yaml b/config/crd/infrastructure.ontai.dev_infrastructurelineageindices.yaml index e4941ef..57421a2 100644 --- a/config/crd/infrastructure.ontai.dev_infrastructurelineageindices.yaml +++ b/config/crd/infrastructure.ontai.dev_infrastructurelineageindices.yaml @@ -1,386 +1,2 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurelineageindices.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureLineageIndex - listKind: InfrastructureLineageIndexList - plural: infrastructurelineageindices - shortNames: - - ili - singular: infrastructurelineageindex - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.rootBinding.rootKind - name: RootKind - type: string - - jsonPath: .spec.rootBinding.rootName - name: RootName - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructureLineageIndex is the sealed causal chain index for a root - declaration in the Seam infrastructure domain. It instantiates the abstract - DomainLineageIndex schema from core.ontai.dev. - - One InfrastructureLineageIndex is created per root declaration by the - InfrastructureLineageController. All derived objects carry a reference to their - root's index; they do not carry their own index instances. - Lineage Index Pattern — seam-core-schema.md §3. - Controller-authored exclusively — CLAUDE.md §14 Decision 3. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: InfrastructureLineageIndexSpec is the spec of an InfrastructureLineageIndex. - properties: - descendantRegistry: - description: |- - DescendantRegistry is the list of all objects derived from the root - declaration. Appended monotonically as new derived objects are created. - Entries are never modified or removed. - items: - description: |- - DescendantEntry records a single derived object in the lineage index. - Entries are appended monotonically. An entry is never modified or removed - except by the retention enforcement loop (which removes stale entries after - the retention window elapses). - properties: - actorRef: - description: |- - ActorRef is the identity propagated from rootBinding.declaringPrincipal. - Every derived object entry carries the initiating human principal from the - root of its causal chain. Immutable. - type: string - createdAt: - description: |- - CreatedAt is the time this descendant entry was appended to the registry. - Used by the retention enforcement loop to determine when a stale entry - (referenced object no longer exists) has exceeded its retention window. - format: date-time - type: string - creationRationale: - allOf: - - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - description: |- - CreationRationale is the reason this derived object was created, drawn from - the Seam Core controlled vocabulary (pkg/lineage.CreationRationale). - type: string - group: - description: Group is the API group of the derived object (e.g., - platform.ontai.dev). - type: string - kind: - description: Kind is the kind of the derived object. - type: string - name: - description: Name is the name of the derived object. - type: string - namespace: - description: Namespace is the namespace of the derived object. - type: string - rootGenerationAtCreation: - description: |- - RootGenerationAtCreation is the metadata.generation of the root declaration - at the time this derived object was created. - format: int64 - type: integer - seamOperator: - description: |- - SeamOperator is the name of the Seam Operator that created this derived - object (e.g., platform, guardian, wrapper, conductor). - type: string - uid: - description: UID is the UID of the derived object. - type: string - version: - description: Version is the API version of the derived object - (e.g., v1alpha1). - type: string - required: - - creationRationale - - group - - kind - - name - - namespace - - rootGenerationAtCreation - - seamOperator - - uid - - version - type: object - type: array - domainRef: - description: |- - DomainRef references the DomainLineageIndex at core.ontai.dev that - this InfrastructureLineageIndex instantiates. This is the formal - traceability link from the infrastructure domain to the domain core. - Format: {name}.{group} — e.g. "infrastructure.core.ontai.dev" - Set by the InfrastructureLineageController on creation. Validated by the - admission webhook: when present, must equal "infrastructure.core.ontai.dev". - type: string - outcomeRegistry: - description: |- - OutcomeRegistry is the append-only registry of terminal outcomes for derived - objects tracked in DescendantRegistry. Entries are appended by LineageController - when a terminal condition is observed on a tracked derived object. Entries are - never modified or removed. An outcomeRegistry entry supersedes but does not - replace its corresponding DescendantRegistry entry. - items: - description: |- - OutcomeEntry records the terminal outcome for a derived object tracked in - DescendantRegistry. Entries are appended by LineageController when a terminal - condition is observed. Entries are never modified or removed. - properties: - derivedObjectUID: - description: DerivedObjectUID is the UID matching a derived - object entry in DescendantRegistry. - type: string - outcomeDetail: - description: |- - OutcomeDetail is a brief human-readable summary of the outcome written by - LineageController from the terminal condition message. Optional. - type: string - outcomeRef: - description: |- - OutcomeRef is the name of the OperationResult ConfigMap or terminal condition - reason that produced this outcome classification. Optional. - type: string - outcomeTimestamp: - description: OutcomeTimestamp is the time when the terminal - condition was observed. - format: date-time - type: string - outcomeType: - description: OutcomeType is the terminal classification of the - derived object lifecycle. - enum: - - Succeeded - - Failed - - Drifted - - Superseded - type: string - required: - - derivedObjectUID - - outcomeTimestamp - - outcomeType - type: object - type: array - policyBindingStatus: - description: |- - PolicyBindingStatus records the InfrastructurePolicy and InfrastructureProfile - bound to the root declaration at last evaluation. - properties: - domainPolicyRef: - description: |- - DomainPolicyRef is the name of the InfrastructurePolicy bound to the root - declaration. - type: string - domainProfileRef: - description: |- - DomainProfileRef is the name of the InfrastructureProfile bound to the - root declaration. - type: string - driftDetected: - description: |- - DriftDetected is true if the controller detected drift between the expected - state derived from the InfrastructurePolicy and the observed state of - derived objects at the last evaluation. - type: boolean - policyGenerationAtLastEvaluation: - description: |- - PolicyGenerationAtLastEvaluation is the metadata.generation of the bound - InfrastructurePolicy at the time of the last policy evaluation cycle. - format: int64 - type: integer - type: object - retentionPolicy: - description: |- - RetentionPolicy declares garbage collection behavior for this index and its - stale descendant entries. If absent, controller defaults apply - (descendantRetentionDays=30, deleteWithRoot=true). - properties: - deleteWithRoot: - default: true - description: |- - DeleteWithRoot controls whether this InfrastructureLineageIndex is garbage - collected when its root declaration is deleted. When true the LineageController - adds an ownerReference from the index to the root declaration, causing - Kubernetes garbage collection to cascade deletion automatically. - - Defaults to true. - type: boolean - descendantRetentionDays: - default: 30 - description: |- - DescendantRetentionDays is the number of days a stale descendant entry is - retained after its referenced object is confirmed not-found in the API server. - After this window elapses the LineageController prunes the entry from the - DescendantRegistry. - - Defaults to 30. Minimum is 1. - format: int32 - minimum: 1 - type: integer - type: object - rootBinding: - description: |- - RootBinding records the root declaration that anchors this lineage index. - Immutable after admission. The admission webhook rejects any update that - modifies a field in this section. - properties: - declaringPrincipal: - description: |- - DeclaringPrincipal is the identity of the human operator or automation - principal that applied the root declaration CR. Stamped by the admission - webhook via annotation infrastructure.ontai.dev/declaring-principal at - CREATE time. Immutable after rootBinding is sealed. - type: string - rootKind: - description: RootKind is the kind of the root declaration (e.g., - TalosCluster, PackExecution). - type: string - rootName: - description: RootName is the name of the root declaration. - type: string - rootNamespace: - description: RootNamespace is the namespace of the root declaration. - type: string - rootObservedGeneration: - description: |- - RootObservedGeneration is the metadata.generation of the root declaration - when this index was created. - format: int64 - type: integer - rootUID: - description: RootUID is the UID of the root declaration at time - of index creation. - type: string - required: - - rootKind - - rootName - - rootNamespace - - rootObservedGeneration - - rootUID - type: object - required: - - rootBinding - type: object - status: - description: |- - InfrastructureLineageIndexStatus is the observed state of an - InfrastructureLineageIndex. - properties: - conditions: - description: Conditions holds the standard Kubernetes condition array - for this resource. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - observedGeneration: - description: |- - ObservedGeneration is the last generation of the InfrastructureLineageIndex - that the controller has processed. - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} +# Tombstone: InfrastructureLineageIndex migrated to LineageRecord under seam.ontai.dev (MIGRATION-3.8). +# See seam.ontai.dev_lineagerecords.yaml. diff --git a/config/crd/infrastructure.ontai.dev_infrastructurepackexecutions.yaml b/config/crd/infrastructure.ontai.dev_infrastructurepackexecutions.yaml deleted file mode 100644 index d691fbb..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructurepackexecutions.yaml +++ /dev/null @@ -1,252 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurepackexecutions.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructurePackExecution - listKind: InfrastructurePackExecutionList - plural: infrastructurepackexecutions - shortNames: - - ipe - singular: infrastructurepackexecution - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.clusterPackRef.name - name: Pack - type: string - - jsonPath: .spec.targetClusterRef - name: Target - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructurePackExecution is the seam-core CRD for a runtime pack delivery request. - wrapper-schema.md §3. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructurePackExecutionSpec defines the desired state of an InfrastructurePackExecution. - wrapper-schema.md §3. - properties: - admissionProfileRef: - description: AdmissionProfileRef is the name of the RBACProfile governing - this execution. - type: string - chartName: - description: ChartName is the Helm chart name. Carried from ClusterPack. - type: string - chartURL: - description: ChartURL is the Helm chart repository URL. Carried from - ClusterPack. - type: string - chartVersion: - description: ChartVersion is the Helm chart version for this execution. - Carried from ClusterPack. - type: string - clusterPackRef: - description: ClusterPackRef identifies the ClusterPack to deploy. - properties: - name: - description: Name is the name of the ClusterPack CR. - minLength: 1 - type: string - version: - description: Version is the expected version of the ClusterPack. - Guards against name reuse. - minLength: 1 - type: string - required: - - name - - version - type: object - helmVersion: - description: HelmVersion is the Helm SDK version used to render the - pack. Carried from ClusterPack. - type: string - lineage: - description: Lineage is the sealed causal chain record for this root - declaration. Immutable after creation. - properties: - creatingOperator: - description: |- - CreatingOperator identifies the Seam Operator that created this object. - This is a structured identity carrying the operator name and its deployed - version at creation time. - properties: - name: - description: |- - Name is the canonical name of the Seam Operator (e.g., platform, guardian, - wrapper, conductor). - type: string - version: - description: |- - Version is the deployed version of the operator at the time the object was - created (e.g., v1.26.5-r3). This allows audit tooling to correlate objects - with the operator version that produced them. - type: string - required: - - name - - version - type: object - creationRationale: - description: |- - CreationRationale is the reason this object was created, drawn from the - Seam Core controlled vocabulary defined in rationale.go. It is not a - free-text field. - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - type: string - rootGenerationAtCreation: - description: |- - RootGenerationAtCreation is the metadata.generation of the root declaration - at the time this object was created. Together with RootUID, it provides a - complete temporal anchor for the derivation record. - format: int64 - type: integer - rootKind: - description: |- - RootKind is the kind of the root declaration that caused this object to - exist (e.g., TalosCluster, PackExecution, RBACPolicy). - type: string - rootName: - description: RootName is the name of the root declaration. - type: string - rootNamespace: - description: RootNamespace is the namespace of the root declaration. - type: string - rootUID: - description: |- - RootUID is the UID of the root declaration at the time this object was - created. Used to verify that no root declaration replacement has occurred. - type: string - required: - - creatingOperator - - creationRationale - - rootGenerationAtCreation - - rootKind - - rootName - - rootNamespace - - rootUID - type: object - targetClusterRef: - description: TargetClusterRef is the name of the target cluster to - deliver the pack to. - type: string - required: - - clusterPackRef - - targetClusterRef - type: object - status: - description: InfrastructurePackExecutionStatus is the observed state of - an InfrastructurePackExecution. - properties: - conditions: - description: Conditions is the list of status conditions for this - PackExecution. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - jobName: - description: JobName is the name of the pack-deploy Kueue Job submitted - for this execution. - type: string - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - operationResultRef: - description: |- - OperationResultRef is the name of the PackOperationResult CR written after - successful pack-deploy Job completion. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_infrastructurepackinstances.yaml b/config/crd/infrastructure.ontai.dev_infrastructurepackinstances.yaml deleted file mode 100644 index 13d6d9a..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructurepackinstances.yaml +++ /dev/null @@ -1,231 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurepackinstances.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructurePackInstance - listKind: InfrastructurePackInstanceList - plural: infrastructurepackinstances - shortNames: - - ipi - singular: infrastructurepackinstance - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.clusterPackRef - name: Pack - type: string - - jsonPath: .spec.targetClusterRef - name: Target - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructurePackInstance is the seam-core CRD recording the delivered state of a pack on a cluster. - wrapper-schema.md §3. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructurePackInstanceSpec defines the desired state of an InfrastructurePackInstance. - wrapper-schema.md §3. - properties: - chartName: - description: ChartName is the Helm chart name. Carried from ClusterPack. - type: string - chartURL: - description: ChartURL is the Helm chart repository URL. Carried from - ClusterPack. - type: string - chartVersion: - description: ChartVersion is the Helm chart version for this instance. - Carried from ClusterPack. - type: string - clusterPackRef: - description: ClusterPackRef is the name of the ClusterPack CR this - instance tracks. - type: string - dependencyPolicy: - description: DependencyPolicy defines behavior when a dependency reports - drift. - properties: - onDrift: - default: Warn - description: |- - OnDrift controls how this PackInstance responds when a declared dependency - PackInstance reports Drifted=True. - enum: - - Block - - Warn - - Ignore - type: string - type: object - dependsOn: - description: DependsOn is the list of pack base names that must be - Delivered before this instance. - items: - type: string - type: array - helmVersion: - description: HelmVersion is the Helm SDK version used to render the - pack. Carried from ClusterPack. - type: string - targetClusterRef: - description: TargetClusterRef is the name of the target cluster this - instance is installed on. - type: string - version: - description: Version is the pack version delivered to the target cluster. - type: string - required: - - clusterPackRef - - targetClusterRef - - version - type: object - status: - description: InfrastructurePackInstanceStatus is the observed state of - an InfrastructurePackInstance. - properties: - conditions: - description: Conditions is the list of status conditions for this - PackInstance. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - deliveredAt: - description: DeliveredAt records when the pack was most recently confirmed - delivered. - format: date-time - type: string - deployedResources: - description: |- - DeployedResources is the list of Kubernetes resources applied by the pack-deploy job. - Used by the PackInstance deletion handler for cleanup. - items: - description: |- - InfrastructureDeployedResourceRef records a single Kubernetes resource applied - by the pack-deploy job. Used by the PackInstance deletion handler to clean up - deployed workload when the ClusterPack is deleted. wrapper-schema.md §3. - properties: - apiVersion: - description: APIVersion is the Kubernetes apiVersion (e.g., - apps/v1, v1). - type: string - kind: - description: Kind is the Kubernetes resource Kind (e.g., Deployment, - Namespace). - type: string - name: - description: Name is the resource name. - type: string - namespace: - description: Namespace is the resource namespace. Empty for - cluster-scoped resources. - type: string - required: - - apiVersion - - kind - - name - type: object - type: array - driftSummary: - description: DriftSummary is a human-readable summary of the current - drift state. - type: string - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - upgradeDirection: - description: |- - UpgradeDirection records the version transition direction for the last deployment. - Initial: first deployment. Upgrade: newer version. Rollback: older version. Redeploy: same version. - enum: - - Initial - - Upgrade - - Rollback - - Redeploy - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_infrastructurepackreceipts.yaml b/config/crd/infrastructure.ontai.dev_infrastructurepackreceipts.yaml deleted file mode 100644 index 5fe1a67..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructurepackreceipts.yaml +++ /dev/null @@ -1,222 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurepackreceipts.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructurePackReceipt - listKind: InfrastructurePackReceiptList - plural: infrastructurepackreceipts - shortNames: - - ipr - singular: infrastructurepackreceipt - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.clusterPackRef - name: Pack - type: string - - jsonPath: .status.verified - name: Verified - type: boolean - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructurePackReceipt is the seam-core CRD for pack delivery acknowledgement on a tenant cluster. - Written by conductor agent after signature verification. INV-026. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructurePackReceiptSpec defines the desired state of an InfrastructurePackReceipt. - Written by the packinstance pull loop on the tenant cluster conductor after - Ed25519 signature verification. INV-026. conductor-schema.md. - properties: - chartName: - description: ChartName is the Helm chart name. Carried from ClusterPack. - type: string - chartURL: - description: ChartURL is the Helm chart repository URL. Carried from - ClusterPack. - type: string - chartVersion: - description: ChartVersion is the Helm chart version. Carried from - ClusterPack. - type: string - clusterPackRef: - description: ClusterPackRef is the name of the ClusterPack CR this - receipt acknowledges. - type: string - deployedResources: - description: |- - DeployedResources is the inventory of Kubernetes resources applied to the tenant cluster - during the pack-deploy Job. Conductor role=tenant uses this list to detect drift by - verifying each resource still exists with the expected state. - CLUSTERPACK-BL-VERSION-CLEANUP, conductor-schema.md. - items: - description: |- - PackReceiptDeployedResource records a single Kubernetes resource that was applied - to the tenant cluster as part of a pack-deploy Job. Used by conductor role=tenant - to detect drift between declared and actual cluster state. - CLUSTERPACK-BL-VERSION-CLEANUP. conductor-schema.md. - properties: - apiVersion: - description: APIVersion is the full API version string (e.g., - "apps/v1"). - type: string - kind: - description: Kind is the resource kind (e.g., "Deployment"). - type: string - name: - description: Name is the resource name. - type: string - namespace: - description: Namespace is the namespace the resource was applied - to. Empty for cluster-scoped resources. - type: string - required: - - apiVersion - - kind - - name - type: object - type: array - helmVersion: - description: HelmVersion is the Helm SDK version. Carried from ClusterPack. - type: string - packInstanceRef: - description: PackInstanceRef is the name of the PackInstance CR this - receipt acknowledges. - type: string - rbacDigest: - description: RBACDigest is the OCI digest of the RBAC layer. Carried - from ClusterPack for audit. - type: string - signatureRef: - description: |- - SignatureRef is the name of the signed artifact Secret on the management cluster - (seam-pack-signed-{cluster}-{packInstance}) from which this receipt was derived. - type: string - targetClusterRef: - description: TargetClusterRef is the name of the cluster this receipt - was generated on. - type: string - workloadDigest: - description: WorkloadDigest is the OCI digest of the workload layer. - Carried from ClusterPack. - type: string - required: - - clusterPackRef - - targetClusterRef - type: object - status: - description: |- - InfrastructurePackReceiptStatus is the observed state of an InfrastructurePackReceipt. - Written by the packinstance pull loop after signature verification. INV-026. - properties: - conditions: - description: Conditions is the list of status conditions for this - PackReceipt. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - signature: - description: |- - Signature is the base64-encoded Ed25519 signature from the signed artifact Secret. - Stored for auditability and idempotency checking. INV-026. - type: string - verificationFailedReason: - description: |- - VerificationFailedReason is set when Verified=false and describes the - specific verification failure (e.g., "Ed25519 signature verification failed (INV-026)"). - type: string - verified: - description: |- - Verified indicates whether the Ed25519 signature on the PackInstance artifact - was successfully verified against the management cluster's public key. INV-026. - type: boolean - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_infrastructurerunnerconfigs.yaml b/config/crd/infrastructure.ontai.dev_infrastructurerunnerconfigs.yaml index 43ea7a5..26cc17e 100644 --- a/config/crd/infrastructure.ontai.dev_infrastructurerunnerconfigs.yaml +++ b/config/crd/infrastructure.ontai.dev_infrastructurerunnerconfigs.yaml @@ -1,323 +1,2 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurerunnerconfigs.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureRunnerConfig - listKind: InfrastructureRunnerConfigList - plural: infrastructurerunnerconfigs - shortNames: - - irc - singular: infrastructurerunnerconfig - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.clusterRef - name: Cluster - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructureRunnerConfig is the seam-core CRD for Conductor agent runtime configuration. - Owned by seam-core; authored exclusively by the platform operator. INV-009. - conductor-schema.md. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructureRunnerConfigSpec is the operator-generated operational contract for a - specific cluster. Generated at runtime by platform using the runner shared library. - Never human-authored. INV-009, INV-010. conductor-schema.md. - properties: - clusterRef: - description: ClusterRef is the name of the TalosCluster this RunnerConfig - is authoritative for. - type: string - maintenanceTargetNodes: - description: MaintenanceTargetNodes is the list of node names that - are the subject of the operation. - items: - type: string - type: array - operationalHistory: - description: OperationalHistory is an append-only record of completed - RunnerConfig executions. - items: - description: |- - RunnerOperationalHistoryEntry is a single append-only audit record describing one - configuration change applied to this RunnerConfig. Never truncated. - properties: - appliedAt: - description: AppliedAt is the time this change was applied. - format: date-time - type: string - appliedBy: - description: AppliedBy identifies who applied the change. - type: string - concern: - description: Concern identifies what aspect of configuration - changed. - type: string - newValue: - description: NewValue is the value after the change. - type: string - previousValue: - description: PreviousValue is the value before the change. Empty - for initial entries. - type: string - required: - - appliedAt - - appliedBy - - concern - - newValue - type: object - type: array - operatorLeaderNode: - description: OperatorLeaderNode is the node hosting the leader pod - of the initiating operator. - type: string - phases: - description: Phases is the ordered list of operational phases for - this cluster's Conductor lifecycle. - items: - description: RunnerPhaseConfig carries per-phase parameters for - the runner's execution context. - properties: - name: - description: Name identifies the phase. - type: string - parameters: - additionalProperties: - type: string - description: Parameters holds phase-specific key-value configuration. - type: object - required: - - name - type: object - type: array - runnerImage: - description: |- - RunnerImage is the fully qualified container image reference for the Conductor agent. - Tag convention: v{talosVersion}-r{revision} stable, dev/dev-rc{N} development. INV-011. - type: string - selfOperation: - description: SelfOperation is true when the Job's execution cluster - and the target cluster are the same. - type: boolean - steps: - description: Steps is the ordered list of execution steps across all - phases. - items: - description: RunnerConfigStep declares one step in a multi-step - operation intent. - properties: - capability: - description: Capability is the named Conductor capability to - invoke for this step. - type: string - dependsOn: - description: DependsOn is the name of a prior step that must - complete before this step begins. - type: string - haltOnFailure: - description: |- - HaltOnFailure controls sequencer behaviour when this step fails. - When true, failure terminates the RunnerConfig with no further steps executing. - type: boolean - name: - description: Name is the unique identifier for this step within - the RunnerConfig. - type: string - parameters: - additionalProperties: - type: string - description: Parameters is the input parameter map passed to - the capability at Job materialisation time. - type: object - required: - - capability - - name - type: object - type: array - required: - - clusterRef - - runnerImage - type: object - status: - description: |- - InfrastructureRunnerConfigStatus is written exclusively by the Conductor agent leader. - CR-INV-006. - properties: - agentLeader: - description: AgentLeader is the pod name of the current Conductor - agent leader. - type: string - agentVersion: - description: AgentVersion is the version string of the Conductor agent - binary currently running. - type: string - capabilities: - description: |- - Capabilities is the self-declared capability manifest emitted by the Conductor agent on startup. - CR-INV-005. - items: - description: RunnerCapabilityEntry is one capability declared by - the Conductor agent on startup. - properties: - description: - description: Description is a human-readable description of - what this capability does. - type: string - name: - description: Name is the capability name (e.g., pack-deploy, - talos-upgrade). - type: string - version: - description: Version is the capability version declared by the - agent. - type: string - required: - - name - - version - type: object - type: array - conditions: - description: Conditions is the standard Kubernetes condition list - for this RunnerConfig. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - failedStep: - description: |- - FailedStep is the name of the first step that reached the Failed phase. - Present only when Phase="Failed". conductor-schema.md §17. - type: string - phase: - description: |- - Phase is the terminal execution phase written by Conductor execute mode. - "Completed" means all steps succeeded. "Failed" means at least one step failed. - Empty means execution is in progress. Platform operators watch this field to - detect terminal conditions without scanning StepResults. conductor-schema.md §17. - type: string - stepResults: - description: StepResults is the ordered list of step result records - written by Conductor execute mode. - items: - description: RunnerConfigStepResult is the status record for one - step. - properties: - completedAt: - description: CompletedAt is the time this step finished execution. - format: date-time - type: string - message: - description: Message is additional context about the step outcome. - type: string - name: - description: Name matches the Name field of the corresponding - RunnerConfigStep in spec. - type: string - startedAt: - description: StartedAt is the time this step began execution. - format: date-time - type: string - status: - allOf: - - enum: - - Succeeded - - Failed - - Skipped - - enum: - - Succeeded - - Failed - - Skipped - description: Status is the terminal status of this step execution. - type: string - required: - - name - - status - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} +# Tombstone: InfrastructureRunnerConfig migrated to RunnerConfig under seam.ontai.dev (MIGRATION-3.8). +# See seam.ontai.dev_runnerconfigs.yaml. diff --git a/config/crd/infrastructure.ontai.dev_infrastructuretalosclusteroperationresults.yaml b/config/crd/infrastructure.ontai.dev_infrastructuretalosclusteroperationresults.yaml deleted file mode 100644 index 755eeaa..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructuretalosclusteroperationresults.yaml +++ /dev/null @@ -1,198 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructuretalosclusteroperationresults.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureTalosClusterOperationResult - listKind: InfrastructureTalosClusterOperationResultList - plural: infrastructuretalosclusteroperationresults - shortNames: - - tcor - singular: infrastructuretalosclusteroperationresult - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.clusterRef - name: Cluster - type: string - - jsonPath: .spec.talosVersion - name: TalosVersion - type: string - - jsonPath: .spec.revision - name: Revision - type: integer - - jsonPath: .spec.operationCount - name: Ops - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructureTalosClusterOperationResult accumulates the day-2 operation history - for one cluster. One CR per cluster, created when the platform operator provisions - the cluster tenant namespace. Operations are appended by the Conductor execute-mode - Job. On talosVersion upgrade, the current revision is archived to the GraphQuery DB - and a new revision epoch begins. - - Named by the cluster name. Lives in seam-tenant-{clusterRef}. - conductor-schema.md §8, seam-core-schema.md §TCOR. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructureTalosClusterOperationResultSpec is the accumulated day-2 operation - history for one cluster, scoped to the current talosVersion revision. - - One CR per cluster. Created by the platform operator when the cluster tenant - namespace is provisioned. Named by the cluster name. Lives in seam-tenant-{clusterRef}. - - When the cluster talosVersion is upgraded, the current revision is archived to - the GraphQuery DB and a new revision begins: Revision increments, TalosVersion - is updated, and Operations is cleared. - - conductor-schema.md §8, seam-core-schema.md §TCOR. - properties: - clusterRef: - description: ClusterRef is the name of the InfrastructureTalosCluster - this result accumulates. - type: string - operationCount: - description: |- - OperationCount is the count of records in Operations for the current revision. - Maintained by the writer alongside Operations so kubectl can display it - as an integer column. Updated atomically with every Operations write. - json tag intentionally omits omitempty so the writer always serializes 0; - the printcolumn then renders "0" rather than blank on zero-operation revisions. - format: int64 - type: integer - operations: - additionalProperties: - description: |- - TalosClusterOperationRecord is a single day-2 operation record within one - talosVersion revision. Multiple records accumulate in the parent TCOR as - operations are performed against the cluster. - properties: - capability: - description: Capability is the conductor capability that produced - this record. - type: string - completedAt: - description: CompletedAt is the time the capability execution - finished. - format: date-time - type: string - failureReason: - description: FailureReason is populated when Status is Failed. - Nil on success. - properties: - category: - description: Category classifies the failure domain. - enum: - - ValidationFailure - - CapabilityUnavailable - - ExecutionFailure - - ExternalDependencyFailure - - InvariantViolation - type: string - reason: - description: Reason is a human-readable description of the - failure. - type: string - required: - - category - - reason - type: object - jobRef: - description: |- - JobRef is the Kubernetes Job name that produced this record. - The platform reconciler uses this to correlate the record with the Job it submitted. - type: string - message: - description: Message provides a human-readable summary of the - outcome. - type: string - startedAt: - description: StartedAt is the time the capability execution - began. - format: date-time - type: string - status: - allOf: - - enum: - - Succeeded - - Failed - - enum: - - Succeeded - - Failed - description: Status is the terminal status of the capability - execution. - type: string - required: - - capability - - jobRef - - status - type: object - description: |- - Operations is the map of day-2 operation records for the current revision, - keyed by Kubernetes Job name (OPERATION_RESULT_CR). Map keying enables - O(1) lookup by the platform reconciler and clean serialization when - archiving the revision to the GraphQuery DB. - type: object - revision: - default: 1 - description: |- - Revision is the monotonic revision counter. Starts at 1. Increments on each - talosVersion upgrade. Each revision holds the operations performed during that - version epoch. Archived revisions are stored in the GraphQuery DB. - format: int64 - type: integer - talosVersion: - description: |- - TalosVersion is the cluster talosVersion for the current active revision. - Matches InfrastructureTalosCluster.spec.talosVersion at the time this revision began. - type: string - required: - - clusterRef - - revision - - talosVersion - type: object - status: - description: |- - InfrastructureTalosClusterOperationResultStatus is the observed state. - Currently empty; reserved for future conditions. - properties: - observedGeneration: - description: ObservedGeneration is the last generation observed by - any consumer. - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_infrastructuretalosclusters.yaml b/config/crd/infrastructure.ontai.dev_infrastructuretalosclusters.yaml deleted file mode 100644 index 76498a4..0000000 --- a/config/crd/infrastructure.ontai.dev_infrastructuretalosclusters.yaml +++ /dev/null @@ -1,393 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructuretalosclusters.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureTalosCluster - listKind: InfrastructureTalosClusterList - plural: infrastructuretalosclusters - shortNames: - - itc - singular: infrastructuretaloscluster - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.mode - name: Mode - type: string - - jsonPath: .spec.role - name: Role - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - InfrastructureTalosCluster is the seam-core CRD for a Talos cluster under Seam governance. - platform-schema.md §4. Decision H. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - InfrastructureTalosClusterSpec is the declared desired state of an InfrastructureTalosCluster. - platform-schema.md §4. - properties: - capi: - description: CAPI holds CAPI integration settings. When absent, the - cluster uses direct bootstrap. - properties: - ciliumPackRef: - description: |- - CiliumPackRef references the cluster-specific Cilium ClusterPack. - Applied as the first pack after the CAPI cluster reaches Running state. - Required when Enabled=true. platform-schema.md §2.3. - properties: - name: - description: Name is the ClusterPack CR name for the Cilium - pack. - type: string - version: - description: Version is the ClusterPack version string. - type: string - required: - - name - - version - type: object - controlPlane: - description: ControlPlane holds control plane configuration. Required - when Enabled=true. - properties: - replicas: - description: Replicas is the desired number of control plane - nodes. - format: int32 - type: integer - type: object - enabled: - description: |- - Enabled determines whether this TalosCluster uses the CAPI path. - True for all target clusters. False for the management cluster. - type: boolean - kubernetesVersion: - description: |- - KubernetesVersion is the Kubernetes version for TalosControlPlane. - Required when Enabled=true. - type: string - talosVersion: - description: |- - TalosVersion is the Talos version to use for TalosConfigTemplate and - CABPT machineconfig generation. Required when Enabled=true. - type: string - workers: - description: Workers is the list of worker node pools. - items: - description: |- - InfrastructureCAPIWorkerPool declares a worker node pool for a CAPI-managed target cluster. - Each pool maps to a MachineDeployment + SeamInfrastructureMachineTemplate. - properties: - name: - description: Name is the pool identifier. Used as the MachineDeployment - name suffix. - type: string - replicas: - description: Replicas is the desired number of worker nodes - in this pool. - format: int32 - type: integer - seamInfrastructureMachineNames: - description: |- - SeamInfrastructureMachineNames lists the SeamInfrastructureMachine CR names - pre-provisioned for this pool. One per node. - items: - type: string - type: array - required: - - name - type: object - type: array - required: - - enabled - type: object - clusterEndpoint: - description: |- - ClusterEndpoint is the cluster VIP or primary API endpoint IP. Required on mode=import. - Optional for bootstrap mode (endpoint derived from bootstrap Job output). - type: string - infrastructureProvider: - allOf: - - enum: - - native - - capi - - screen - - enum: - - native - - capi - - screen - default: native - description: |- - InfrastructureProvider declares the infrastructure provider backing this cluster. - Defaults to native when absent. The only reserved future value is screen (INV-021). - type: string - kubeconfigSecretRef: - description: |- - KubeconfigSecretRef is the name of the Secret containing the kubeconfig for this cluster. - Required on mode=import. Not used when CAPI manages the cluster lifecycle. - type: string - kubernetesVersion: - description: |- - KubernetesVersion is the Kubernetes version for this cluster. Set from - bootstrap.kubernetesVersion or derived automatically from the Talos version - support matrix when not explicitly provided. Informational — upgrade CRs - (UpgradePolicy with UpgradeTypeKubernetes) govern the actual k8s version. - type: string - lineage: - description: Lineage is the sealed causal chain record for this root - declaration. Immutable after creation. - properties: - creatingOperator: - description: |- - CreatingOperator identifies the Seam Operator that created this object. - This is a structured identity carrying the operator name and its deployed - version at creation time. - properties: - name: - description: |- - Name is the canonical name of the Seam Operator (e.g., platform, guardian, - wrapper, conductor). - type: string - version: - description: |- - Version is the deployed version of the operator at the time the object was - created (e.g., v1.26.5-r3). This allows audit tooling to correlate objects - with the operator version that produced them. - type: string - required: - - name - - version - type: object - creationRationale: - description: |- - CreationRationale is the reason this object was created, drawn from the - Seam Core controlled vocabulary defined in rationale.go. It is not a - free-text field. - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - type: string - rootGenerationAtCreation: - description: |- - RootGenerationAtCreation is the metadata.generation of the root declaration - at the time this object was created. Together with RootUID, it provides a - complete temporal anchor for the derivation record. - format: int64 - type: integer - rootKind: - description: |- - RootKind is the kind of the root declaration that caused this object to - exist (e.g., TalosCluster, PackExecution, RBACPolicy). - type: string - rootName: - description: RootName is the name of the root declaration. - type: string - rootNamespace: - description: RootNamespace is the namespace of the root declaration. - type: string - rootUID: - description: |- - RootUID is the UID of the root declaration at the time this object was - created. Used to verify that no root declaration replacement has occurred. - type: string - required: - - creatingOperator - - creationRationale - - rootGenerationAtCreation - - rootKind - - rootName - - rootNamespace - - rootUID - type: object - mode: - allOf: - - enum: - - bootstrap - - import - - enum: - - bootstrap - - import - description: Mode declares whether this cluster is bootstrapped from - scratch or imported. - type: string - nodeAddresses: - description: |- - NodeAddresses is the list of node IPs belonging to this cluster. Used by - DSNSReconciler to populate A records in the seam DNS zone. platform-schema.md §5. - items: - type: string - type: array - role: - allOf: - - enum: - - management - - tenant - - enum: - - management - - tenant - description: Role declares the cluster role in the Seam topology. - Mandatory on mode=import. - type: string - talosVersion: - description: |- - TalosVersion is the Talos OS version for this cluster. Used by Conductor to select - a compatible runner image. INV-012. - type: string - talosconfigSecretRef: - description: TalosconfigSecretRef is the name of the Secret containing - the talosconfig for this cluster. - type: string - versionUpgrade: - description: |- - VersionUpgrade, when set to true, triggers a cluster-level rolling Talos upgrade - to the version declared in spec.talosVersion. The platform reconciler creates an - UpgradePolicy CR automatically and clears this field after the UpgradePolicy is - created. Applicable only to cluster-wide Talos version upgrades — individual node - operations, etcd maintenance, and other day-2 operations are not affected. - For management clusters, the Conductor executor upgrades the leader node last and - the platform operator releases its lease before the leader node reboots. - type: boolean - required: - - mode - type: object - x-kubernetes-validations: - - message: role is required when mode is import - rule: self.mode != 'import' || (has(self.role) && self.role != '') - status: - description: InfrastructureTalosClusterStatus is the observed state of - an InfrastructureTalosCluster. - properties: - capiClusterRef: - description: |- - CAPIClusterRef is a reference to the owned CAPI Cluster object in the tenant - namespace. Only set for CAPI-managed clusters (capi.enabled=true). - properties: - name: - description: Name is the object name. - type: string - namespace: - description: Namespace is the object namespace. May be empty for - cluster-scoped objects. - type: string - required: - - name - type: object - conditions: - description: Conditions is the list of status conditions for this - TalosCluster. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: ObservedGeneration is the generation most recently reconciled. - format: int64 - type: integer - observedTalosVersion: - description: |- - ObservedTalosVersion is the Talos version last confirmed running by a successful - day-2 upgrade operation (UpgradePolicy). The platform reconciler uses this to - prevent spec.talosVersion from regressing the cluster below its current version. - Set after each successful talos-upgrade or stack-upgrade UpgradePolicy. - type: string - origin: - description: Origin records how this cluster came under Seam governance. - enum: - - bootstrapped - - imported - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_packoperationresults.yaml b/config/crd/infrastructure.ontai.dev_packoperationresults.yaml deleted file mode 100644 index 9c7bc3a..0000000 --- a/config/crd/infrastructure.ontai.dev_packoperationresults.yaml +++ /dev/null @@ -1,292 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: packoperationresults.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: PackOperationResult - listKind: PackOperationResultList - plural: packoperationresults - shortNames: - - por - singular: packoperationresult - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.capability - name: Capability - type: string - - jsonPath: .spec.status - name: Status - type: string - - jsonPath: .spec.targetClusterRef - name: Cluster - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - PackOperationResult is the immutable result record written by the Conductor - execute-mode Job after a pack-deploy capability completes. It replaces the - ConfigMap output channel, providing a versioned, richly-typed CR that the - wrapper PackExecutionReconciler reads to advance PackExecution status and - that the lineagesink can consume as additional data. One PackOperationResult - per PackExecution, created in namespace seam-tenant-{clusterName}. - seam-core-schema.md §8, Decision 11. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - PackOperationResultSpec is the complete result document written by the - Conductor execute-mode Job before exit. Written by conductor; read by wrapper. - seam-core-schema.md §8, Decision 11. - properties: - artifacts: - description: Artifacts is the list of artifacts produced by this execution. - items: - description: |- - PackOperationArtifact is a structured reference to an artifact produced - by a pack-deploy execution. Never contains raw artifact content. - properties: - checksum: - description: 'Checksum is the content-addressed checksum. Format: - sha256:.' - type: string - kind: - description: 'Kind declares the artifact type. One of: ConfigMap, - Secret, OCIImage, S3Object.' - enum: - - ConfigMap - - Secret - - OCIImage - - S3Object - type: string - name: - description: Name is a logical identifier for this artifact. - type: string - reference: - description: Reference is the fully qualified reference for - the artifact kind. - type: string - required: - - kind - - name - - reference - type: object - type: array - capability: - description: Capability is the name of the Conductor capability that - produced this result. - type: string - clusterPackRef: - description: ClusterPackRef is the name of the ClusterPack CR that - was deployed. - type: string - clusterPackVersion: - description: |- - ClusterPackVersion is the ClusterPack spec.version deployed in this operation. - Populated by the Conductor executor at write time. Rollback anchor: the wrapper - reads this field from the target POR revision to restore when spec.rollbackToRevision - is set. Superseded PORs are retained with ontai.dev/superseded=true label to - enable N-step rollback. seam-core-schema.md §7.8. - type: string - completedAt: - description: CompletedAt is the time the capability execution finished. - format: date-time - type: string - deployedResources: - description: |- - DeployedResources is the list of Kubernetes resources applied during this - execution. Populated by pack-deploy on success. Used by PackInstanceReconciler - for deletion cleanup. - items: - description: |- - PackOperationDeployedResource records a single Kubernetes resource applied - during a pack-deploy execution. - properties: - apiVersion: - description: APIVersion is the Kubernetes apiVersion (e.g., - apps/v1, v1). - type: string - kind: - description: Kind is the Kubernetes resource Kind (e.g., Deployment, - Namespace). - type: string - name: - description: Name is the resource name. - type: string - namespace: - description: Namespace is the resource namespace. Empty for - cluster-scoped resources. - type: string - required: - - apiVersion - - kind - - name - type: object - type: array - failureReason: - description: FailureReason is populated when Status is Failed. Nil - on success. - properties: - category: - description: Category classifies the failure domain. - enum: - - ValidationFailure - - CapabilityUnavailable - - ExecutionFailure - - ExternalDependencyFailure - - InvariantViolation - - LicenseViolation - - StorageUnavailable - type: string - failedStep: - description: FailedStep is the name of the step that failed. Empty - for single-step capabilities. - type: string - reason: - description: Reason is a human-readable description of the specific - failure. - type: string - required: - - category - - reason - type: object - packExecutionRef: - description: PackExecutionRef is the name of the PackExecution CR - that triggered this operation. - type: string - phase: - description: Phase identifies the RunnerConfig phase this result belongs - to. - type: string - previousRevisionRef: - description: |- - PreviousRevisionRef is the name of the PackOperationResult CR that was deleted when - this revision was written. Enables chain reconstruction for the full operation history. - Absent for revision 1 (no predecessor). - type: string - rbacDigest: - description: |- - RBACDigest is the OCI digest of the RBAC layer deployed in this operation. - Copied from ClusterPack.spec.rbacDigest at deploy time. Rollback anchor. - type: string - revision: - description: |- - Revision is the monotonically increasing revision counter for this pack operation - sequence. Incremented each time a new result supersedes the previous one. The - single-active-revision pattern ensures exactly one PackOperationResult exists per - ClusterPack operation sequence at any time. - format: int64 - type: integer - startedAt: - description: StartedAt is the time the capability execution began. - format: date-time - type: string - status: - allOf: - - enum: - - Succeeded - - Failed - - enum: - - Succeeded - - Failed - description: Status is the terminal status of the capability execution. - type: string - steps: - description: Steps contains individual step results for multi-step - capabilities. - items: - description: |- - PackOperationStepResult is the execution result for one step within a - multi-step capability. - properties: - completedAt: - description: CompletedAt is the time this step finished execution. - format: date-time - type: string - message: - description: Message provides additional context about the step - outcome. - type: string - name: - description: Name is the step identifier within the capability. - type: string - startedAt: - description: StartedAt is the time this step began execution. - format: date-time - type: string - status: - allOf: - - enum: - - Succeeded - - Failed - - enum: - - Succeeded - - Failed - description: Status is the terminal status of this step. - type: string - required: - - name - - status - type: object - type: array - talosClusterOperationResultRef: - description: |- - TalosClusterOperationResultRef is reserved for future cross-reference to a - TalosCluster-scoped OperationResult. Stub field; not populated by any current - controller. - type: string - targetClusterRef: - description: TargetClusterRef is the name of the target cluster this - operation ran against. - type: string - workloadDigest: - description: |- - WorkloadDigest is the OCI digest of the workload layer deployed in this operation. - Copied from ClusterPack.spec.workloadDigest at deploy time. Rollback anchor. - type: string - required: - - capability - - revision - - status - type: object - status: - description: |- - PackOperationResultStatus is the observed state of a PackOperationResult. - Currently empty; reserved for future controller-set conditions. - properties: - observedGeneration: - description: ObservedGeneration is the last generation processed by - any consumer. - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/infrastructure.ontai.dev_seammemberships.yaml b/config/crd/infrastructure.ontai.dev_seammemberships.yaml index 13ce463..860285e 100644 --- a/config/crd/infrastructure.ontai.dev_seammemberships.yaml +++ b/config/crd/infrastructure.ontai.dev_seammemberships.yaml @@ -1,176 +1,2 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: seammemberships.infrastructure.ontai.dev -spec: - group: infrastructure.ontai.dev - names: - kind: SeamMembership - listKind: SeamMembershipList - plural: seammemberships - shortNames: - - sm - singular: seammembership - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.admitted - name: Admitted - type: boolean - - jsonPath: .spec.tier - name: Tier - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - SeamMembership is the formal join declaration for an operator wishing to - become a member of the Seam infrastructure family. Guardian validates and - admits the membership after verifying the operator's RBACProfile. Operators - that are not members may not be allocated PermissionSnapshots. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: SeamMembershipSpec defines the desired state of a SeamMembership. - properties: - appIdentityRef: - description: |- - AppIdentityRef references the operator's application-layer identity. - For Seam family operators this is the operator name (guardian, platform, - wrapper, conductor, seam-core, vortex). - Format: {name} — references an AppIdentity in the domain-core (future) - or the operator's service account name (current). - type: string - domainIdentityRef: - description: |- - DomainIdentityRef references the DomainIdentity at core.ontai.dev - that this operator traces to. Must match the domainIdentityRef on - the operator's RBACProfile. - type: string - principalRef: - description: |- - PrincipalRef is the Kubernetes service account that this operator - runs as. Format: system:serviceaccount:{namespace}:{name} - Must match the principalRef on the operator's RBACProfile. - type: string - tier: - description: |- - Tier declares the membership tier. Valid values: infrastructure, application. - infrastructure: Seam family operators (guardian, platform, wrapper, etc.) - application: Application operators (vortex, future app operators) - enum: - - infrastructure - - application - type: string - required: - - appIdentityRef - - domainIdentityRef - - principalRef - - tier - type: object - status: - description: SeamMembershipStatus defines the observed state of a SeamMembership. - properties: - admitted: - description: Admitted is true when Guardian has validated and admitted - this member. - type: boolean - admittedAt: - description: AdmittedAt is the timestamp when Guardian admitted this - member. - format: date-time - type: string - conditions: - description: Conditions is the list of status conditions for this - SeamMembership. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - permissionSnapshotRef: - description: |- - PermissionSnapshotRef is the name of the PermissionSnapshot Guardian - resolved for this member. Set after admission. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} +# Tombstone: SeamMembership migrated to seam.ontai.dev (MIGRATION-3.8). +# See seam.ontai.dev_seammemberships.yaml. diff --git a/config/crd/infrastructure.ontai.dev_infrastructurepackbuilds.yaml b/config/crd/seam.ontai.dev_driftsignals.yaml similarity index 59% rename from config/crd/infrastructure.ontai.dev_infrastructurepackbuilds.yaml rename to config/crd/seam.ontai.dev_driftsignals.yaml index 94281d1..cbb31ef 100644 --- a/config/crd/infrastructure.ontai.dev_infrastructurepackbuilds.yaml +++ b/config/crd/seam.ontai.dev_driftsignals.yaml @@ -4,21 +4,24 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.1 - name: infrastructurepackbuilds.infrastructure.ontai.dev + name: driftsignals.seam.ontai.dev spec: - group: infrastructure.ontai.dev + group: seam.ontai.dev names: - kind: InfrastructurePackBuild - listKind: InfrastructurePackBuildList - plural: infrastructurepackbuilds + kind: DriftSignal + listKind: DriftSignalList + plural: driftsignals shortNames: - - ipb - singular: infrastructurepackbuild + - ds + singular: driftsignal scope: Namespaced versions: - additionalPrinterColumns: - - jsonPath: .spec.category - name: Category + - jsonPath: .spec.state + name: State + type: string + - jsonPath: .spec.correlationID + name: CorrelationID type: string - jsonPath: .metadata.creationTimestamp name: Age @@ -27,9 +30,11 @@ spec: schema: openAPIV3Schema: description: |- - InfrastructurePackBuild is the seam-core CRD for compiler input specification. - Compiler reads this at compile time; never applied to a cluster as a live CR. - conductor-schema.md §7. + DriftSignal is the seam-core CRD for the three-state drift acknowledgement chain. + Written by conductor role=tenant; acknowledged by conductor role=management. + Decision I. At-least-once delivery. Human-at-Boundary invariant enforced via + configurable escalation threshold and TerminalDrift Condition. conductor-schema.md. + Migrated from infrastructure.ontai.dev to seam.ontai.dev (MIGRATION-3.8). properties: apiVersion: description: |- @@ -50,85 +55,87 @@ spec: type: object spec: description: |- - InfrastructurePackBuildSpec defines the desired state of an InfrastructurePackBuild. - Compiler input specification. Read by the Compiler at compile time; never applied to a cluster as a CR. - conductor-schema.md §7. + DriftSignalSpec defines the observed drift event written by conductor role=tenant. + Decision I. conductor-schema.md. properties: - category: - allOf: - - enum: - - helm - - kustomize - - raw - - enum: - - helm - - kustomize - - raw - description: 'Category declares the compilation category. Must be - one of: helm, kustomize, raw.' - type: string - componentName: - description: ComponentName is the name of the component being compiled. - type: string - helmSource: - description: HelmSource describes the Helm chart source. Required - when category=helm. + affectedCRRef: + description: AffectedCRRef is a typed reference to the CR that exhibited + drift. properties: - chart: - description: Chart is the chart name used for rendering context. + group: + description: Group is the API group of the drifted CR. type: string - url: - description: URL is the full URL to the Helm chart tarball (.tgz). + kind: + description: Kind is the Kind of the drifted CR. type: string - valuesFile: - description: ValuesFile is the path to a YAML values file. Optional. + name: + description: Name is the name of the drifted CR. type: string - version: - description: Version is the chart version string. + namespace: + description: Namespace is the namespace of the drifted CR. Empty + for cluster-scoped resources. type: string required: - - chart - - url - - version + - group + - kind + - name type: object - kustomizeSource: - description: KustomizeSource describes the Kustomize source. Required - when category=kustomize. - properties: - path: - description: Path is the path to the kustomization root directory. - type: string - required: - - path - type: object - rawSource: - description: RawSource describes the raw manifest source. Required - when category=raw. - properties: - path: - description: Path is the path to the directory containing raw - YAML manifests. - type: string - required: - - path - type: object - targetClusters: - description: TargetClusters is the list of cluster names to which - the compiled pack should be delivered. - items: - type: string - type: array + correctionJobRef: + description: |- + CorrectionJobRef is the name of the corrective Job created by the management cluster. + Populated when state transitions to queued. + type: string + correlationID: + description: |- + CorrelationID is a unique identifier for this drift event, used to deduplicate + signals across federation retries. Format: UUID v4. + type: string + driftReason: + description: DriftReason is a human-readable description of why drift + was detected. + type: string + escalationCounter: + description: |- + EscalationCounter is the number of times this signal has been re-emitted without + acknowledgement. Incremented by conductor role=tenant on each re-emit cycle. + When this counter reaches the configurable escalation threshold, conductor writes a + type=TerminalDrift Condition on the affected CR and stops re-emitting. Decision I. + format: int32 + type: integer + observedAt: + description: ObservedAt is the time the drift was first observed by + conductor role=tenant. + format: date-time + type: string + state: + allOf: + - enum: + - pending + - delivered + - queued + - confirmed + - enum: + - pending + - delivered + - queued + - confirmed + description: State is the current acknowledgement state of this drift + signal. Decision I. + type: string required: - - category - - componentName + - affectedCRRef + - correlationID + - driftReason + - observedAt + - state type: object status: - description: InfrastructurePackBuildStatus is the observed state of an - InfrastructurePackBuild. + description: DriftSignalStatus is the observed state of a DriftSignal. + Written by conductor role=management. properties: conditions: description: Conditions is the list of status conditions for this - PackBuild. + DriftSignal. items: description: Condition contains details for one aspect of the current state of this API Resource. diff --git a/config/crd/seam.ontai.dev_lineagerecords.yaml b/config/crd/seam.ontai.dev_lineagerecords.yaml new file mode 100644 index 0000000..ccddd35 --- /dev/null +++ b/config/crd/seam.ontai.dev_lineagerecords.yaml @@ -0,0 +1,377 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: lineagerecords.seam.ontai.dev +spec: + group: seam.ontai.dev + names: + kind: LineageRecord + listKind: LineageRecordList + plural: lineagerecords + shortNames: + - lr + singular: lineagerecord + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.rootBinding.rootKind + name: RootKind + type: string + - jsonPath: .spec.rootBinding.rootName + name: RootName + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + LineageRecord is the sealed causal chain index for a root declaration in the + Seam infrastructure domain. Renamed from InfrastructureLineageIndex (MIGRATION-3.8). + + One LineageRecord is created per root declaration by the LineageController. + All derived objects carry a reference to their root's record; they do not carry + their own record instances. Controller-authored exclusively -- CLAUDE.md Decision 3. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: LineageRecordSpec is the spec of a LineageRecord. + properties: + descendantRegistry: + description: |- + DescendantRegistry is the list of all objects derived from the root + declaration. Appended monotonically as new derived objects are created. + Entries are never modified or removed. + items: + description: |- + DescendantEntry records a single derived object in the lineage record. + Entries are appended monotonically. An entry is never modified or removed + except by the retention enforcement loop (which removes stale entries after + the retention window elapses). + properties: + actorRef: + description: |- + ActorRef is the identity propagated from rootBinding.declaringPrincipal. + Every derived object entry carries the initiating human principal from the + root of its causal chain. Immutable. + type: string + createdAt: + description: |- + CreatedAt is the time this descendant entry was appended to the registry. + Used by the retention enforcement loop to determine when a stale entry + (referenced object no longer exists) has exceeded its retention window. + format: date-time + type: string + creationRationale: + allOf: + - enum: + - ClusterProvision + - ClusterDecommission + - SecurityEnforcement + - PackExecution + - VirtualizationFulfillment + - ConductorAssignment + - VortexBinding + - enum: + - ClusterProvision + - ClusterDecommission + - SecurityEnforcement + - PackExecution + - VirtualizationFulfillment + - ConductorAssignment + - VortexBinding + description: |- + CreationRationale is the reason this derived object was created, drawn from + the Seam Core controlled vocabulary (pkg/lineage.CreationRationale). + type: string + group: + description: Group is the API group of the derived object (e.g., + platform.ontai.dev). + type: string + kind: + description: Kind is the kind of the derived object. + type: string + name: + description: Name is the name of the derived object. + type: string + namespace: + description: Namespace is the namespace of the derived object. + type: string + rootGenerationAtCreation: + description: |- + RootGenerationAtCreation is the metadata.generation of the root declaration + at the time this derived object was created. + format: int64 + type: integer + seamOperator: + description: |- + SeamOperator is the name of the Seam Operator that created this derived + object (e.g., platform, guardian, wrapper, conductor). + type: string + uid: + description: UID is the UID of the derived object. + type: string + version: + description: Version is the API version of the derived object + (e.g., v1alpha1). + type: string + required: + - creationRationale + - group + - kind + - name + - namespace + - rootGenerationAtCreation + - seamOperator + - uid + - version + type: object + type: array + domainRef: + description: |- + DomainRef references the DomainLineageIndex at core.ontai.dev that + this LineageRecord instantiates. This is the formal traceability link + from the infrastructure domain to the domain core. + Format: {name}.{group} -- e.g. "infrastructure.core.ontai.dev" + Set by the LineageController on creation. Validated by the + admission webhook: when present, must equal "infrastructure.core.ontai.dev". + type: string + outcomeRegistry: + description: |- + OutcomeRegistry is the append-only registry of terminal outcomes for derived + objects tracked in DescendantRegistry. Entries are appended by LineageController + when a terminal condition is observed on a tracked derived object. Entries are + never modified or removed. An outcomeRegistry entry supersedes but does not + replace its corresponding DescendantRegistry entry. + items: + description: |- + OutcomeEntry records the terminal outcome for a derived object tracked in + DescendantRegistry. Entries are appended by LineageController when a terminal + condition is observed. Entries are never modified or removed. + properties: + derivedObjectUID: + description: DerivedObjectUID is the UID matching a derived + object entry in DescendantRegistry. + type: string + outcomeDetail: + description: |- + OutcomeDetail is a brief human-readable summary of the outcome written by + LineageController from the terminal condition message. Optional. + type: string + outcomeRef: + description: |- + OutcomeRef is the name of the OperationResult ConfigMap or terminal condition + reason that produced this outcome classification. Optional. + type: string + outcomeTimestamp: + description: OutcomeTimestamp is the time when the terminal + condition was observed. + format: date-time + type: string + outcomeType: + description: OutcomeType is the terminal classification of the + derived object lifecycle. + enum: + - Succeeded + - Failed + - Drifted + - Superseded + type: string + required: + - derivedObjectUID + - outcomeTimestamp + - outcomeType + type: object + type: array + policyBindingStatus: + description: |- + PolicyBindingStatus records the InfrastructurePolicy and InfrastructureProfile + bound to the root declaration at last evaluation. + properties: + domainPolicyRef: + description: |- + DomainPolicyRef is the name of the InfrastructurePolicy bound to the root + declaration. + type: string + domainProfileRef: + description: |- + DomainProfileRef is the name of the InfrastructureProfile bound to the + root declaration. + type: string + driftDetected: + description: |- + DriftDetected is true if the controller detected drift between the expected + state derived from the InfrastructurePolicy and the observed state of + derived objects at the last evaluation. + type: boolean + policyGenerationAtLastEvaluation: + description: |- + PolicyGenerationAtLastEvaluation is the metadata.generation of the bound + InfrastructurePolicy at the time of the last policy evaluation cycle. + format: int64 + type: integer + type: object + retentionPolicy: + description: |- + RetentionPolicy declares garbage collection behavior for this record and its + stale descendant entries. If absent, controller defaults apply + (descendantRetentionDays=30, deleteWithRoot=true). + properties: + deleteWithRoot: + default: true + description: |- + DeleteWithRoot controls whether this LineageRecord is garbage collected when + its root declaration is deleted. When true the LineageController adds an + ownerReference from the record to the root declaration, causing Kubernetes + garbage collection to cascade deletion automatically. Defaults to true. + type: boolean + descendantRetentionDays: + default: 30 + description: |- + DescendantRetentionDays is the number of days a stale descendant entry is + retained after its referenced object is confirmed not-found in the API server. + After this window elapses the LineageController prunes the entry from the + DescendantRegistry. Defaults to 30. Minimum is 1. + format: int32 + minimum: 1 + type: integer + type: object + rootBinding: + description: |- + RootBinding records the root declaration that anchors this lineage record. + Immutable after admission. The admission webhook rejects any update that + modifies a field in this section. + properties: + declaringPrincipal: + description: |- + DeclaringPrincipal is the identity of the human operator or automation + principal that applied the root declaration CR. Stamped by the admission + webhook via annotation infrastructure.ontai.dev/declaring-principal at + CREATE time. Immutable after rootBinding is sealed. + type: string + rootKind: + description: RootKind is the kind of the root declaration (e.g., + TalosCluster, PackExecution). + type: string + rootName: + description: RootName is the name of the root declaration. + type: string + rootNamespace: + description: RootNamespace is the namespace of the root declaration. + type: string + rootObservedGeneration: + description: |- + RootObservedGeneration is the metadata.generation of the root declaration + when this record was created. + format: int64 + type: integer + rootUID: + description: RootUID is the UID of the root declaration at time + of record creation. + type: string + required: + - rootKind + - rootName + - rootNamespace + - rootObservedGeneration + - rootUID + type: object + required: + - rootBinding + type: object + status: + description: LineageRecordStatus is the observed state of a LineageRecord. + properties: + conditions: + description: Conditions holds the standard Kubernetes condition array + for this resource. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + description: |- + ObservedGeneration is the last generation of the LineageRecord that the + controller has processed. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/seam.ontai.dev_runnerconfigs.yaml b/config/crd/seam.ontai.dev_runnerconfigs.yaml new file mode 100644 index 0000000..094bf6e --- /dev/null +++ b/config/crd/seam.ontai.dev_runnerconfigs.yaml @@ -0,0 +1,323 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: runnerconfigs.seam.ontai.dev +spec: + group: seam.ontai.dev + names: + kind: RunnerConfig + listKind: RunnerConfigList + plural: runnerconfigs + shortNames: + - rc + singular: runnerconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.clusterRef + name: Cluster + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + RunnerConfig is the seam-core CRD for Conductor agent runtime configuration. + Owned by seam-core; authored exclusively by the platform operator. INV-009. + conductor-schema.md. MIGRATION-3.8. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + RunnerConfigSpec is the operator-generated operational contract for a + specific cluster. Generated at runtime by platform using the runner shared library. + Never human-authored. INV-009, INV-010. conductor-schema.md. + properties: + clusterRef: + description: ClusterRef is the name of the TalosCluster this RunnerConfig + is authoritative for. + type: string + maintenanceTargetNodes: + description: MaintenanceTargetNodes is the list of node names that + are the subject of the operation. + items: + type: string + type: array + operationalHistory: + description: OperationalHistory is an append-only record of completed + RunnerConfig executions. + items: + description: |- + RunnerOperationalHistoryEntry is a single append-only audit record describing one + configuration change applied to this RunnerConfig. Never truncated. + properties: + appliedAt: + description: AppliedAt is the time this change was applied. + format: date-time + type: string + appliedBy: + description: AppliedBy identifies who applied the change. + type: string + concern: + description: Concern identifies what aspect of configuration + changed. + type: string + newValue: + description: NewValue is the value after the change. + type: string + previousValue: + description: PreviousValue is the value before the change. Empty + for initial entries. + type: string + required: + - appliedAt + - appliedBy + - concern + - newValue + type: object + type: array + operatorLeaderNode: + description: OperatorLeaderNode is the node hosting the leader pod + of the initiating operator. + type: string + phases: + description: Phases is the ordered list of operational phases for + this cluster's Conductor lifecycle. + items: + description: RunnerPhaseConfig carries per-phase parameters for + the runner's execution context. + properties: + name: + description: Name identifies the phase. + type: string + parameters: + additionalProperties: + type: string + description: Parameters holds phase-specific key-value configuration. + type: object + required: + - name + type: object + type: array + runnerImage: + description: |- + RunnerImage is the fully qualified container image reference for the Conductor agent. + Tag convention: v{talosVersion}-r{revision} stable, dev/dev-rc{N} development. INV-011. + type: string + selfOperation: + description: SelfOperation is true when the Job's execution cluster + and the target cluster are the same. + type: boolean + steps: + description: Steps is the ordered list of execution steps across all + phases. + items: + description: RunnerConfigStep declares one step in a multi-step + operation intent. + properties: + capability: + description: Capability is the named Conductor capability to + invoke for this step. + type: string + dependsOn: + description: DependsOn is the name of a prior step that must + complete before this step begins. + type: string + haltOnFailure: + description: |- + HaltOnFailure controls sequencer behaviour when this step fails. + When true, failure terminates the RunnerConfig with no further steps executing. + type: boolean + name: + description: Name is the unique identifier for this step within + the RunnerConfig. + type: string + parameters: + additionalProperties: + type: string + description: Parameters is the input parameter map passed to + the capability at Job materialisation time. + type: object + required: + - capability + - name + type: object + type: array + required: + - clusterRef + - runnerImage + type: object + status: + description: |- + RunnerConfigStatus is written exclusively by the Conductor agent leader. + CR-INV-006. + properties: + agentLeader: + description: AgentLeader is the pod name of the current Conductor + agent leader. + type: string + agentVersion: + description: AgentVersion is the version string of the Conductor agent + binary currently running. + type: string + capabilities: + description: |- + Capabilities is the self-declared capability manifest emitted by the Conductor agent on startup. + CR-INV-005. + items: + description: RunnerCapabilityEntry is one capability declared by + the Conductor agent on startup. + properties: + description: + description: Description is a human-readable description of + what this capability does. + type: string + name: + description: Name is the capability name (e.g., pack-deploy, + talos-upgrade). + type: string + version: + description: Version is the capability version declared by the + agent. + type: string + required: + - name + - version + type: object + type: array + conditions: + description: Conditions is the standard Kubernetes condition list + for this RunnerConfig. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + failedStep: + description: |- + FailedStep is the name of the first step that reached the Failed phase. + Present only when Phase="Failed". conductor-schema.md §17. + type: string + phase: + description: |- + Phase is the terminal execution phase written by Conductor execute mode. + "Completed" means all steps succeeded. "Failed" means at least one step failed. + Empty means execution is in progress. Platform operators watch this field to + detect terminal conditions without scanning StepResults. conductor-schema.md §17. + type: string + stepResults: + description: StepResults is the ordered list of step result records + written by Conductor execute mode. + items: + description: RunnerConfigStepResult is the status record for one + step. + properties: + completedAt: + description: CompletedAt is the time this step finished execution. + format: date-time + type: string + message: + description: Message is additional context about the step outcome. + type: string + name: + description: Name matches the Name field of the corresponding + RunnerConfigStep in spec. + type: string + startedAt: + description: StartedAt is the time this step began execution. + format: date-time + type: string + status: + allOf: + - enum: + - Succeeded + - Failed + - Skipped + - enum: + - Succeeded + - Failed + - Skipped + description: Status is the terminal status of this step execution. + type: string + required: + - name + - status + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/seam.ontai.dev_seammemberships.yaml b/config/crd/seam.ontai.dev_seammemberships.yaml new file mode 100644 index 0000000..9888e61 --- /dev/null +++ b/config/crd/seam.ontai.dev_seammemberships.yaml @@ -0,0 +1,177 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: seammemberships.seam.ontai.dev +spec: + group: seam.ontai.dev + names: + kind: SeamMembership + listKind: SeamMembershipList + plural: seammemberships + shortNames: + - sm + singular: seammembership + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.admitted + name: Admitted + type: boolean + - jsonPath: .spec.tier + name: Tier + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + SeamMembership is the formal join declaration for an operator wishing to + become a member of the Seam infrastructure family. Guardian validates and + admits the membership after verifying the operator's RBACProfile. Operators + that are not members may not be allocated PermissionSnapshots. + Migrated from infrastructure.ontai.dev to seam.ontai.dev (MIGRATION-3.8). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: SeamMembershipSpec defines the desired state of a SeamMembership. + properties: + appIdentityRef: + description: |- + AppIdentityRef references the operator's application-layer identity. + For Seam family operators this is the operator name (guardian, platform, + wrapper, conductor, seam-core, vortex). + Format: {name} -- references an AppIdentity in the domain-core (future) + or the operator's service account name (current). + type: string + domainIdentityRef: + description: |- + DomainIdentityRef references the DomainIdentity at core.ontai.dev + that this operator traces to. Must match the domainIdentityRef on + the operator's RBACProfile. + type: string + principalRef: + description: |- + PrincipalRef is the Kubernetes service account that this operator + runs as. Format: system:serviceaccount:{namespace}:{name} + Must match the principalRef on the operator's RBACProfile. + type: string + tier: + description: |- + Tier declares the membership tier. Valid values: infrastructure, application. + infrastructure: Seam family operators (guardian, platform, wrapper, etc.) + application: Application operators (vortex, future app operators) + enum: + - infrastructure + - application + type: string + required: + - appIdentityRef + - domainIdentityRef + - principalRef + - tier + type: object + status: + description: SeamMembershipStatus defines the observed state of a SeamMembership. + properties: + admitted: + description: Admitted is true when Guardian has validated and admitted + this member. + type: boolean + admittedAt: + description: AdmittedAt is the timestamp when Guardian admitted this + member. + format: date-time + type: string + conditions: + description: Conditions is the list of status conditions for this + SeamMembership. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + permissionSnapshotRef: + description: |- + PermissionSnapshotRef is the name of the PermissionSnapshot Guardian + resolved for this member. Set after admission. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/docs/seam-core-schema.md b/docs/seam-core-schema.md index d2f2f58..184cdc0 100644 --- a/docs/seam-core-schema.md +++ b/docs/seam-core-schema.md @@ -1,1014 +1 @@ -# seam-core-schema -> API Group: infrastructure.ontai.dev -> Repository: seam-core -> Layer: Seam Core - infrastructure domain instantiation of core.ontai.dev -> All agents read this before touching any seam-core CRD or shared library type. - ---- - -## 1. Domain Boundary - -Seam Core is the CRD registry for the Seam platform. It owns cross-operator CRD -definitions that no single operator owns. No reconciliation logic lives here. -No capability engine lives here. Seam Core installs CRD definitions and runs -three controllers: LineageReconciler, DescendantReconciler, and DSNSReconciler. - -**SC-INV-001** - seam-core owns all cross-operator CRD definitions. Reconcilers live in the operator repo. -**SC-INV-002** - Phase 2B migration complete (2026-04-25). All types migrated to infrastructure.ontai.dev. Old groups runner.ontai.dev and infra.ontai.dev are superseded. -**SC-INV-003** - seam-core installs before all operators. - ---- - -## 2. Master GVK Reference - -All types below are under `infrastructure.ontai.dev / v1alpha1`. - -| Kind | Resource (plural) | Short | Scope | Authoring operator | Reconciling operator | Migrated from | -|-----------------------------|-------------------------------------|-------|------------|---------------------|----------------------|----------------------------| -| InfrastructureLineageIndex | infrastructurelineageindices | ili | Namespaced | seam-core (LC) | seam-core (LC) | -- | -| InfrastructureRunnerConfig | infrastructurerunnerconfigs | irc | Namespaced | platform | conductor (agent/exec)| runner.ontai.dev/RunnerConfig | -| InfrastructureTalosCluster | infrastructuretalosclusters | itc | Namespaced | human / GitOps | platform | platform.ontai.dev/TalosCluster | -| InfrastructureClusterPack | infrastructureclusterpacks | icp | Namespaced | human / GitOps | wrapper | infra.ontai.dev/ClusterPack | -| InfrastructurePackExecution | infrastructurepackexecutions | ipe | Namespaced | human / GitOps | wrapper | infra.ontai.dev/PackExecution | -| InfrastructurePackInstance | infrastructurepackinstances | ipi | Namespaced | wrapper | wrapper | infra.ontai.dev/PackInstance | -| InfrastructurePackBuild | infrastructurepackbuilds | ipb | Namespaced | human / GitOps | compiler (offline) | infra.ontai.dev/PackBuild | -| InfrastructurePackReceipt | infrastructurepackreceipts | ipr | Namespaced | conductor (agent) | conductor (agent) | runner.ontai.dev/PackReceipt | -| PackOperationResult | packoperationresults | por | Namespaced | conductor (execute) | wrapper (reader) | -- | -| DriftSignal | driftsignals | ds | Namespaced | conductor (tenant) | conductor (mgmt) | -- | -| SeamMembership | seammemberships | sm | Namespaced | human / GitOps | guardian | -- | - -**ILI naming convention:** `strings.ToLower(kind) + "-" + name` -Examples: `infrastructuretaloscluster-ccs-mgmt`, `infrastructurepackexecution-exec-001` - -**CAPI types** (separate API group, not owned by seam-core): - -| Kind | Group | Reconciling operator | -|---------------------------------|------------------------------------|----------------------| -| SeamInfrastructureCluster | infrastructure.cluster.x-k8s.io | platform (CAPI) | -| SeamInfrastructureMachine | infrastructure.cluster.x-k8s.io | platform (CAPI) | -| SeamInfrastructureMachineTemplate | infrastructure.cluster.x-k8s.io | platform (CAPI) | - -**Seam-core controller GVK watch lists** (determines which GVKs cause reconciler invocations): - -- `RootDeclarationGVKs` (LineageReconciler): InfrastructureTalosCluster, InfrastructureClusterPack, InfrastructurePackExecution, InfrastructurePackInstance, RBACPolicy, RBACProfile, IdentityBinding, IdentityProvider, PermissionSet -- `DerivedObjectGVKs` (DescendantReconciler): InfrastructureRunnerConfig, InfrastructurePackInstance -- `DSNSGVKs` (DSNSReconciler): InfrastructureTalosCluster, InfrastructurePackInstance, IdentityBinding, IdentityProvider, InfrastructureRunnerConfig - ---- - -## 3. InfrastructureLineageIndex - -### 3.1 Purpose - -`InfrastructureLineageIndex` is the concrete sealed causal chain index for all -objects managed by the Seam platform in the infrastructure domain. One instance -is created per root declaration (TalosCluster, PackExecution, etc.) by the -LineageReconciler. All derived objects carry a reference to their root -declaration's `InfrastructureLineageIndex`. They do not carry their own index -instances. - -The index grows monotonically as new derived objects are created. Entries in -`spec.descendantRegistry` are never modified or removed. - -### 3.2 CRD Stub - -``` -# STUB - infrastructure.ontai.dev/v1alpha1 InfrastructureLineageIndex -# Seam Core infrastructure domain instantiation of core.ontai.dev DomainLineageIndex. -# controller-gen not yet wired for seam-core. Hand-authored stub pending wiring. ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: infrastructurelineageindices.infrastructure.ontai.dev - annotations: - ontai.dev/layer: "seam-core" - ontai.dev/status: "stub" - ontai.dev/instantiates: "core.ontai.dev/DomainLineageIndex" -spec: - group: infrastructure.ontai.dev - names: - kind: InfrastructureLineageIndex - listKind: InfrastructureLineageIndexList - plural: infrastructurelineageindices - singular: infrastructurelineageindex - shortNames: - - ili - scope: Namespaced - versions: - - name: v1alpha1 - served: true - storage: true - subresources: - status: {} - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - required: [rootBinding] - properties: - rootBinding: - type: object - description: > - Identifies the root declaration that anchors this lineage index. - Immutable after creation. Admission webhook rejects any update - that modifies a field in this section. - required: [rootKind, rootName, rootNamespace, rootUID, rootObservedGeneration] - properties: - rootKind: - type: string - rootName: - type: string - rootNamespace: - type: string - rootUID: - type: string - rootObservedGeneration: - type: integer - format: int64 - declaringPrincipal: - type: string - description: > - Identity of the human operator or automation principal that - applied the root declaration CR. Stamped by the admission - webhook via annotation infrastructure.ontai.dev/declaring-principal - at object creation time. Read by LineageController when creating - the ILI. Immutable after rootBinding is sealed. - descendantRegistry: - type: array - description: > - Registry of all objects derived from the root declaration. - Appended monotonically. Entries are never modified or removed. - items: - type: object - required: [kind, name, namespace, uid, seamOperator, creationRationale, rootGenerationAtCreation] - properties: - kind: - type: string - name: - type: string - namespace: - type: string - uid: - type: string - seamOperator: - type: string - description: Name of the Seam Operator that created this derived object. - creationRationale: - type: string - description: > - Reason this derived object was created. Constrained to - the pkg/lineage.CreationRationale enumeration. - enum: - - ClusterProvision - - ClusterDecommission - - SecurityEnforcement - - PackExecution - - VirtualizationFulfillment - - ConductorAssignment - - VortexBinding - rootGenerationAtCreation: - type: integer - format: int64 - createdAt: - type: string - format: date-time - description: > - Timestamp when DescendantReconciler appended this entry. - Set to the reconciler's current time at append. Immutable. - actorRef: - type: string - description: > - Identity propagated from rootBinding.declaringPrincipal. - Every derived object entry carries the initiating human - principal from the root of its causal chain. Immutable. - policyBindingStatus: - type: object - description: > - Records the InfrastructurePolicy and InfrastructureProfile - bound to the root declaration at last evaluation. - properties: - domainPolicyRef: - type: string - description: Name of the InfrastructurePolicy bound to the root declaration. - domainProfileRef: - type: string - description: Name of the InfrastructureProfile bound to the root declaration. - policyGenerationAtLastEvaluation: - type: integer - format: int64 - description: Generation of the InfrastructurePolicy at last evaluation. - driftDetected: - type: boolean - description: True if drift detected between expected and observed state. - outcomeRegistry: - type: array - description: > - Append-only registry of terminal outcomes for derived objects - tracked in descendantRegistry. Entries are appended by - LineageController when a terminal condition is observed on a - tracked derived object. Entries are never modified or removed. - items: - type: object - required: [derivedObjectUID, outcomeType, outcomeTimestamp] - properties: - derivedObjectUID: - type: string - description: UID matching a derivedObject entry in descendantRegistry. - outcomeType: - type: string - enum: [Succeeded, Failed, Drifted, Superseded] - description: Terminal classification of the derived object lifecycle. - outcomeTimestamp: - type: string - format: date-time - description: Time when the terminal condition was observed. - outcomeRef: - type: string - description: > - Name of the OperationResult ConfigMap or terminal condition - reason that produced this outcome classification. Optional. - outcomeDetail: - type: string - description: > - Brief human-readable summary of the outcome. Written by - LineageController from the terminal condition message. - Optional. - status: - type: object - properties: - conditions: - type: array - items: - type: object - observedGeneration: - type: integer - format: int64 -``` - -### 3.3 Field Reference - -#### spec.rootBinding (immutable after admission) - -| Field | Type | Required | Description | -|------------------------|--------|----------|---------------------------------------------------------------------------------------| -| rootKind | string | yes | Kind of the root declaration | -| rootName | string | yes | Name of the root declaration | -| rootNamespace | string | yes | Namespace of the root declaration | -| rootUID | string | yes | UID of the root declaration at index creation time | -| rootObservedGeneration | int64 | yes | Root declaration generation when this index was created | -| declaringPrincipal | string | no | Identity of the principal that applied the root declaration CR. Stamped at CREATE time. Immutable. | - -#### spec.descendantRegistry[] - -| Field | Type | Required | Description | -|--------------------------|-----------|----------|------------------------------------------------------------------------| -| group | string | yes | API group of the derived object | -| version | string | yes | API version of the derived object | -| kind | string | yes | Kind of the derived object | -| name | string | yes | Name of the derived object | -| namespace | string | yes | Namespace of the derived object | -| uid | string | yes | UID of the derived object | -| seamOperator | string | yes | Seam Operator that created this derived object | -| creationRationale | string | yes | Value from `pkg/lineage.CreationRationale` enum | -| rootGenerationAtCreation | int64 | yes | Root declaration generation when derived object was created | -| createdAt | date-time | no | Timestamp when DescendantReconciler appended this entry. Immutable. | -| actorRef | string | no | Identity propagated from rootBinding.declaringPrincipal. Immutable. | - -#### spec.policyBindingStatus - -| Field | Type | Required | Description | -|----------------------------------|---------|----------|----------------------------------------------------------------------| -| domainPolicyRef | string | no | Name of the bound InfrastructurePolicy | -| domainProfileRef | string | no | Name of the bound InfrastructureProfile | -| policyGenerationAtLastEvaluation | int64 | no | InfrastructurePolicy generation at last evaluation | -| driftDetected | boolean | no | True if drift detected at last evaluation | - -#### spec.outcomeRegistry[] - -| Field | Type | Required | Description | -|------------------|-----------|----------|--------------------------------------------------------------------------------------| -| derivedObjectUID | string | yes | UID matching a derivedObject entry in descendantRegistry | -| outcomeType | string | yes | Terminal classification: Succeeded, Failed, Drifted, or Superseded | -| outcomeTimestamp | date-time | yes | Time when the terminal condition was observed | -| outcomeRef | string | no | Name of the OperationResult ConfigMap or terminal condition reason. Optional. | -| outcomeDetail | string | no | Brief human-readable summary written by LineageController. Optional. | - -Entries are appended monotonically. No entry is ever updated or removed. An -outcomeRegistry entry for a given derivedObjectUID supersedes but does not replace -its corresponding descendantRegistry entry. Both records are permanent. - ---- - -## 4. Creation Rationale Enumeration - -Defined in `seam-core/pkg/lineage/rationale.go`. This is a compile-time -`CreationRationale string` type with a controlled vocabulary. All Seam Operators -import this package when populating `SealedCausalChain.CreationRationale`. - -New values require a Pull Request to seam-core and Platform Governor review. -Operators do not extend this vocabulary unilaterally. - -| Value | Operator(s) | Meaning | -|--------------------------|------------------------------|-------------------------------------------------------------------| -| ClusterProvision | Platform | A cluster lifecycle root declaration was created | -| ClusterDecommission | Platform | A cluster decommission root declaration was created | -| SecurityEnforcement | Guardian | A security plane declaration was created | -| PackExecution | Wrapper | A pack delivery or execution root declaration was created | -| VirtualizationFulfillment| Screen (future) | A virtualization workload root declaration was created | -| ConductorAssignment | Conductor (agent mode) | An operational assignment was created by the Conductor agent | -| VortexBinding | Vortex (future) | A portal policy binding was created | - ---- - -## 5. SealedCausalChain Field Type - -Defined in `seam-core/pkg/lineage/chain.go`. This is the Go struct that every -Seam-managed CRD embeds in its spec. It is authored once at creation time and -sealed at admission. The admission webhook rejects any update request that -modifies this field after the object is created. - -| Field | Type | Description | -|--------------------------|------------------------------|-------------------------------------------------------------------| -| rootKind | string | Kind of the root declaration that caused this object to exist | -| rootName | string | Name of the root declaration | -| rootNamespace | string | Namespace of the root declaration | -| rootUID | types.UID | UID of the root declaration at time of this object's creation | -| creatingOperator | OperatorIdentity | Seam Operator name and version that created this object | -| creationRationale | lineage.CreationRationale | Reason from the controlled vocabulary | -| rootGenerationAtCreation | int64 | Root declaration generation at time this object was created | - -`OperatorIdentity` has two fields: `name` (string) and `version` (string). - ---- - -## 6. Derivation from Domain Core - -`InfrastructureLineageIndex` instantiates `DomainLineageIndex` from `core.ontai.dev` -per the domain-core-schema.md instantiation contract (§3). The instantiation rules -applied in this domain are: - -| Constraint | Domain Core (abstract) | Seam Core (infrastructure instantiation) | -|-----------------------------------|-----------------------------------------|--------------------------------------------------------| -| API group | core.ontai.dev | infrastructure.ontai.dev | -| creationRationale constraint | unconstrained string | enum - `pkg/lineage.CreationRationale` values | -| domainPolicyRef | string (abstract) | Name of an `InfrastructurePolicy` CR | -| domainProfileRef | string (abstract) | Name of an `InfrastructureProfile` CR | -| rootBinding fields | as defined - unmodified | as defined - unmodified | -| Lineage Index Pattern | one index per root declaration | one index per root declaration - unchanged | -| Authorship rule | controller-authored exclusively | controller-authored exclusively - unchanged | -| Immutability rule | rootBinding sealed at admission | rootBinding sealed at admission - unchanged | - ---- - -## 7. Per-CRD Field Reference - -### 7.1 InfrastructureRunnerConfig - -**Short name:** irc | **Scope:** Namespaced | **Authored by:** platform | **Reconciled by:** conductor - -Operator-generated operational contract for a specific cluster. Never human-authored. -INV-009, INV-010. Phase-2B migration from `runner.ontai.dev/RunnerConfig`. - -#### spec - -| Field | Type | Required | Description | -|------------------------|---------------------------|----------|---------------------------------------------------------------------------| -| clusterRef | string | yes | Name of the TalosCluster this RunnerConfig is authoritative for | -| runnerImage | string | yes | Fully qualified container image reference for Conductor agent. INV-011. | -| phases | RunnerPhaseConfig[] | no | Ordered list of operational phases for Conductor lifecycle | -| steps | RunnerConfigStep[] | no | Ordered list of execution steps across all phases | -| operationalHistory | RunnerOperationalHistoryEntry[] | no | Append-only record of completed RunnerConfig executions | -| maintenanceTargetNodes | string[] | no | Node names that are the subject of the operation | -| operatorLeaderNode | string | no | Node hosting the leader pod of the initiating operator | -| selfOperation | bool | no | True when execution cluster and target cluster are the same | - -**RunnerConfigStep fields:** name, capability, parameters (map), dependsOn (string), haltOnFailure (bool) - -**RunnerPhaseConfig fields:** name, parameters (map) - -#### status (written by Conductor agent leader exclusively) - -| Field | Type | Description | -|----------------|-------------------------|------------------------------------------------------------------------------------| -| capabilities | RunnerCapabilityEntry[] | Self-declared capability manifest emitted by Conductor agent on startup | -| agentVersion | string | Version string of the running Conductor agent binary | -| agentLeader | string | Pod name of the current Conductor agent leader | -| phase | string | Terminal execution phase: Completed or Failed. Empty when in progress. | -| failedStep | string | Name of the first step that reached Failed. Present only when phase=Failed. | -| stepResults | RunnerConfigStepResult[]| Ordered step result records written by Conductor execute mode | -| conditions | metav1.Condition[] | Standard Kubernetes condition list | - ---- - -### 7.2 InfrastructureTalosCluster - -**Short name:** itc | **Scope:** Namespaced | **Authored by:** human / GitOps | **Reconciled by:** platform - -Root declaration for every cluster under Seam governance. One instance per cluster. -Phase-2B migration from `platform.ontai.dev/TalosCluster`. Decision H applies (deletion cascade order). - -#### spec - -| Field | Type | Required | Description | -|------------------------|-------------------------------|----------|-----------------------------------------------------------------------------| -| mode | string (enum) | yes | `bootstrap` or `import`. bootstrap = new cluster, import = existing cluster | -| role | string (enum) | no* | `management` or `tenant`. Mandatory on mode=import. | -| talosVersion | string | no | Talos OS version. Used by Conductor for compatible runner image. INV-012. | -| clusterEndpoint | string | no | Cluster VIP or primary API endpoint IP. Required on mode=import. | -| nodeAddresses | string[] | no | Node IPs. Used by DSNSReconciler to populate A records. | -| capi | InfrastructureCAPIConfig | no | CAPI integration settings. Absent = direct bootstrap. | -| infrastructureProvider | string (enum) | no | `native`, `capi`, or `screen` (reserved). Default: native. | -| kubeconfigSecretRef | string | no | Secret name containing kubeconfig. Required on mode=import. | -| talosconfigSecretRef | string | no | Secret name containing talosconfig. | -| lineage | lineage.SealedCausalChain | no | Sealed causal chain record. Immutable after creation. | - -**InfrastructureCAPIConfig fields:** enabled (bool), talosVersion, kubernetesVersion, controlPlane (replicas), workers ([]InfrastructureCAPIWorkerPool), ciliumPackRef - -**Deletion semantics (Decision H):** mode=bootstrap triggers permanent decommission. mode=import triggers severance only (cluster continues to exist unmanaged). - -#### status - -| Field | Type | Description | -|-----------------|-----------------------|--------------------------------------------------------------------------| -| observedGeneration | int64 | Generation most recently reconciled | -| origin | string (enum) | `bootstrapped` or `imported` | -| capiClusterRef | InfrastructureLocalObjectRef | Reference to the owned CAPI Cluster object. Only for CAPI clusters. | -| conditions | metav1.Condition[] | Status conditions including `Ready` and `LineageSynced` | - ---- - -### 7.3 InfrastructureClusterPack - -**Short name:** icp | **Scope:** Namespaced | **Authored by:** human / GitOps | **Reconciled by:** wrapper - -Records a compiled OCI artifact that is ready for runtime delivery. Spec is immutable -after creation. Phase-2B migration from `infra.ontai.dev/ClusterPack`. - -#### spec - -| Field | Type | Required | Description | -|--------------------|-----------------------------------|----------|----------------------------------------------------------------------| -| version | string | yes | Semantic version of this pack. Immutable. | -| registryRef | InfrastructurePackRegistryRef | yes | OCI registry URL and digest. Immutable. | -| checksum | string | no | Content-addressed checksum of the full artifact manifest set | -| rbacDigest | string | no | OCI digest of the RBAC layer (SA, Role, ClusterRole, Bindings) | -| workloadDigest | string | no | OCI digest of the workload layer. Applied after RBACProfile ready. | -| clusterScopedDigest| string | no | OCI digest of cluster-scoped non-RBAC layer | -| sourceBuildRef | string | no | Opaque reference to the build that produced this pack | -| executionOrder | InfrastructurePackExecutionStage[]| no | Ordered stages: rbac, storage, stateful, stateless | -| provenance | InfrastructurePackProvenance | no | Build-time metadata: buildID, buildTimestamp, sourceRef | -| basePackName | string | no | Logical pack name shared across versions (e.g., nginx-ingress) | -| targetClusters | string[] | no | Cluster names to which this pack should be delivered | -| chartVersion | string | no | Helm chart version used to compile this pack | -| chartURL | string | no | Helm chart repository URL | -| chartName | string | no | Helm chart name | -| helmVersion | string | no | Helm SDK version | -| valuesFile | string | no | Path to the values file used during pack compilation | -| lifecyclePolicies | InfrastructureLifecyclePolicy | no | retainOnDeletion (bool, default true) | -| lineage | lineage.SealedCausalChain | no | Sealed causal chain record. Immutable after creation. | - -#### status - -| Field | Type | Description | -|--------------------|--------------------|--------------------------------------------------------------------------| -| signed | bool | Whether the conductor signing loop has signed this pack | -| packSignature | string | Base64-encoded Ed25519 signature from management cluster conductor | -| observedGeneration | int64 | Generation most recently reconciled | -| conditions | metav1.Condition[] | Status conditions | - ---- - -### 7.4 InfrastructurePackExecution - -**Short name:** ipe | **Scope:** Namespaced | **Authored by:** human / GitOps | **Reconciled by:** wrapper - -Runtime pack delivery request. Triggers wrapper to create a Kueue Job. -Phase-2B migration from `infra.ontai.dev/PackExecution`. - -#### spec - -| Field | Type | Required | Description | -|--------------------|--------------------------------|----------|------------------------------------------------------------------| -| clusterPackRef | InfrastructureClusterPackRef | yes | Name and version of the ClusterPack to deploy | -| targetClusterRef | string | yes | Name of the target cluster to deliver the pack to | -| admissionProfileRef| string | no | Name of the RBACProfile governing this execution | -| chartVersion | string | no | Carried from ClusterPack | -| chartURL | string | no | Carried from ClusterPack | -| chartName | string | no | Carried from ClusterPack | -| helmVersion | string | no | Carried from ClusterPack | -| lineage | lineage.SealedCausalChain | no | Sealed causal chain record. Immutable after creation. | - -#### status - -| Field | Type | Description | -|--------------------|--------------------|--------------------------------------------------------------------------| -| observedGeneration | int64 | Generation most recently reconciled | -| jobName | string | Name of the pack-deploy Kueue Job submitted for this execution | -| operationResultRef | string | Name of the PackOperationResult CR written after successful completion | -| conditions | metav1.Condition[] | Status conditions | - ---- - -### 7.5 InfrastructurePackInstance - -**Short name:** ipi | **Scope:** Namespaced | **Authored by:** wrapper | **Reconciled by:** wrapper - -Records the delivered state of a pack on a specific cluster. Created by wrapper -after pack-deploy Job completes. Phase-2B migration from `infra.ontai.dev/PackInstance`. - -#### spec - -| Field | Type | Required | Description | -|------------------|-----------------------------------|----------|----------------------------------------------------------------------| -| clusterPackRef | string | yes | Name of the ClusterPack CR this instance tracks | -| version | string | yes | Pack version delivered to the target cluster | -| targetClusterRef | string | yes | Name of the target cluster this instance is installed on | -| dependsOn | string[] | no | Pack base names that must be Delivered before this instance | -| dependencyPolicy | InfrastructureDependencyPolicy | no | onDrift: Block, Warn (default), or Ignore | -| chartVersion | string | no | Carried from ClusterPack | -| chartURL | string | no | Carried from ClusterPack | -| chartName | string | no | Carried from ClusterPack | -| helmVersion | string | no | Carried from ClusterPack | - -#### status - -| Field | Type | Description | -|--------------------|-------------------------------------|----------------------------------------------------------------------| -| observedGeneration | int64 | Generation most recently reconciled | -| deliveredAt | metav1.Time | When the pack was most recently confirmed delivered | -| driftSummary | string | Human-readable summary of the current drift state | -| upgradeDirection | string (enum) | Initial, Upgrade, Rollback, or Redeploy | -| deployedResources | InfrastructureDeployedResourceRef[] | Resources applied by pack-deploy. Used for deletion cleanup. | -| conditions | metav1.Condition[] | Status conditions | - ---- - -### 7.6 InfrastructurePackBuild - -**Short name:** ipb | **Scope:** Namespaced | **Authored by:** human / GitOps | **Reconciled by:** compiler (offline) - -Compiler input specification. Read by the Compiler at compile time. Never applied -to a cluster as a live CR with an active controller. Phase-2B migration from -`infra.ontai.dev/PackBuild`. - -#### spec - -| Field | Type | Required | Description | -|-----------------|-----------------------------------------|--------------|-----------------------------------------------------------------| -| componentName | string | yes | Name of the component being compiled | -| category | string (enum) | yes | `helm`, `kustomize`, or `raw` | -| helmSource | InfrastructurePackHelmSource | if helm | URL, chart, version, valuesFile | -| kustomizeSource | InfrastructurePackKustomizeSource | if kustomize | path to kustomization root | -| rawSource | InfrastructurePackRawSource | if raw | path to raw YAML manifest directory | -| targetClusters | string[] | no | Cluster names to which the compiled pack should be delivered | - ---- - -### 7.7 InfrastructurePackReceipt - -**Short name:** ipr | **Scope:** Namespaced | **Authored by:** conductor (agent) | **Reconciled by:** conductor (agent) - -Pack delivery acknowledgement written by the Conductor agent on the tenant cluster -after verifying the signed PackInstance. INV-026. Phase-2B migration from -`runner.ontai.dev/PackReceipt`. - -#### spec - -| Field | Type | Required | Description | -|-------------------|--------|----------|-----------------------------------------------------------------------------| -| clusterPackRef | string | yes | Name of the ClusterPack CR this receipt acknowledges | -| targetClusterRef | string | yes | Name of the cluster this receipt was generated on | -| packSignature | string | no | Base64-encoded Ed25519 signature from management cluster conductor. INV-026. | -| signatureVerified | bool | no | Whether the conductor agent verified the pack signature | -| rbacDigest | string | no | OCI digest of the RBAC layer. Carried from ClusterPack for audit. | -| workloadDigest | string | no | OCI digest of the workload layer. Carried from ClusterPack. | -| chartVersion | string | no | Carried from ClusterPack | -| chartURL | string | no | Carried from ClusterPack | -| chartName | string | no | Carried from ClusterPack | -| helmVersion | string | no | Carried from ClusterPack | - ---- - -### 7.8 PackOperationResult - -**Short name:** por | **Scope:** Namespaced | **Authored by:** conductor (execute) | **Read by:** wrapper - -Immutable result record written by the Conductor execute-mode Job after a pack-deploy -capability completes. Replaces the ConfigMap output channel. One per PackExecution, -created in `seam-tenant-{clusterName}` namespace. - -#### spec - -| Field | Type | Required | Description | -|-------------------------------|--------------------------------|----------|-----------------------------------------------------------------------| -| packExecutionRef | string | no | Name of the PackExecution CR that triggered this operation | -| clusterPackRef | string | no | Name of the ClusterPack CR that was deployed | -| targetClusterRef | string | no | Name of the target cluster this operation ran against | -| capability | string | yes | Name of the Conductor capability that produced this result | -| phase | string | no | RunnerConfig phase this result belongs to | -| status | string (enum) | yes | `Succeeded` or `Failed` | -| startedAt | metav1.Time | no | Time the capability execution began | -| completedAt | metav1.Time | no | Time the capability execution finished | -| failureReason | PackOperationFailureReason | no | Structured failure description. Nil on success. | -| deployedResources | PackOperationDeployedResource[]| no | Resources applied during execution. Used for PackInstance cleanup. | -| artifacts | PackOperationArtifact[] | no | Artifacts produced by this execution | -| steps | PackOperationStepResult[] | no | Step results for multi-step capabilities | -| revision | int64 | no | Monotonically increasing revision counter for this pack operation | -| previousRevisionRef | string | no | Name of the PackOperationResult deleted when this revision was written | -| talosClusterOperationResultRef| string | no | Reserved stub. Not populated by any current controller. | -| clusterPackVersion | string | no | ClusterPack spec.version deployed in this operation. N-step rollback anchor. | -| rbacDigest | string | no | OCI digest of the RBAC layer deployed. Rollback restoration anchor. | -| workloadDigest | string | no | OCI digest of the workload layer deployed. Rollback restoration anchor.| - -**Rollback invariants (N-step model):** The POR writer labels the predecessor `ontai.dev/superseded=true` instead of deleting it. Superseded PORs are retained up to `maxRetainedSupersededPORs` (10) per ClusterPack; the oldest is pruned when the cap is exceeded. The wrapper rollback handler lists all PORs for the ClusterPack (both active and superseded) via `ontai.dev/cluster-pack` label and reads `clusterPackVersion`, `rbacDigest`, `workloadDigest` directly from the POR at `spec.revision == rollbackToRevision`. Any retained revision is reachable in one `spec.rollbackToRevision` field set -- not limited to N-1. - -**Labels on POR:** -- `ontai.dev/cluster-pack={clusterPackRef}` -- set on every POR (active and superseded) to allow ClusterPack-scoped queries without knowing the PackExecution ref. -- `ontai.dev/superseded=true` -- set by the POR writer when a revision is superseded. Active POR carries no superseded label. - -**PackOperationFailureReason fields:** category (enum: ValidationFailure, CapabilityUnavailable, ExecutionFailure, ExternalDependencyFailure, InvariantViolation, LicenseViolation, StorageUnavailable), reason (string), failedStep (string) - -**PackOperationArtifact fields:** name, kind (enum: ConfigMap, Secret, OCIImage, S3Object), reference, checksum - ---- - -### 7.9 DriftSignal - -**Short name:** ds | **Scope:** Namespaced | **Authored by:** conductor (role=tenant) | **Reconciled by:** conductor (role=management) - -Three-state drift acknowledgement chain. Written by conductor role=tenant when it -detects a delta between declared and actual state. Acknowledged by conductor -role=management. Decision H. At-least-once delivery. - -#### spec - -| Field | Type | Required | Description | -|-------------------|-----------------------|----------|-------------------------------------------------------------------------------------------------| -| state | string (enum) | yes | `pending`, `delivered`, `queued`, or `confirmed` | -| correlationID | string | yes | UUID v4. Used to deduplicate signals across federation retries. | -| observedAt | metav1.Time | yes | Time the drift was first observed by conductor role=tenant | -| affectedCRRef | DriftAffectedCRRef | yes | Typed reference to the CR that exhibited drift: group, kind, namespace, name | -| driftReason | string | yes | Human-readable description of why drift was detected | -| correctionJobRef | string | no | Name of the corrective Job created by the management cluster. Set when state=queued. | -| escalationCounter | int32 | no | Re-emit count without acknowledgement. At threshold: TerminalDrift Condition set, no more re-emits. | - -**State lifecycle:** pending -> delivered -> queued -> confirmed. Transitions are one-way. - ---- - -### 7.10 SeamMembership - -**Short name:** sm | **Scope:** Namespaced | **Authored by:** human / GitOps | **Reconciled by:** guardian - -Formal join declaration for an operator wishing to become a member of the Seam -infrastructure family. Guardian validates and admits the membership after verifying -the operator's RBACProfile. Operators that are not members may not be allocated -PermissionSnapshots. - -#### spec - -| Field | Type | Required | Description | -|-------------------|---------------|----------|------------------------------------------------------------------------------------------------------| -| appIdentityRef | string | yes | Operator's application-layer identity (e.g., guardian, platform, wrapper, conductor) | -| domainIdentityRef | string | yes | DomainIdentity at core.ontai.dev this operator traces to. Must match the RBACProfile's domainIdentityRef. | -| principalRef | string | yes | Kubernetes service account: `system:serviceaccount:{namespace}:{name}`. Must match RBACProfile. | -| tier | string (enum) | yes | `infrastructure` (Seam family operators) or `application` (app operators) | - -#### status - -| Field | Type | Description | -|----------------------|--------------------|------------------------------------------------------------------------| -| admitted | bool | True when Guardian has validated and admitted this member | -| admittedAt | metav1.Time | Timestamp when Guardian admitted this member | -| permissionSnapshotRef| string | Name of the PermissionSnapshot Guardian resolved for this member | -| conditions | metav1.Condition[] | Admitted (bool), Validated (bool) | - ---- - -## 8. Domain Semantic Name Service - -> **Locked Governor Decision - 2026-04-06** -> All six decisions in this section are locked. A Platform Governor constitutional -> amendment is required to change any of them. - ---- - -### Decision 1 - DSNS is a controller within seam-core, not a separate binary or deployment - -DSNS (Domain Semantic Name Service) is implemented as a controller registered in -`cmd/seam-core/main.go` alongside `LineageController`. It shares the existing -informer cache. There is no separate DSNS binary, no separate DSNS Deployment, and -no separate DSNS service account beyond the seam-core controller manager's service -account. DSNS runs inside the seam-core controller manager process. - -DSNS watches all nine root-declaration GVKs already watched by LineageController: - -| GVK | API group | Operator | -|-----|-----------|----------| -| InfrastructureTalosCluster | infrastructure.ontai.dev | Platform | -| SeamInfrastructureCluster | infrastructure.cluster.x-k8s.io | Platform | -| SeamInfrastructureMachine | infrastructure.cluster.x-k8s.io | Platform | -| InfrastructureClusterPack | infrastructure.ontai.dev | Wrapper | -| InfrastructurePackExecution | infrastructure.ontai.dev | Wrapper | -| InfrastructurePackInstance | infrastructure.ontai.dev | Wrapper | -| RBACPolicy | security.ontai.dev | Guardian | -| RBACProfile | security.ontai.dev | Guardian | -| IdentityBinding | security.ontai.dev | Guardian | - -DSNS derives all DNS records from these CRDs without calling into any operator's -reconciler and without any operator importing a DSNS client package. - -**The boundary is permanent and locked:** Operators write CRDs. DSNS projects -CRDs to DNS. No operator holds a dependency on DSNS. No operator calls DSNS APIs. -This separation is enforced at the package boundary - DSNS is a consumer of CRD -state, not a shared library imported by operators. - ---- - -### Decision 2 - DNS backend is a ConfigMap named dsns-zone in ont-system - -The DNS backend is a single ConfigMap named `dsns-zone` in `ont-system`. DSNS is -the sole writer of this ConfigMap. Write exclusivity is enforced by an admission -webhook using the same controller-authorship gate pattern as -`InfrastructureLineageIndex`: writes to the `dsns-zone` ConfigMap from any principal -other than the seam-core controller manager service account are rejected. - -CoreDNS serves the zone using the `file` plugin, mounting the `dsns-zone` ConfigMap -at a path in the CoreDNS pod. The CoreDNS `reload` plugin propagates zone changes -within five seconds of the ConfigMap being updated. - -No etcd sidecar. No dedicated DNS backend. No new infrastructure beyond one -ConfigMap and one CoreDNS Corefile stanza. The zone file content in the ConfigMap -is a standard RFC 1035 zone file generated by DSNSReconciler. - ---- - -### Decision 3 - Authoritative zone is seam.ontave.dev; CoreDNS delivery via compiler enable phase 5 - -The authoritative zone served by DSNS is `seam.ontave.dev`. - -The CoreDNS configuration is additive to the existing CoreDNS deployment - one new -Corefile stanza is added for the `seam.ontave.dev` zone, pointing at the mounted -ConfigMap path. The existing CoreDNS stanzas are not modified. - -CoreDNS is exposed externally via a LoadBalancer service on port 53 UDP and TCP -using the management cluster VIP (10.20.0.10 in the lab). This LoadBalancer service -is a new resource emitted by the enable phase; it does not modify the existing -CoreDNS ClusterIP service used for in-cluster DNS. - -The following three resources are all emitted by `compiler enable` in phase 5 -(`05-post-bootstrap`), in this order: - -1. The `dsns-zone` ConfigMap (initially empty zone file; DSNSReconciler populates it) -2. The CoreDNS Corefile stanza (mounted as a ConfigMap update to the CoreDNS config) -3. The CoreDNS LoadBalancer service on port 53 UDP/TCP - -Phase 5 is the correct phase because DSNS depends on CNPG (phase 0), Guardian -(phases 1-2), all operators (phase 3), and Conductor (phase 4) being operational -before DNS records can be populated. - ---- - -### Decision 4 - DNS record schema - -All records are under the `seam.ontave.dev` zone. DSNSReconciler derives records -from the nine watched GVKs with no operator involvement. - -**Platform records** - emitted when an `InfrastructureTalosCluster` reaches `Ready`: - -| Record type | Name pattern | Value | -|-------------|--------------|-------| -| A | `{cluster-name}.seam.ontave.dev` | Cluster VIP | -| A | `api.{cluster-name}.seam.ontave.dev` | API server endpoint | -| TXT | `role.{cluster-name}.seam.ontave.dev` | Cluster role classification | - -**Guardian records** - emitted on condition transitions: - -| Record type | Name pattern | Value | Trigger | -|-------------|--------------|-------|---------| -| TXT | `identity.{subject-hash}.guardian.{cluster-name}.seam.ontave.dev` | RBACProfile name and IdentityProvider | IdentityBinding resolves | -| TXT | `idp.{provider-name}.guardian.seam.ontave.dev` | OIDC discovery endpoint | IdentityProvider reaches Valid condition | - -**Wrapper records** - emitted on PackInstance completion: - -| Record type | Name pattern | Value | -|-------------|--------------|-------| -| TXT | `pack.{pack-name}.{version}.wrapper.{cluster-name}.seam.ontave.dev` | PackReceipt digest | - -**Conductor records** - emitted from RunnerConfig terminal state: - -| Record type | Name pattern | Value | -|-------------|--------------|-------| -| TLSA-style TXT | `authority.conductor.seam.ontave.dev` | Management Conductor signing key fingerprint | -| TXT | `run.{runnerconfig-name}.conductor.{cluster-name}.seam.ontave.dev` | Validation result digest | - -**Sovereign cluster delegation** - emitted when InfrastructureTalosCluster role classification is `sovereign`: - -| Record type | Name pattern | Value | -|-------------|--------------|-------| -| NS | `{cluster-name}.seam.ontave.dev` | Sovereign cluster's CoreDNS endpoint | - -The NS delegation record enables a sovereign cluster to serve its own sub-zone under -`{cluster-name}.seam.ontave.dev` via its own CoreDNS instance. DSNS writes the -delegation record; the sovereign cluster operator is responsible for configuring the -delegated zone. - ---- - -### Decision 5 - Two runtime consumers with hard dependencies on DSNS availability - -Exactly two runtime components have hard dependencies on DSNS availability: - -**Conductor - tenant agent startup:** -At tenant cluster agent startup, Conductor queries `authority.conductor.seam.ontave.dev` -to retrieve the management Conductor signing key fingerprint. This DNS lookup -bootstraps signing key trust before the tenant Conductor establishes its federation -gRPC stream to the management cluster. If the record is absent or unreachable, the -tenant Conductor enters a degraded state and retries. The federation stream is not -established until the signing key fingerprint is confirmed. - -**Compiler - cluster coordinate discovery:** -Compiler queries the `seam.ontave.dev` zone during cluster operations to discover -cluster coordinates (VIP, API server endpoint, role) without requiring hardcoded -kubeconfig paths or static configuration. Cluster coordinates are read from DNS at -compile time. This eliminates the need for hardcoded cluster addresses in Compiler -invocations after initial bootstrap. - -No other Seam component holds a hard runtime dependency on DSNS. All other consumers -are optional or best-effort. - ---- - -## 9. Lineage Provision Standards - -### Declaration 1 - core.ontai.dev is a contract and pattern layer exclusively - -The `core.ontai.dev` API group is a contract and pattern layer exclusively. It -defines abstract types and structural contracts that domain layers instantiate. It -never runs controllers against downstream domain CRs. It never watches, lists, or -reconciles objects from any domain below it. Seam Core inherits this as a permanent, -locked boundary: no Seam Core component may implement or instantiate a controller -at the `core.ontai.dev` layer, and no component at that layer may reference -`infrastructure.ontai.dev` types. This boundary has no exceptions and requires a -Platform Governor constitutional amendment to change. - ---- - -### Declaration 2 - infrastructure.ontai.dev is the aggregation boundary for the Seam operator family - -Seam Core inherits `DomainLineageIndex` from `core.ontai.dev` and translates it -into `InfrastructureLineageIndex` under `infrastructure.ontai.dev`. This extended -type carries Seam-specific lineage fields beyond the abstract contract: cluster -topology classification, RunnerConfig provenance, and operator domain boundary -metadata. These extensions are defined here, at the domain instantiation layer, -not at `core.ontai.dev`. - -Seam Core also instantiates the abstract aggregation ODC from `core.ontai.dev` -as the concrete `InfrastructureLineageController`. This controller manages -`InfrastructureLineageIndex` CR lifecycle within the Seam operator family. It is -the sole controller that appends to `spec.descendantRegistry`, evaluates -`spec.policyBindingStatus`, and reconciles lineage index state. No individual Seam -Operator implements its own lineage aggregation controller. - -**Semantic data flow constraint - permanent:** -Semantic lineage data produced by Seam operators flows downward only. It originates -at the operator layer, registers in `InfrastructureLineageIndex` at Seam Core, and -is evaluated against `InfrastructurePolicy` and `InfrastructureProfile` at Seam Core. -Semantic data never travels upward to `core.ontai.dev`. The core layer has no -knowledge of which Seam Operators exist, which clusters they manage, or what -operational history they have produced. This is a permanent, locked constraint. - ---- - -### Declaration 3 - Community domain pattern: contract and pattern from core, runtime from domain - -The community domain pattern is the standard composition model for any operator -family adopting `DomainLineageIndex`. The `core.ontai.dev` layer provides two -things: the contract (the abstract type definition) and the pattern (the abstract -aggregation ODC defining how conforming implementations must behave). The domain -layer provides everything else: the concrete type instantiation, the concrete -controller implementation, the domain-specific rationale enumeration, and the -domain-specific policy and profile CRD bindings. - -This is the community free pass: any operator family can participate in structured -lineage tracking by instantiating `DomainLineageIndex` in their own API group, -implementing the aggregation ODC contract in their own controller, and defining -their own rationale vocabulary. They do not need to contribute to `core.ontai.dev` -or `seam-core` to participate. The abstract contract is sufficient. Seam Core's -`InfrastructureLineageIndex` and `InfrastructureLineageController` are the first -community instantiation of this pattern. They are the reference implementation, not -the only allowed implementation. - ---- - -### Declaration 4 - Seam Core annotation namespace structure - -All annotations placed on Seam-managed CRs by Seam Operators follow a two-tier -namespace structure under the `infrastructure.ontai.dev` prefix. - -**Tier 1 - operator-authored annotations:** -Individual Seam Operators author annotations under the `infrastructure.ontai.dev` -prefix for their own operational keys. Each operator retains full authorship -authority over its own keys within this prefix. No cross-operator coordination is -required for operator-specific annotation keys. - -**Tier 2 - governance sub-prefix (reserved):** -The `governance.infrastructure.ontai.dev` sub-prefix is reserved exclusively for -cross-cutting annotations written by controllers governed by Seam Core - specifically -the `InfrastructureLineageController` and any future Seam Core governed controller. -Individual Seam Operators never write annotations under the -`governance.infrastructure.ontai.dev` sub-prefix on their own authority. Doing so -is an invariant violation. Any annotation key under the governance sub-prefix that -an individual operator needs to consume must be written by the Seam Core governed -controller and only read by the operator. - -This structure ensures that annotations under the governance sub-prefix carry the -same authorship integrity guarantee as the `InfrastructureLineageIndex` itself: -they are controller-authored by a single, designated authority, not overwritten by -arbitrary operators. - ---- - -### Declaration 5 - Reserved LineageSynced condition type - -The condition type `LineageSynced` is reserved across all Seam Operator CRD status -condition sets. No Seam Operator may define a condition of a different type for -this purpose, and no Seam Operator may repurpose this condition type for a meaning -other than lineage synchronization status. - -**Lifecycle protocol:** -1. On first observation of a root declaration CR, the responsible reconciler sets - `LineageSynced = False` with reason `LineageControllerAbsent` and a message - indicating that `InfrastructureLineageController` has not yet processed this object. -2. The reconciler that owns the root declaration type never updates `LineageSynced` - again after this initial write. It is a one-time initialization. The reconciler - writes it once; it does not poll or re-evaluate it. -3. Once `InfrastructureLineageController` is deployed and processes the root - declaration, it takes ownership of the `LineageSynced` condition and updates it - to `True` with appropriate reason and message. All subsequent updates to - `LineageSynced` are made exclusively by `InfrastructureLineageController`. -4. If `InfrastructureLineageController` is not deployed (e.g., stub phase, pre-Seam - Core installation), `LineageSynced` remains `False/LineageControllerAbsent` - indefinitely. This is an expected and documented steady state during the stub - phase. It is not an error condition requiring operator action. - -This protocol ensures that `LineageSynced` is never in an undefined state: it is -either at its initialized value (written by the reconciler, ownership not yet -transferred) or at a Seam Core governed value (ownership held by -`InfrastructureLineageController`). The transition is a one-way ownership transfer. -It cannot be reversed without a Governor-scheduled migration session. - ---- - -### Declaration 6 - outcomeRegistry is the terminal closure protocol - -When LineageController observes a terminal condition on any tracked derived object, -it appends an outcomeRegistry entry before the next reconcile cycle begins. An -outcomeRegistry entry for a given derivedObjectUID supersedes but does not replace -its corresponding descendantRegistry entry. Both records are permanent. - -Terminal condition observation is event-driven: LineageController watches all nine -root-declaration GVKs via its existing informer cache. On any status condition -transition to a terminal type (Succeeded, Failed, Drifted, or Superseded), the -controller appends the corresponding outcomeRegistry entry to the governing ILI -using an SSA patch. The patch is idempotent: if an entry already exists for the -given derivedObjectUID, the patch is a no-op. The append-only invariant is enforced -at admission: any write that modifies an existing outcomeRegistry entry is rejected. - -This protocol closes the causal chain: every derived object has both its creation -recorded (descendantRegistry) and its terminal outcome recorded (outcomeRegistry) -within the same ILI. Vortex retrieval can reconstruct the full lifecycle of any -derived object without querying the derived object's namespace. - ---- - -## 10. Deferred Implementation - -The following are out of scope for the stub phase and must not be acted on -without explicit Governor scheduling: - -- **LineageController admission webhook** - the webhook handler that rejects - updates modifying `spec.rootBinding` or `SealedCausalChain` fields. - Requires a Guardian Controller Engineer session. -- **controller-gen wiring for seam-core** - currently no code generation for - InfrastructureLineageIndex. The CRD YAML in §3 is a hand-authored stub. -- **InfrastructurePolicy and InfrastructureProfile CRDs** - referenced by ILI - spec.policyBindingStatus. Type files not yet in api/v1alpha1. Deferred pending - Guardian policy engine design session. - ---- - -*seam-core-schema - Seam Core infrastructure domain* -*This document is authored and amended by the Platform Governor and Schema Engineer only.* - -2026-04-21 - Amended to inherit domain-core-schema.md amendments from session/12. - declaringPrincipal added to spec.rootBinding. createdAt and actorRef added to - spec.descendantRegistry entries. outcomeRegistry added. Declaration 6 added. -2026-04-25 - Phase 2B complete. §2 Master GVK Reference added. §7 Per-CRD Field - Reference added covering all 11 seam-core owned types. Sections renumbered - to accommodate new content. All GVK references updated to infrastructure.ontai.dev - with Infrastructure-prefixed kind names. Old groups runner.ontai.dev and - infra.ontai.dev removed from all tables. +# Moved to seam-schema.md diff --git a/docs/seam-schema.md b/docs/seam-schema.md new file mode 100644 index 0000000..6c6cd3d --- /dev/null +++ b/docs/seam-schema.md @@ -0,0 +1,460 @@ +# seam-schema + +API Group: `seam.ontai.dev` +Repository: `seam` +All agents read this document in full before touching any CRD or shared library type in this repository. + +--- + +## 1. Domain boundary + +seam is the cross-operator CRD registry for the ONT platform. It declares the four types that span operator boundaries and the shared library packages consumed by every operator. No reconciliation logic lives in this repository. No capability engine lives here. + +seam.ontai.dev is not the group for operator-specific types. The division of ownership is: + +- `seam.ontai.dev` -- LineageRecord, RunnerConfig, DriftSignal, SeamMembership (this repo) +- `platform.ontai.dev` -- TalosCluster, ClusterLog, and all day-2 operation CRDs (platform repo) +- `seam.ontai.dev` (dispatcher-owned) -- PackDelivery, PackExecution, PackInstalled, PackReceipt, PackLog (dispatcher repo) +- `guardian.ontai.dev` -- all guardian RBAC plane types (guardian repo) + +SC-INV-001 -- seam owns all cross-operator CRD definitions under seam.ontai.dev. Reconcilers live in the operator repo. +SC-INV-002 -- All new CRD work goes directly into seam under seam.ontai.dev. +SC-INV-003 -- seam CRD manifests are installed before all operators. + +--- + +## 2. Master GVK reference + +All types below are under `seam.ontai.dev / v1alpha1`. + +| Kind | Resource (plural) | Short name | Scope | Authoring principal | Reconciling operator | +|---|---|---|---|---|---| +| LineageRecord | lineagerecords | lr | Namespaced | LineageController only | LineageController (seam-owned, deferred) | +| RunnerConfig | runnerconfigs | rc | Namespaced | platform operator | conductor agent mode / exec mode | +| DriftSignal | driftsignals | ds | Namespaced | conductor role=tenant | conductor role=management | +| SeamMembership | seammemberships | sm | Namespaced | human / GitOps | guardian | + +--- + +## 3. LineageRecord + +### 3.1 Purpose + +LineageRecord is the sealed causal chain index for a root declaration in the ONT platform. One LineageRecord is created per root declaration (currently: TalosCluster, PackDelivery) by the LineageController. All derived objects record derivation back to their root's LineageRecord. They do not each get their own record. + +The record is controller-authored exclusively (root Decision 3). No human operator and no automation pipeline may create or modify a LineageRecord. The admission webhook enforces this. + +`spec.descendantRegistry` grows monotonically. Entries are appended, never modified or removed (except by the retention enforcement loop after a staleness threshold is exceeded). + +### 3.2 Naming convention + +LineageRecord names are computed as `strings.ToLower(rootKind) + "-" + rootName`. + +Examples: `taloscluster-ccs-mgmt`, `packdelivery-cilium-v1` + +The helper `lineage.IndexName(kind, name)` from `pkg/lineage` produces this value. Operators that need to reference the LineageRecord for a given root use this function. + +### 3.3 spec fields + +**spec.rootBinding** (LineageRecordRootBinding, required, immutable after admission) + +Records the root declaration that anchors this record. All subfields are immutable. + +| Field | Type | Description | +|---|---|---| +| rootKind | string | Kind of the root declaration (e.g., TalosCluster, PackDelivery) | +| rootName | string | Name of the root declaration | +| rootNamespace | string | Namespace of the root declaration | +| rootUID | types.UID | UID of the root declaration at record creation time | +| rootObservedGeneration | int64 | metadata.generation of the root declaration at record creation | +| declaringPrincipal | string | Identity of the human or automation principal that applied the root CR. Stamped at CREATE by the admission webhook from the annotation `infrastructure.ontai.dev/declaring-principal`. Optional. | + +**spec.domainRef** (string, optional) + +References the DomainLineageIndex at `core.ontai.dev` that this LineageRecord instantiates. + +**spec.descendantRegistry** ([]DescendantEntry, optional) + +Append-only list of all objects derived from the root declaration. + +Each DescendantEntry has: + +| Field | Type | Description | +|---|---|---| +| group | string | API group of the derived object | +| version | string | API version of the derived object | +| kind | string | Kind of the derived object | +| name | string | Name of the derived object | +| namespace | string | Namespace of the derived object | +| uid | types.UID | UID of the derived object | +| seamOperator | string | Name of the Seam Operator that created this derived object | +| creationRationale | CreationRationale | Reason this derived object was created (see section 6) | +| rootGenerationAtCreation | int64 | metadata.generation of the root declaration at derived object creation time | +| createdAt | *metav1.Time | Optional. Time this entry was appended | +| actorRef | string | Optional. Identity propagated from rootBinding.declaringPrincipal | + +**spec.policyBindingStatus** (*InfrastructurePolicyBindingStatus, optional) + +Records the InfrastructurePolicy and InfrastructureProfile bound to the root declaration at last evaluation. + +| Field | Type | Description | +|---|---|---| +| domainPolicyRef | string | Name of the InfrastructurePolicy bound at last evaluation | +| domainProfileRef | string | Name of the InfrastructureProfile bound at last evaluation | +| policyGenerationAtLastEvaluation | int64 | metadata.generation of the bound policy at last evaluation | +| driftDetected | bool | True if drift was detected at the last evaluation cycle | + +**spec.outcomeRegistry** ([]OutcomeEntry, optional) + +Append-only registry of terminal outcomes for derived objects. Entries are written by LineageController when a terminal condition is observed. Never modified or removed. + +Each OutcomeEntry has: + +| Field | Type | Description | +|---|---|---| +| derivedObjectUID | types.UID | UID matching a DescendantEntry in descendantRegistry | +| outcomeType | OutcomeType | Terminal classification: Succeeded, Failed, Drifted, or Superseded | +| outcomeTimestamp | metav1.Time | Time when the terminal condition was observed | +| outcomeRef | string | Optional. Name of the OperationResult or terminal condition reason | +| outcomeDetail | string | Optional. Brief human-readable summary of the outcome | + +**spec.retentionPolicy** (*LineageRetentionPolicy, optional) + +Declares garbage collection behavior. + +| Field | Type | Default | Description | +|---|---|---|---| +| descendantRetentionDays | int32 | 30 | Days a stale descendant entry is retained after its object is confirmed not-found. Minimum 1. | +| deleteWithRoot | bool | true | When true, this LineageRecord is garbage collected when its root declaration is deleted | + +### 3.4 status fields + +| Field | Type | Description | +|---|---|---| +| observedGeneration | int64 | Last generation processed by the controller | +| conditions | []metav1.Condition | Standard Kubernetes condition array | + +Condition types: + +- `LineageSynced` -- set by the responsible reconciler to False with reason `LineageControllerAbsent` on first observation. LineageController sets it to True when it takes ownership. See section 7 Declaration 5. + +### 3.5 Labels used by DescendantReconciler + +Operators call `lineage.SetDescendantLabels` at derived object creation time to mark that object for the DescendantReconciler. The function writes five labels: + +| Label key | Value | +|---|---| +| `infrastructure.ontai.dev/root-ili` | LineageRecord name (e.g., taloscluster-ccs-mgmt) | +| `infrastructure.ontai.dev/root-ili-namespace` | Namespace of the LineageRecord (may differ from derived object namespace) | +| `infrastructure.ontai.dev/seam-operator` | Canonical operator name (e.g., platform, dispatcher) | +| `infrastructure.ontai.dev/creation-rationale` | CreationRationale value | +| `infrastructure.ontai.dev/actor-ref` | Declaring principal, propagated from root annotation | + +The cross-namespace case: when a derived object lives in a different namespace than its root (e.g., RunnerConfig in `ont-system`, LineageRecord in `seam-system`), the `root-ili-namespace` label carries the LineageRecord's namespace so the DescendantReconciler can resolve the reference correctly. + +--- + +## 4. RunnerConfig + +### 4.1 Purpose + +RunnerConfig is the operator-generated operational contract for a Conductor agent on a specific cluster. It is created by the platform operator at runtime. It is never human-authored (INV-009). The platform operator is the sole author of RunnerConfig specs. The Conductor agent leader is the sole author of RunnerConfig status. + +### 4.2 spec fields + +| Field | Type | Description | +|---|---|---| +| clusterRef | string | Name of the TalosCluster this RunnerConfig is authoritative for | +| runnerImage | string | Fully qualified container image reference for the Conductor agent. Tag convention: `v{talosVersion}-r{revision}` for stable, `dev` or `dev-rc{N}` for development (INV-011, INV-012) | +| phases | []RunnerPhaseConfig | Optional. Ordered list of operational phases for this cluster's Conductor lifecycle | +| steps | []RunnerConfigStep | Optional. Ordered list of execution steps across all phases | +| operationalHistory | []RunnerOperationalHistoryEntry | Optional. Append-only record of completed RunnerConfig executions. Never truncated | +| maintenanceTargetNodes | []string | Optional. Node names that are the subject of the operation | +| operatorLeaderNode | string | Optional. Node hosting the leader pod of the initiating operator | +| selfOperation | bool | Optional. True when the Job's execution cluster and the target cluster are the same | + +**RunnerPhaseConfig** fields: + +| Field | Type | Description | +|---|---|---| +| name | string | Phase identifier | +| parameters | map[string]string | Optional. Phase-specific key-value configuration | + +**RunnerConfigStep** fields: + +| Field | Type | Description | +|---|---|---| +| name | string | Unique identifier for this step within the RunnerConfig | +| capability | string | Named Conductor capability to invoke for this step | +| parameters | map[string]string | Optional. Input parameter map passed to the capability at Job materialisation time | +| dependsOn | string | Optional. Name of a prior step that must complete before this step begins | +| haltOnFailure | bool | Optional. When true, failure of this step terminates the RunnerConfig with no further steps executing | + +**RunnerOperationalHistoryEntry** fields: + +| Field | Type | Description | +|---|---|---| +| appliedAt | metav1.Time | Time this change was applied | +| concern | string | What aspect of configuration changed | +| previousValue | string | Optional. Value before the change | +| newValue | string | Value after the change | +| appliedBy | string | Identity of who applied the change | + +### 4.3 status fields + +Status is written exclusively by the Conductor agent leader. + +| Field | Type | Description | +|---|---|---| +| capabilities | []RunnerCapabilityEntry | Optional. Self-declared capability manifest emitted by the Conductor agent on startup | +| agentVersion | string | Optional. Version string of the Conductor agent binary currently running | +| agentLeader | string | Optional. Pod name of the current Conductor agent leader | +| phase | string | Optional. Terminal execution phase written by Conductor exec mode. "Completed" means all steps succeeded. "Failed" means at least one step failed. Empty means execution is in progress | +| failedStep | string | Optional. Name of the first step that reached the Failed phase. Present only when phase="Failed" | +| stepResults | []RunnerConfigStepResult | Optional. Ordered list of step result records written by Conductor exec mode | +| conditions | []metav1.Condition | Optional. Standard Kubernetes condition list | + +**RunnerCapabilityEntry** fields: + +| Field | Type | Description | +|---|---|---| +| name | string | Capability name (e.g., pack-deploy, talos-upgrade) | +| version | string | Capability version declared by the agent | +| description | string | Optional. Human-readable description | + +**RunnerConfigStepResult** fields: + +| Field | Type | Description | +|---|---|---| +| name | string | Matches Name in the corresponding RunnerConfigStep | +| status | RunnerStepResultPhase | Terminal status: Succeeded, Failed, or Skipped | +| startedAt | *metav1.Time | Optional. Time this step began execution | +| completedAt | *metav1.Time | Optional. Time this step finished execution | +| message | string | Optional. Additional context about the step outcome | + +Platform operators watch `status.phase` to detect terminal conditions without scanning `status.stepResults`. + +--- + +## 5. DriftSignal + +### 5.1 Purpose + +DriftSignal is the three-state acknowledgement chain for drift events detected by Conductor role=tenant on a managed cluster. Conductor role=tenant writes the signal when it observes drift on a TalosCluster or PackDelivery CR. Conductor role=management reads the signal and orchestrates a corrective job. At-least-once delivery applies across federation retries. + +Conductor detects drift only for TalosCluster and PackDelivery. It writes the drift reason to the CR status, signals via DriftSignal, and never remediates directly (root Decision 14). + +### 5.2 State machine + +| State | Set by | Meaning | +|---|---|---| +| pending | conductor role=tenant | Signal written; not yet delivered to management cluster | +| delivered | federation channel | Signal transmitted to management cluster. At-least-once delivery | +| queued | conductor role=management | Corrective job accepted and enqueued; not yet complete | +| confirmed | conductor role=management | Corrective job completed; resolution acknowledged. Terminal state | + +### 5.3 Escalation protocol + +`spec.escalationCounter` is incremented by conductor role=tenant on each re-emit cycle when no acknowledgement has been received. When the counter reaches the configurable escalation threshold, conductor writes a `type=TerminalDrift` condition on the affected CR and stops re-emitting. Human intervention is required at that point. + +### 5.4 spec fields + +| Field | Type | Description | +|---|---|---| +| state | DriftSignalState | Current acknowledgement state: pending, delivered, queued, or confirmed | +| correlationID | string | UUID v4. Unique identifier for this drift event; used to deduplicate signals across federation retries | +| observedAt | metav1.Time | Time the drift was first observed by conductor role=tenant | +| affectedCRRef | DriftAffectedCRRef | Typed reference to the CR that exhibited drift | +| driftReason | string | Human-readable description of why drift was detected | +| correctionJobRef | string | Optional. Name of the corrective Job created by the management cluster. Set when state transitions to queued | +| escalationCounter | int32 | Optional. Number of times this signal has been re-emitted without acknowledgement | + +**DriftAffectedCRRef** fields: + +| Field | Type | Description | +|---|---|---| +| group | string | API group of the drifted CR | +| kind | string | Kind of the drifted CR | +| namespace | string | Optional. Namespace of the drifted CR. Empty for cluster-scoped resources | +| name | string | Name of the drifted CR | + +### 5.5 status fields + +Status is written by conductor role=management. + +| Field | Type | Description | +|---|---|---| +| observedGeneration | int64 | Optional. Generation most recently reconciled | +| conditions | []metav1.Condition | Optional. Standard Kubernetes condition list | + +### 5.6 Print columns + +`kubectl get ds` shows: State, CorrelationID, Age. + +--- + +## 6. SeamMembership + +### 6.1 Purpose + +SeamMembership is the formal join declaration for an operator wishing to become a member of the ONT platform operator family. An operator applies a SeamMembership CR on startup. Guardian validates the membership by verifying the referenced RBACProfile exists and has reached `provisioned=true`, and that the `domainIdentityRef` matches. Operators that are not admitted members may not receive PermissionSnapshots. + +### 6.2 spec fields + +| Field | Type | Description | +|---|---|---| +| appIdentityRef | string | The operator's application-layer identity. For current operators this is the operator's service account name | +| domainIdentityRef | string | References the DomainIdentity at `core.ontai.dev`. Must match the `domainIdentityRef` on the operator's RBACProfile | +| principalRef | string | Kubernetes service account that this operator runs as. Format: `system:serviceaccount:{namespace}:{name}`. Must match the `principalRef` on the operator's RBACProfile | +| tier | string | Membership tier. Valid values: `infrastructure` (Seam family operators), `application` (application operators) | + +### 6.3 status fields + +Status is written by guardian. + +| Field | Type | Description | +|---|---|---| +| admitted | bool | Optional. True when Guardian has validated and admitted this member | +| admittedAt | *metav1.Time | Optional. Timestamp when Guardian admitted this member | +| permissionSnapshotRef | string | Optional. Name of the PermissionSnapshot Guardian resolved for this member. Set after admission | +| conditions | []metav1.Condition | Optional. Standard Kubernetes condition list | + +Condition types: + +- `Admitted` -- True when Guardian has validated and admitted this member (all validation passes) +- `Validated` -- True when structural and cross-reference validation passes (domainIdentityRef matches RBACProfile, RBACProfile is provisioned) + +Condition reasons: + +| Reason | Condition | Description | +|---|---|---| +| MembershipAdmitted | Admitted=True | All validation passed | +| DomainIdentityMismatch | Admitted=False | spec.domainIdentityRef does not match the RBACProfile | +| PrincipalMismatch | Admitted=False | spec.principalRef does not match any RBACProfile principalRef | +| RBACProfileNotProvisioned | Admitted=False | Matching RBACProfile has not reached provisioned=true. Requeues | + +### 6.4 Print columns + +`kubectl get sm` shows: Admitted, Tier, Age. + +--- + +## 7. CreationRationale enumeration + +`pkg/lineage.CreationRationale` is the compile-time controlled vocabulary for why a derived object was created. Every `SealedCausalChain` carries exactly one value from this enumeration. It is not a free-text field and is not a per-operator registry. + +New values require a PR to this repository and Platform Governor review. No operator may extend the enumeration unilaterally (root Decision 5). + +| Value | Set by | Trigger | +|---|---|---| +| ClusterProvision | platform | A TalosCluster or related cluster lifecycle root declaration is created | +| ClusterDecommission | platform | A cluster decommission root declaration (e.g., ClusterReset) is created | +| SecurityEnforcement | guardian | A security plane root declaration (e.g., RBACPolicy, PermissionSet) causes a derived object | +| PackExecution | dispatcher | A pack delivery or execution root declaration (e.g., PackDelivery, PackExecution) is created | +| VirtualizationFulfillment | screen (future) | A virtualization workload root declaration is created. NOT IMPLEMENTED | +| ConductorAssignment | conductor agent mode | An operational assignment object is created by the management cluster Conductor | +| VortexBinding | vortex (future) | A portal policy binding root declaration is created. NOT IMPLEMENTED | + +--- + +## 8. SealedCausalChain type + +`pkg/lineage.SealedCausalChain` is the immutable causal chain field embedded in every Seam-managed CRD spec. All operators embed this type by reference rather than redefining its fields. + +Immutability contract: this field is authored once at object creation time and is sealed permanently. The admission webhook rejects any update that modifies any field within SealedCausalChain after the object has been created. No controller, human, or pipeline may alter this field post-admission. + +| Field | Type | Description | +|---|---|---| +| rootKind | string | Kind of the root declaration that caused this object to exist | +| rootName | string | Name of the root declaration | +| rootNamespace | string | Namespace of the root declaration | +| rootUID | types.UID | UID of the root declaration at creation time. Detects root replacement | +| creatingOperator | OperatorIdentity | Seam Operator that created this object | +| creationRationale | CreationRationale | Reason from the controlled vocabulary in section 7 | +| rootGenerationAtCreation | int64 | metadata.generation of the root declaration at creation time. Temporal anchor | + +**OperatorIdentity** subtype: + +| Field | Type | Description | +|---|---|---| +| name | string | Canonical operator name (e.g., platform, guardian, dispatcher, conductor) | +| version | string | Deployed version of the operator at creation time (e.g., v1.26.5-r3). Enables audit correlation | + +--- + +## 9. pkg/conditions vocabulary + +`pkg/conditions` is the single source of truth for all condition type and reason string constants used across guardian, platform, dispatcher, and conductor. Operators import these constants and do not declare local string aliases. + +### Cross-operator conditions (all operators) + +| Constant | String value | Used by | +|---|---|---| +| ConditionTypeLineageSynced | `LineageSynced` | All root-declaration reconcilers | +| ReasonLineageControllerAbsent | `LineageControllerAbsent` | All root-declaration reconcilers | + +LineageSynced lifecycle protocol (Declaration 5): + +1. On first observation, the responsible reconciler sets LineageSynced to False with reason LineageControllerAbsent. One-time write. +2. LineageController takes ownership on deployment and sets LineageSynced to True. +3. If LineageController is absent, the condition remains False indefinitely. This is the expected steady state during the stub phase. + +Terminal state: True (set by LineageController, not by the operator reconciler). + +The full condition vocabulary is in `pkg/conditions/conditions.go`. Operator-specific sections cover guardian, platform, and dispatcher condition types. + +--- + +## 10. Controllers + +### LineageController + +- Status: deferred implementation milestone (root Decision 6) +- Manages the lifecycle of LineageRecord CRs +- Is the sole principal permitted to create or update LineageRecord instances (root Decision 3) +- Watches root declaration GVKs (CRDs labelled `infrastructure.ontai.dev/lineage-root=true`) +- Appends DescendantEntry records as derived objects appear +- Writes OutcomeEntry records when terminal conditions are observed on derived objects +- Sets LineageSynced=True on root declarations it manages + +### DescendantReconciler + +- Watches derived objects that carry the `infrastructure.ontai.dev/root-ili` label +- Reads the label set written by `lineage.SetDescendantLabels` to locate the LineageRecord +- Appends the derived object to `spec.descendantRegistry` of the referenced LineageRecord +- Cross-namespace label: when the derived object is in a different namespace from the LineageRecord, uses `infrastructure.ontai.dev/root-ili-namespace` to resolve the reference + +--- + +## 11. Lineage provision standards + +These declarations define the platform-wide contract for how lineage fields are populated and who writes them. They apply to every operator in the ONT stack. + +**Declaration 1 -- One LineageRecord per root declaration.** +TalosCluster or PackDelivery creation produces exactly one LineageRecord anchored to that root. All derived objects record derivation back to the anchor. Records are not replicated per derived object. + +**Declaration 2 -- spec.lineage is immutable after admission.** +The SealedCausalChain embedded in each operator CRD spec is typed, immutable after the admission webhook processes the CREATE request, and carries creation context. Annotations are advisory. Spec fields are contractual. + +**Declaration 3 -- LineageRecord instances are controller-authored exclusively.** +No human or pipeline writes a LineageRecord. Only the owning controller creates it. The admission webhook enforces this. + +**Declaration 4 -- Lineage field introduced at stub phase.** +spec.lineage and the SealedCausalChain construction function are authored when types are first stubbed. Reconcilers proceed without LineageController being deployed. LineageController is a deferred milestone. + +**Declaration 5 -- LineageSynced is the reserved cross-operator condition.** +Every root declaration reconciler sets LineageSynced=False with reason LineageControllerAbsent on first observation. LineageController sets it True when deployed. Steady state without LineageController is LineageSynced=False. + +**Declaration 6 -- actorRef is propagated from the declaring-principal annotation.** +The admission webhook stamps `infrastructure.ontai.dev/declaring-principal` on root declaration CRDs at CREATE time. Operators read this annotation from the root object and pass it as `actorRef` to `lineage.SetDescendantLabels` at derived object creation. Pass empty string when the annotation is absent. + +--- + +## 12. Deferred implementations + +The following capabilities are designed and specified but not yet implemented: + +- LineageController -- manages LineageRecord lifecycle, appends descendant entries, writes outcome entries. Declaration 4. +- VirtualizationFulfillment rationale -- reserved for the Screen operator. INV-021: no Screen implementation until Governor-approved ADR. +- VortexBinding rationale -- reserved for the Vortex operator (future). +- `spec.domainRef` on LineageRecord -- references a DomainLineageIndex at `core.ontai.dev`. The `core.ontai.dev` group is not yet implemented. diff --git a/go.mod b/go.mod index 4af4a84..23f6c84 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/ontai-dev/seam-core +module github.com/ontai-dev/seam go 1.25.3 diff --git a/internal/controller/descendant_reconciler.go b/internal/controller/descendant_reconciler.go index 28e5b39..67691ef 100644 --- a/internal/controller/descendant_reconciler.go +++ b/internal/controller/descendant_reconciler.go @@ -29,8 +29,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/pkg/lineage" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/pkg/lineage" ) // Label keys operators must set on derived objects to trigger descendant tracking. @@ -46,8 +46,8 @@ const ( // watches. Operators set LabelRootILI on objects of these kinds at creation time. // One DescendantReconciler instance is registered per GVK in main.go. var DerivedObjectGVKs = []schema.GroupVersionKind{ - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureRunnerConfig"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "RunnerConfig"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, } // DescendantReconciler watches a single derived-object GVK and appends @@ -89,7 +89,7 @@ func (r *DescendantReconciler) Reconcile(ctx context.Context, req ctrl.Request) } // Fetch the referenced ILI. - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} iliKey := client.ObjectKey{Name: iliName, Namespace: iliNamespace} if err := r.Client.Get(ctx, iliKey, ili); err != nil { if apierrors.IsNotFound(err) { diff --git a/internal/controller/dsns_reconciler.go b/internal/controller/dsns_reconciler.go index ee5489d..d96924a 100644 --- a/internal/controller/dsns_reconciler.go +++ b/internal/controller/dsns_reconciler.go @@ -24,19 +24,19 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - idns "github.com/ontai-dev/seam-core/internal/dns" + idns "github.com/ontai-dev/seam/internal/dns" ) // categoryForKind maps a GVK kind to a DSNS record category constant. func categoryForKind(kind string) string { switch kind { - case "InfrastructureTalosCluster", "SeamInfrastructureCluster", "SeamInfrastructureMachine": + case "TalosCluster", "SeamInfrastructureCluster", "SeamInfrastructureMachine": return idns.RecordCategoryClusterTopology case "IdentityBinding", "IdentityProvider": return idns.RecordCategoryIdentityPlane - case "InfrastructurePackInstance", "InfrastructureClusterPack", "InfrastructurePackExecution": + case "PackInstalled", "PackDelivery", "PackExecution": return idns.RecordCategoryPackLineage - case "InfrastructureRunnerConfig": + case "RunnerConfig": return idns.RecordCategoryExecutionAuthority default: return idns.RecordCategoryClusterTopology @@ -71,7 +71,7 @@ func recordStrings(records []idns.Record) []string { // severityForObject returns the DSNSEvent severity for an object based on its // current condition state. Degraded condition → warning; all other states → informational. func severityForObject(obj *unstructured.Unstructured, kind string) string { - if kind == "InfrastructureRunnerConfig" && hasConditionTrue(obj, "Degraded") { + if kind == "RunnerConfig" && hasConditionTrue(obj, "Degraded") { return idns.SeverityWarning } return idns.SeverityInformational @@ -120,21 +120,21 @@ const DSNSFinalizer = "dsns.infrastructure.ontai.dev/cleanup" // CRD state is projected to DNS records in seam.ontave.dev. // seam-core-schema.md §8 Decision 4. var DSNSGVKs = []schema.GroupVersionKind{ - // Platform operator — InfrastructureTalosCluster Ready state → cluster A, api A, role TXT - // (or sovereign NS delegation for screen provider). Decision G. - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"}, + // Platform operator — TalosCluster Ready state → cluster A, api A, role TXT + // (or sovereign NS delegation for screen provider). MIGRATION-3.1: seam.ontai.dev. + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"}, - // Wrapper operator — InfrastructurePackInstance terminal Succeeded state → pack TXT. Decision G. - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, + // Wrapper operator — PackInstalled terminal Succeeded state → pack TXT. Decision G. + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, // Guardian operator — IdentityBinding resolved → identity TXT. - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, // Guardian operator — IdentityProvider Valid → idp TXT. - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, - // Conductor — InfrastructureRunnerConfig terminal state → run TXT. Decision G. - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureRunnerConfig"}, + // Conductor — RunnerConfig terminal state → run TXT. Decision G. + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "RunnerConfig"}, } // DSNSReconciler watches a single GVK and projects CRD state to DNS records. @@ -252,9 +252,9 @@ func (r *DSNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. // TalosCluster: log the cluster name and Ready status before derivation to aid // diagnosis when the cluster is Ready but records are not appearing in the zone. // The reconciler watches all namespaces and requires Ready=True to emit records. - if r.GVK.Kind == "InfrastructureTalosCluster" { + if r.GVK.Kind == "TalosCluster" { ready := hasConditionTrue(obj, "Ready") - logger.V(1).Info("reconciling InfrastructureTalosCluster DNS records", + logger.V(1).Info("reconciling TalosCluster DNS records", "cluster", obj.GetName(), "namespace", obj.GetNamespace(), "ready", ready) } records := r.deriveRecords(obj) @@ -273,15 +273,15 @@ func (r *DSNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. // seam-core-schema.md §8 Decision 4. func (r *DSNSReconciler) deriveRecords(obj *unstructured.Unstructured) []idns.Record { switch r.GVK.Kind { - case "InfrastructureTalosCluster": + case "TalosCluster": return deriveTalosClusterRecords(obj) case "IdentityBinding": return deriveIdentityBindingRecords(obj) case "IdentityProvider": return deriveIdentityProviderRecords(obj) - case "InfrastructurePackInstance": + case "PackInstalled": return derivePackInstanceRecords(obj) - case "InfrastructureRunnerConfig": + case "RunnerConfig": return deriveRunnerConfigRecords(obj) default: return nil diff --git a/internal/controller/lineage_controller.go b/internal/controller/lineage_controller.go index 48f7451..9418649 100644 --- a/internal/controller/lineage_controller.go +++ b/internal/controller/lineage_controller.go @@ -29,43 +29,42 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + lineagepkg "github.com/ontai-dev/seam/pkg/lineage" ) // GovernanceAnnotationPrefix is the reserved governance sub-prefix under which -// the InfrastructureLineageController writes annotations on root declaration CRs -// and on InfrastructureLineageIndex instances. Individual Seam Operators are +// the LineageController writes annotations on root declaration CRs +// and on LineageRecord instances. Individual Seam Operators are // prohibited from writing under this sub-prefix. seam-core-schema.md §7 Declaration 4. const GovernanceAnnotationPrefix = "governance.infrastructure.ontai.dev" // GovernanceAnnotationLineageIndexRef is written on root declaration CRs to record -// the name of the InfrastructureLineageIndex created for that declaration. +// the name of the LineageRecord created for that declaration. const GovernanceAnnotationLineageIndexRef = GovernanceAnnotationPrefix + "/lineage-index-ref" -// GovernanceAnnotationControllerAuthored is written on InfrastructureLineageIndex -// instances to assert controller-authorship per CLAUDE.md §14 Decision 3. +// GovernanceAnnotationControllerAuthored is written on LineageRecord +// instances to assert controller-authorship per CLAUDE.md Decision 3. const GovernanceAnnotationControllerAuthored = GovernanceAnnotationPrefix + "/controller-authored" // ReasonLineageIndexCreated is the reason set on the LineageSynced condition when -// the InfrastructureLineageController successfully creates an ILI for the root declaration. +// the LineageController successfully creates a LineageRecord for the root declaration. const ReasonLineageIndexCreated = "LineageIndexCreated" // InfrastructureDomainRef is the canonical domainRef value for all Seam infrastructure -// ILIs. It is the {name}.{group} reference to the DomainLineageIndex at core.ontai.dev -// that the InfrastructureLineageIndex instantiates. All infrastructure ILIs trace to -// this single domain root. CLAUDE.md §14 Decision 2. +// LineageRecords. CLAUDE.md Decision 2. const InfrastructureDomainRef = "infrastructure.core.ontai.dev" // RootDeclarationGVK names all root-declaration CRD GroupVersionKinds that the -// InfrastructureLineageController watches. One InfrastructureLineageIndex is created -// per observed instance of any of these kinds. +// LineageController watches. One LineageRecord is created per observed instance +// of any of these kinds. // -// CLAUDE.md §14 Decision 4 — one index per root declaration across all operators. +// CLAUDE.md Decision 4 -- one record per root declaration across all operators. var RootDeclarationGVKs = []schema.GroupVersionKind{ - // Platform operator — infrastructure.ontai.dev (Decision G) - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"}, + // Platform operator -- seam.ontai.dev (MIGRATION-3.1) + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"}, - // Platform operator — platform.ontai.dev (operational root declarations) + // Platform operator -- platform.ontai.dev (operational root declarations) {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "UpgradePolicy"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "NodeMaintenance"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "ClusterMaintenance"}, @@ -77,21 +76,21 @@ var RootDeclarationGVKs = []schema.GroupVersionKind{ {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "TalosMachineConfigRestore"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "HardeningProfile"}, - // Platform CAPI provider — infrastructure.ontai.dev + // Platform CAPI provider -- infrastructure.ontai.dev {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "SeamInfrastructureCluster"}, {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "SeamInfrastructureMachine"}, - // Wrapper operator — infrastructure.ontai.dev (Decision G) - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureClusterPack"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackExecution"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, - - // Guardian operator — security.ontai.dev - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "RBACProfile"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "PermissionSet"}, + // Dispatcher operator -- seam.ontai.dev (MIGRATION-3.3-3.7) + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackExecution"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, + + // Guardian operator -- guardian.ontai.dev (constitutional refactor 2026-05-12) + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACProfile"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "PermissionSet"}, } // LineageReconciler watches a single root-declaration GVK and reconciles @@ -131,13 +130,26 @@ func (r *LineageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, fmt.Errorf("failed to get %s %s: %w", r.GVK.Kind, req.NamespacedName, err) } + // Step A1 -- Check the lineage-root CRD label. Only GVKs whose CRD carries + // infrastructure.ontai.dev/lineage-root="true" produce a new LineageRecord. + // All other GVKs are derived objects; they are forwarded to handleDerivedObject + // which resolves the nearest root via ownerReferences. + isRoot, err := IsRootDeclaration(ctx, r.Client, r.GVK) + if err != nil { + logger.Error(err, "CRD lineage-root label check failed — treating as non-root; requeuing") + return ctrl.Result{RequeueAfter: 30 * time.Second}, nil + } + if !isRoot { + return r.handleDerivedObject(ctx, root) + } + // Step B — Check idempotency guard: governance annotation already set means // this root declaration has already been processed. Verify ILI exists and return. iliName := lineageIndexName(r.GVK.Kind, root.GetName()) if existing, ok := root.GetAnnotations()[GovernanceAnnotationLineageIndexRef]; ok && existing == iliName { // Idempotency guard: annotation already set with the correct ILI name. // Verify the ILI still exists; if not, re-create it. - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} err := r.Client.Get(ctx, client.ObjectKey{Name: iliName, Namespace: root.GetNamespace()}, ili) if err == nil { // ILI exists and annotation is set — ensure LineageSynced=True. @@ -152,7 +164,7 @@ func (r *LineageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } // Step C — Get or create the InfrastructureLineageIndex. - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} iliKey := client.ObjectKey{Name: iliName, Namespace: root.GetNamespace()} if err := r.Client.Get(ctx, iliKey, ili); err != nil { if !apierrors.IsNotFound(err) { @@ -216,13 +228,13 @@ func (r *LineageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // root declaration and populates rootBinding.declaringPrincipal. If the annotation // is absent (bootstrap window or pre-amendment object), declaringPrincipal is set // to "system:unknown". seam-core-schema.md §7 Declaration 6. -func (r *LineageReconciler) buildILI(root *unstructured.Unstructured, iliName string) *seamv1alpha1.InfrastructureLineageIndex { +func (r *LineageReconciler) buildILI(root *unstructured.Unstructured, iliName string) *seamv1alpha1.LineageRecord { declaringPrincipal := root.GetAnnotations()["infrastructure.ontai.dev/declaring-principal"] if declaringPrincipal == "" { declaringPrincipal = "system:unknown" } - return &seamv1alpha1.InfrastructureLineageIndex{ + return &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ Name: iliName, Namespace: root.GetNamespace(), @@ -239,8 +251,8 @@ func (r *LineageReconciler) buildILI(root *unstructured.Unstructured, iliName st "infrastructure.ontai.dev/root-name": root.GetName(), }, }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ RootKind: r.GVK.Kind, RootName: root.GetName(), RootNamespace: root.GetNamespace(), @@ -356,7 +368,7 @@ const defaultDescendantRetentionDays = 30 // // A nil CreatedAt timestamp means the entry predates retention tracking — the entry // is never pruned to preserve backward compatibility. -func (r *LineageReconciler) pruneStaleDescendants(ctx context.Context, ili *seamv1alpha1.InfrastructureLineageIndex) error { +func (r *LineageReconciler) pruneStaleDescendants(ctx context.Context, ili *seamv1alpha1.LineageRecord) error { if len(ili.Spec.DescendantRegistry) == 0 { return nil } @@ -426,7 +438,7 @@ func (r *LineageReconciler) pruneStaleDescendants(ctx context.Context, ili *seam // declaration is deleted. // // The ownerReference is idempotent — if it is already set, no patch is issued. -func (r *LineageReconciler) ensureOwnerReferenceIfDeleteWithRoot(ctx context.Context, root *unstructured.Unstructured, ili *seamv1alpha1.InfrastructureLineageIndex) error { +func (r *LineageReconciler) ensureOwnerReferenceIfDeleteWithRoot(ctx context.Context, root *unstructured.Unstructured, ili *seamv1alpha1.LineageRecord) error { deleteWithRoot := true // default per RetentionPolicy if ili.Spec.RetentionPolicy != nil { deleteWithRoot = ili.Spec.RetentionPolicy.DeleteWithRoot @@ -459,6 +471,157 @@ func (r *LineageReconciler) ensureOwnerReferenceIfDeleteWithRoot(ctx context.Con return r.Client.Patch(ctx, ili, patch) } +// CRDNameForGVK returns the CRD object name for a GVK using the standard plural convention: +// - lowercase kind +// - trailing 'y' replaced with 'ies' +// - 's' appended otherwise +// - suffixed with "." + group +func CRDNameForGVK(gvk schema.GroupVersionKind) string { + kind := strings.ToLower(gvk.Kind) + var plural string + switch { + case strings.HasSuffix(kind, "y"): + plural = kind[:len(kind)-1] + "ies" + case strings.HasSuffix(kind, "s"): + plural = kind + "es" + default: + plural = kind + "s" + } + return plural + "." + gvk.Group +} + +// IsRootDeclaration reports whether the CRD for gvk carries the lineage-root label +// (infrastructure.ontai.dev/lineage-root="true"). Returns false (not an error) when +// the CRD object is not found in the API server. +func IsRootDeclaration(ctx context.Context, c client.Client, gvk schema.GroupVersionKind) (bool, error) { + crdName := CRDNameForGVK(gvk) + crd := &unstructured.Unstructured{} + crd.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", + }) + if err := c.Get(ctx, client.ObjectKey{Name: crdName}, crd); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("get CRD %s: %w", crdName, err) + } + labels, _, _ := unstructured.NestedStringMap(crd.Object, "metadata", "labels") + return labels[lineagepkg.LabelLineageRoot] == "true", nil +} + +// ResolveRootOwner walks ownerReferences from obj up to maxHops to find an owner +// whose GVK CRD carries the lineage-root label. Returns nil, nil when no root +// owner is found within maxHops. +func ResolveRootOwner(ctx context.Context, c client.Client, obj *unstructured.Unstructured, maxHops int) (*unstructured.Unstructured, error) { + current := obj + for hop := 0; hop < maxHops; hop++ { + refs := current.GetOwnerReferences() + if len(refs) == 0 { + return nil, nil + } + // Prefer the controller ownerRef; fall back to the first ref. + ref := refs[0] + for _, r := range refs { + if r.Controller != nil && *r.Controller { + ref = r + break + } + } + gv, err := schema.ParseGroupVersion(ref.APIVersion) + if err != nil { + return nil, fmt.Errorf("parse ownerRef APIVersion %q: %w", ref.APIVersion, err) + } + ownerGVK := gv.WithKind(ref.Kind) + + isRoot, err := IsRootDeclaration(ctx, c, ownerGVK) + if err != nil { + return nil, fmt.Errorf("CRD check for owner %v: %w", ownerGVK, err) + } + + owner := &unstructured.Unstructured{} + owner.SetGroupVersionKind(ownerGVK) + if err := c.Get(ctx, client.ObjectKey{Name: ref.Name, Namespace: current.GetNamespace()}, owner); err != nil { + if apierrors.IsNotFound(err) { + return nil, nil + } + return nil, fmt.Errorf("get owner %s %s: %w", ref.Kind, ref.Name, err) + } + + if isRoot { + return owner, nil + } + current = owner + } + return nil, nil +} + +// handleDerivedObject is called when the reconciled GVK is not a lineage root. +// It walks ownerReferences to find the nearest root and appends a DescendantEntry +// to that root's LineageRecord. If no root is found within 3 hops, a warning is +// logged and the object is requeued. +func (r *LineageReconciler) handleDerivedObject(ctx context.Context, obj *unstructured.Unstructured) (ctrl.Result, error) { + logger := log.FromContext(ctx).WithValues("gvk", r.GVK.String(), "name", obj.GetName()) + + root, err := ResolveRootOwner(ctx, r.Client, obj, 3) + if err != nil { + logger.Error(err, "ownerRef walk failed — requeuing") + return ctrl.Result{RequeueAfter: 30 * time.Second}, nil + } + if root == nil { + logger.Info("no lineage-root owner found within 3 ownerRef hops — requeuing", + "namespace", obj.GetNamespace()) + return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil + } + + iliName := lineageIndexName(root.GroupVersionKind().Kind, root.GetName()) + ili := &seamv1alpha1.LineageRecord{} + if err := r.Client.Get(ctx, client.ObjectKey{Name: iliName, Namespace: root.GetNamespace()}, ili); err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + return ctrl.Result{}, fmt.Errorf("get LineageRecord %s: %w", iliName, err) + } + + // Idempotency: skip if entry for this UID already exists. + objUID := obj.GetUID() + for _, entry := range ili.Spec.DescendantRegistry { + if entry.UID == objUID { + return ctrl.Result{}, nil + } + } + + labels := obj.GetLabels() + seamOperator := labels["infrastructure.ontai.dev/seam-operator"] + if seamOperator == "" { + seamOperator = "unknown" + } + rationaleStr := labels["infrastructure.ontai.dev/creation-rationale"] + if rationaleStr == "" { + rationaleStr = string(lineagepkg.ClusterProvision) + } + now := metav1.Now() + entry := seamv1alpha1.DescendantEntry{ + Group: r.GVK.Group, + Version: r.GVK.Version, + Kind: r.GVK.Kind, + Name: obj.GetName(), + Namespace: obj.GetNamespace(), + UID: objUID, + SeamOperator: seamOperator, + CreationRationale: lineagepkg.CreationRationale(rationaleStr), + RootGenerationAtCreation: root.GetGeneration(), + CreatedAt: &now, + } + + patch := client.MergeFrom(ili.DeepCopy()) + ili.Spec.DescendantRegistry = append(ili.Spec.DescendantRegistry, entry) + logger.Info("appended DescendantEntry to LineageRecord", + "iliName", iliName, "rootKind", root.GroupVersionKind().Kind, "rootName", root.GetName()) + return ctrl.Result{}, r.Client.Patch(ctx, ili, patch) +} + // lineageIndexName returns the deterministic InfrastructureLineageIndex name for // a given root declaration kind and name. The format is: // {lowercasekind}-{name} diff --git a/internal/controller/outcome_reconciler.go b/internal/controller/outcome_reconciler.go index 43c2e28..5a10291 100644 --- a/internal/controller/outcome_reconciler.go +++ b/internal/controller/outcome_reconciler.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" ) // OutcomeReconciler watches derived object GVKs and appends OutcomeEntry records @@ -65,7 +65,7 @@ func (r *OutcomeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct if iliNamespace == "" { iliNamespace = obj.GetNamespace() } - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} iliKey := client.ObjectKey{Name: iliName, Namespace: iliNamespace} if err := r.Client.Get(ctx, iliKey, ili); err != nil { if apierrors.IsNotFound(err) { diff --git a/internal/webhook/authorship_gate.go b/internal/webhook/authorship_gate.go index 2551d04..f6ced52 100644 --- a/internal/webhook/authorship_gate.go +++ b/internal/webhook/authorship_gate.go @@ -1,7 +1,7 @@ // authorship_gate.go contains only pure functions and value types for the -// controller-authorship admission gate on InfrastructureLineageIndex. +// controller-authorship admission gate on LineageRecord. // -// AUTHORSHIP CONTRACT: InfrastructureLineageIndex instances are controller-authored +// AUTHORSHIP CONTRACT: LineageRecord instances are controller-authored // exclusively. No human operator, no automation pipeline, and no other controller // may create or update them. The admission webhook rejects any CREATE or UPDATE // whose requesting principal is not the LineageController ServiceAccount. @@ -46,18 +46,18 @@ type AuthorshipGateDecision struct { } // EvaluateAuthorshipGate applies the controller-authorship policy to an incoming -// admission request for InfrastructureLineageIndex. It is a pure function: no +// admission request for LineageRecord. It is a pure function: no // side effects, no Kubernetes API calls, no I/O. // // Evaluation order: -// 1. If Kind is not InfrastructureLineageIndex, allow unconditionally. +// 1. If Kind is not LineageRecord, allow unconditionally. // 2. If the operation is DELETE, allow unconditionally. // The authorship gate covers CREATE and UPDATE only. // 3. If RequestingUser matches LineageControllerIdentity, allow. // 4. Otherwise, reject — the request is not from the authorized LineageController // ServiceAccount. CLAUDE.md §14 Decision 3. func EvaluateAuthorshipGate(req AuthorshipGateRequest) AuthorshipGateDecision { - if req.Kind != InfrastructureLineageIndexKind { + if req.Kind != LineageRecordKind { return AuthorshipGateDecision{Allowed: true} } @@ -72,10 +72,10 @@ func EvaluateAuthorshipGate(req AuthorshipGateRequest) AuthorshipGateDecision { return AuthorshipGateDecision{ Allowed: false, Reason: fmt.Sprintf( - "InfrastructureLineageIndex instances are controller-authored exclusively; "+ + "LineageRecord instances are controller-authored exclusively; "+ "only the InfrastructureLineageController ServiceAccount (%q) may create or "+ "update them — no human operator, automation pipeline, or other controller "+ - "is authorized to write InfrastructureLineageIndex resources "+ + "is authorized to write LineageRecord resources "+ "(CLAUDE.md §14 Decision 3, seam-core-schema.md §7 Declaration 4); "+ "requesting user %q is not authorized", LineageControllerIdentity, req.RequestingUser, diff --git a/internal/webhook/domainref_validation.go b/internal/webhook/domainref_validation.go index 3bd0f04..b1d7c72 100644 --- a/internal/webhook/domainref_validation.go +++ b/internal/webhook/domainref_validation.go @@ -1,7 +1,7 @@ // domainref_validation.go contains pure functions and value types for the -// spec.domainRef validation gate on InfrastructureLineageIndex. +// spec.domainRef validation gate on LineageRecord. // -// DOMAINREF CONTRACT: When spec.domainRef is set on a new InfrastructureLineageIndex, +// DOMAINREF CONTRACT: When spec.domainRef is set on a new LineageRecord, // it must equal the canonical infrastructure domain reference ("infrastructure.core.ontai.dev"). // Unknown values are rejected immediately. Empty is permitted — the LineageController // will set the correct value during reconciliation. @@ -16,7 +16,7 @@ import "fmt" const DomainRefWebhookPath = "/validate-lineage-index-domainref" // ValidInfrastructureDomainRef is the only accepted non-empty value for -// spec.domainRef on InfrastructureLineageIndex instances. It is the +// spec.domainRef on LineageRecord instances. It is the // {name}.{group} reference to the DomainLineageIndex at core.ontai.dev // that this infrastructure ILI instantiates. CLAUDE.md §14 Decision 2. const ValidInfrastructureDomainRef = "infrastructure.core.ontai.dev" @@ -41,18 +41,18 @@ type DomainRefValidationDecision struct { } // EvaluateDomainRefValidation validates spec.domainRef on CREATE requests for -// InfrastructureLineageIndex. It is a pure function: no side effects, no +// LineageRecord. It is a pure function: no side effects, no // Kubernetes API calls, no I/O. // // Evaluation order: -// 1. If Kind is not InfrastructureLineageIndex, allow unconditionally. +// 1. If Kind is not LineageRecord, allow unconditionally. // 2. If the operation is not CREATE, allow unconditionally. // domainRef is authored at creation time; updates are not re-validated here. // 3. If domainRef is empty, allow — the LineageController will populate it. // 4. If domainRef equals ValidInfrastructureDomainRef, allow. // 5. Otherwise, reject — unknown domain ref value. func EvaluateDomainRefValidation(req DomainRefValidationRequest) DomainRefValidationDecision { - if req.Kind != InfrastructureLineageIndexKind { + if req.Kind != LineageRecordKind { return DomainRefValidationDecision{Allowed: true} } if req.Operation != OperationCreate { @@ -69,7 +69,7 @@ func EvaluateDomainRefValidation(req DomainRefValidationRequest) DomainRefValida Reason: fmt.Sprintf( "spec.domainRef must be %q for infrastructure domain ILIs; "+ "unknown domain ref %q — the only valid traceability link for "+ - "InfrastructureLineageIndex is the infrastructure domain root at core.ontai.dev "+ + "LineageRecord is the infrastructure domain root at core.ontai.dev "+ "(seam-core-schema.md §3, CLAUDE.md §14 Decision 2)", ValidInfrastructureDomainRef, req.DomainRef, ), diff --git a/internal/webhook/rootbinding_immutability.go b/internal/webhook/rootbinding_immutability.go index 7cd35a8..68f8530 100644 --- a/internal/webhook/rootbinding_immutability.go +++ b/internal/webhook/rootbinding_immutability.go @@ -3,10 +3,10 @@ // // This file (rootbinding_immutability.go) contains only pure functions and // value types for the spec.rootBinding immutability gate on -// InfrastructureLineageIndex. It has no imports from +// LineageRecord. It has no imports from // sigs.k8s.io/controller-runtime/pkg/webhook. // -// IMMUTABILITY CONTRACT: spec.rootBinding on InfrastructureLineageIndex is +// IMMUTABILITY CONTRACT: spec.rootBinding on LineageRecord is // authored once at creation time and sealed permanently. The admission webhook // rejects any UPDATE request that modifies any field in spec.rootBinding. // seam-core-schema.md §3.1, domain-core-schema.md §2.1. @@ -22,9 +22,9 @@ import ( // admission webhook is registered in the Seam Core webhook server. const RootBindingWebhookPath = "/validate-lineage-index-immutability" -// InfrastructureLineageIndexKind is the kind name for InfrastructureLineageIndex. +// LineageRecordKind is the kind name for LineageRecord (formerly LineageRecord). // The immutability gate intercepts only this kind. -const InfrastructureLineageIndexKind = "InfrastructureLineageIndex" +const LineageRecordKind = "LineageRecord" // AdmissionOperation is the type of operation for an incoming admission request. type AdmissionOperation string @@ -42,7 +42,7 @@ const ( // It contains only the fields required for the immutability decision, decoupled // from any Kubernetes API machinery. type RootBindingImmutabilityRequest struct { - // Kind is the resource kind being admitted (e.g., "InfrastructureLineageIndex"). + // Kind is the resource kind being admitted (e.g., "LineageRecord"). Kind string // Operation is the admission operation type. Operation AdmissionOperation @@ -63,11 +63,11 @@ type RootBindingImmutabilityDecision struct { } // EvaluateRootBindingImmutability applies the spec.rootBinding immutability policy -// to an incoming admission request for InfrastructureLineageIndex. It is a pure +// to an incoming admission request for LineageRecord. It is a pure // function: no side effects, no Kubernetes API calls, no I/O. // // Evaluation order: -// 1. If Kind is not InfrastructureLineageIndex, allow unconditionally. +// 1. If Kind is not LineageRecord, allow unconditionally. // 2. If the operation is not UPDATE (CREATE, DELETE), allow unconditionally. // rootBinding is authored at CREATE time. DELETE is always permitted. // 3. If old and new spec.rootBinding are semantically equal (both absent, or @@ -75,7 +75,7 @@ type RootBindingImmutabilityDecision struct { // 4. Otherwise, reject — spec.rootBinding has been modified. // seam-core-schema.md §3.1, domain-core-schema.md §2.1. func EvaluateRootBindingImmutability(req RootBindingImmutabilityRequest) RootBindingImmutabilityDecision { - if req.Kind != InfrastructureLineageIndexKind { + if req.Kind != LineageRecordKind { return RootBindingImmutabilityDecision{Allowed: true} } @@ -94,8 +94,8 @@ func EvaluateRootBindingImmutability(req RootBindingImmutabilityRequest) RootBin "the rootBinding section identifies the root declaration that anchors this "+ "lineage index and is sealed at admission — any field change is rejected "+ "(seam-core-schema.md §3.1, domain-core-schema.md §2.1); "+ - "to record a different root binding, create a new InfrastructureLineageIndex", - InfrastructureLineageIndexKind, + "to record a different root binding, create a new LineageRecord", + LineageRecordKind, ), } } diff --git a/pkg/conditions/conditions.go b/pkg/conditions/conditions.go index f548a09..213da63 100644 --- a/pkg/conditions/conditions.go +++ b/pkg/conditions/conditions.go @@ -890,16 +890,16 @@ const ( ) const ( - // ConditionTypeWrapperRunnerRBACNotReady is set when the wrapper-runner + // ConditionTypeDispatcherRunnerRBACNotReady is set when the dispatcher-runner // ServiceAccount in the target cluster namespace lacks a required RBAC - // permission. Gate 5 of the PackExecution gate check — runs via + // permission. Gate 5 of the PackExecution gate check -- runs via // SubjectAccessReview before the Kueue Job is submitted. // Terminal state: False (all required verbs allowed, proceed). - // Operators: wrapper (PackExecution). - ConditionTypeWrapperRunnerRBACNotReady = "WrapperRunnerRBACNotReady" + // Operators: dispatcher (PackExecution). + ConditionTypeDispatcherRunnerRBACNotReady = "DispatcherRunnerRBACNotReady" - // ReasonWrapperRunnerRBACNotReady is set on both True and False states. - ReasonWrapperRunnerRBACNotReady = "WrapperRunnerRBACNotReady" + // ReasonDispatcherRunnerRBACNotReady is set on both True and False states. + ReasonDispatcherRunnerRBACNotReady = "DispatcherRunnerRBACNotReady" ) const ( diff --git a/pkg/conditions/validate.go b/pkg/conditions/validate.go index 5da4800..ef533dd 100644 --- a/pkg/conditions/validate.go +++ b/pkg/conditions/validate.go @@ -233,8 +233,8 @@ var vocabulary = map[string]map[string]struct{}{ ConditionTypeRBACProfileNotProvisioned: reasons( ReasonRBACProfileNotReady, ), - ConditionTypeWrapperRunnerRBACNotReady: reasons( - ReasonWrapperRunnerRBACNotReady, + ConditionTypeDispatcherRunnerRBACNotReady: reasons( + ReasonDispatcherRunnerRBACNotReady, ), ConditionTypePackExecutionFailed: reasons( ReasonJobFailed, diff --git a/pkg/e2e/client.go b/pkg/e2e/client.go index 579017d..cd61114 100644 --- a/pkg/e2e/client.go +++ b/pkg/e2e/client.go @@ -6,7 +6,7 @@ // // Usage pattern in operator e2e suites: // -// import e2ehelpers "github.com/ontai-dev/seam-core/pkg/e2e" +// import e2ehelpers "github.com/ontai-dev/seam/pkg/e2e" // // var mgmt *e2ehelpers.ClusterClient // diff --git a/pkg/e2e/poller.go b/pkg/e2e/poller.go index 93bb9c5..756569d 100644 --- a/pkg/e2e/poller.go +++ b/pkg/e2e/poller.go @@ -9,7 +9,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/ontai-dev/seam-core/pkg/conditions" + "github.com/ontai-dev/seam/pkg/conditions" ) // DefaultPollTimeout is the default timeout for ConditionPoller. diff --git a/pkg/lineage/descendant.go b/pkg/lineage/descendant.go index f94c027..b7c2051 100644 --- a/pkg/lineage/descendant.go +++ b/pkg/lineage/descendant.go @@ -6,6 +6,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// LabelLineageRoot is the CRD metadata label key that marks a kind as a lineage +// root declaration. The LineageController reads this label from the CRD object +// in the API server to determine whether a reconciled CR should produce a new +// LineageRecord. Only TalosCluster and PackDelivery CRDs carry this label. +const LabelLineageRoot = "infrastructure.ontai.dev/lineage-root" + // LabelRootILINamespace is the optional label key that carries the namespace // of the InfrastructureLineageIndex when it differs from the derived object's // namespace. DescendantReconciler reads this label and uses it for the ILI diff --git a/test/e2e/ac4_lineage_controller_test.go b/test/e2e/ac4_lineage_controller_test.go index 6fc56c1..4f62d0a 100644 --- a/test/e2e/ac4_lineage_controller_test.go +++ b/test/e2e/ac4_lineage_controller_test.go @@ -2,16 +2,16 @@ package e2e_test // AC-4: LineageController manifest tracking acceptance contract. // -// Scenario: After seam-core is installed on ccs-mgmt and the InfrastructureLineageController -// is running, every root declaration CR must have exactly one InfrastructureLineageIndex +// Scenario: After seam-core is installed on ccs-mgmt and the LineageController +// is running, every root declaration CR must have exactly one LineageRecord // created with the correct rootBinding and governance annotation. // -// - Exactly one ILI per root declaration (Lineage Index Pattern) -// - ILI name is {lowercasekind}-{name} +// - Exactly one LineageRecord per root declaration (Lineage Index Pattern) +// - LineageRecord name is {lowercasekind}-{name} // - governance.infrastructure.ontai.dev/lineage-index-ref set on root declaration // - LineageSynced=True with reason LineageIndexCreated // - DescendantRegistry starts empty -// - ILI is not deleted when root declaration is deleted (audit retention) +// - LineageRecord is not deleted when root declaration is deleted (audit retention) // // Promotion condition: requires live cluster with MGMT_KUBECONFIG and // TENANT-CLUSTER-E2E closed (ccs-dev onboarded as tenant cluster). @@ -23,7 +23,7 @@ import ( ) var _ = Describe("AC-4: LineageController manifest tracking", func() { - It("InfrastructureLineageController creates one ILI per TalosCluster root declaration", func() { + It("LineageController creates one LineageRecord per TalosCluster root declaration", func() { Skip("requires live cluster with MGMT_KUBECONFIG and TENANT-CLUSTER-E2E closed") }) diff --git a/test/e2e/lineage_controller_test.go b/test/e2e/lineage_controller_test.go index fb38b0d..ea48df2 100644 --- a/test/e2e/lineage_controller_test.go +++ b/test/e2e/lineage_controller_test.go @@ -10,19 +10,19 @@ package e2e_test // (the LineageController watches root declarations) // // What this test verifies (seam-core-schema.md §3, conductor-schema.md §14 Decision 3): -// - LineageController creates exactly one InfrastructureLineageIndex per root declaration -// - ILI name follows the lineage.IndexName(rootKind, rootName) pattern -// - ILI spec.rootBinding fields match the root declaration (kind, name, namespace, UID, generation) -// - ILI spec.rootBinding is immutable — an attempted UPDATE to rootBinding is rejected -// - ILI spec.descendantRegistry starts empty and grows as derived objects are created -// - A second TalosCluster CR creates a separate ILI (one per root, not shared) +// - LineageController creates exactly one LineageRecord per root declaration +// - LineageRecord name follows the lineage.IndexName(rootKind, rootName) pattern +// - LineageRecord spec.rootBinding fields match the root declaration (kind, name, namespace, UID, generation) +// - LineageRecord spec.rootBinding is immutable — an attempted UPDATE to rootBinding is rejected +// - LineageRecord spec.descendantRegistry starts empty and grows as derived objects are created +// - A second TalosCluster CR creates a separate LineageRecord (one per root, not shared) import ( . "github.com/onsi/ginkgo/v2" ) var _ = Describe("LineageController index creation", func() { - It("LineageController creates one InfrastructureLineageIndex per TalosCluster", func() { + It("LineageController creates one LineageRecord per TalosCluster", func() { Skip("lab cluster not yet provisioned") }) @@ -30,11 +30,11 @@ var _ = Describe("LineageController index creation", func() { Skip("lab cluster not yet provisioned") }) - It("ILI spec.rootBinding is immutable — webhook rejects UPDATE to any rootBinding field", func() { + It("LineageRecord spec.rootBinding is immutable — webhook rejects UPDATE to any rootBinding field", func() { Skip("lab cluster not yet provisioned") }) - It("ILI spec.descendantRegistry grows as RunnerConfig and derived objects are created", func() { + It("LineageRecord spec.descendantRegistry grows as RunnerConfig and derived objects are created", func() { Skip("lab cluster not yet provisioned") }) diff --git a/test/e2e/lineage_root_filter_test.go b/test/e2e/lineage_root_filter_test.go new file mode 100644 index 0000000..18c5002 --- /dev/null +++ b/test/e2e/lineage_root_filter_test.go @@ -0,0 +1,42 @@ +package e2e_test + +// Lineage-root CRD label filter: e2e acceptance stubs. +// +// These stubs cover the LineageController admission filter introduced in MIGRATION-3.8 +// Part 3. The filter reads infrastructure.ontai.dev/lineage-root on the reconciled +// GVK's CRD object to decide whether to create a LineageRecord directly (root path) +// or walk ownerReferences to find the nearest root (derived path). +// +// Promotion condition: requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed. +// +// seam-core-schema.md §7. CLAUDE.md §14 Decisions 1 and 3. + +import ( + . "github.com/onsi/ginkgo/v2" +) + +var _ = Describe("LineageController root-label admission filter", func() { + It("creates LineageRecord for TalosCluster (CRD carries lineage-root label)", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) + + It("creates LineageRecord for PackDelivery (CRD carries lineage-root label)", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) + + It("does not create a LineageRecord for a derived object with no lineage-root CRD label", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) + + It("appends DescendantEntry to root LineageRecord when derived object ownerRef resolves within 1 hop", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) + + It("appends DescendantEntry to root LineageRecord when derived object ownerRef resolves within 3 hops", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) + + It("requeues derived object with 5-minute delay when no root found within 3 ownerRef hops", func() { + Skip("requires live cluster with MGMT_KUBECONFIG and MIGRATION-3.8 closed") + }) +}) diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go index 5215b15..1affbd3 100644 --- a/test/e2e/suite_test.go +++ b/test/e2e/suite_test.go @@ -1,6 +1,6 @@ // Package e2e contains the seam-core end-to-end test suite. // -// These tests verify the InfrastructureLineageIndex lifecycle and the +// These tests verify the LineageRecord lifecycle and the // LineageController index management behaviour on a live cluster. // // Required environment variables: @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - e2ehelpers "github.com/ontai-dev/seam-core/pkg/e2e" + e2ehelpers "github.com/ontai-dev/seam/pkg/e2e" ) // Suite-level cluster clients, initialized in BeforeSuite. diff --git a/test/integration/lineage/all_gvks_test.go b/test/integration/lineage/all_gvks_test.go index 7999bee..32a631e 100644 --- a/test/integration/lineage/all_gvks_test.go +++ b/test/integration/lineage/all_gvks_test.go @@ -1,6 +1,6 @@ // Package lineage_test contains integration tests for the seam-core -// InfrastructureLineageController, verifying that all 9 registered root declaration -// GVKs produce a correctly structured InfrastructureLineageIndex with the right +// LineageController, verifying that all registered root declaration +// GVKs produce a correctly structured LineageRecord with the right // rootBinding, governance annotation, and LineageSynced=True condition. // // Tests use controller-runtime's fake client — no live cluster or envtest required. @@ -8,7 +8,7 @@ // in controller.RootDeclarationGVKs, providing a regression guard against accidental // GVK removal or ILI naming drift. // -// seam-core-schema.md §7. CLAUDE.md Decisions 1-6. Root invariant: 9 GVKs. +// seam-core-schema.md §7. CLAUDE.md Decisions 1-6. package lineage_test import ( @@ -27,8 +27,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" ) // ── helpers ────────────────────────────────────────────────────────────────── @@ -60,7 +60,7 @@ func buildRootDeclaration(gvk schema.GroupVersionKind, name, namespace string) * "type": seamv1alpha1.ConditionTypeLineageSynced, "status": "False", "reason": "LineageControllerAbsent", - "message": "InfrastructureLineageController is not yet deployed.", + "message": "LineageController is not yet deployed.", "lastTransitionTime": metav1.Now().UTC().Format("2006-01-02T15:04:05Z"), }, }, "status", "conditions") @@ -73,6 +73,18 @@ func expectedILIName(kind, name string) string { return strings.ToLower(kind) + "-" + name } +// buildRootLabeledCRD returns an unstructured CRD object for gvk carrying the +// lineage-root label. Added to fake clients so IsRootDeclaration returns true. +func buildRootLabeledCRD(gvk schema.GroupVersionKind) *unstructured.Unstructured { + crd := &unstructured.Unstructured{} + crd.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinition", + }) + crd.SetName(controller.CRDNameForGVK(gvk)) + crd.SetLabels(map[string]string{"infrastructure.ontai.dev/lineage-root": "true"}) + return crd +} + // reconcileGVK runs the LineageReconciler for the given GVK and root object. func reconcileGVK(t *testing.T, r *controller.LineageReconciler, name, namespace string) ctrl.Result { t.Helper() @@ -109,8 +121,8 @@ func TestLineageController_AllGVKs_ProduceILIWithCorrectRootBinding(t *testing.T c := fake.NewClientBuilder(). WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, buildRootLabeledCRD(gvk)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{Client: c, Scheme: s, GVK: gvk} @@ -120,7 +132,7 @@ func TestLineageController_AllGVKs_ProduceILIWithCorrectRootBinding(t *testing.T } iliName := expectedILIName(gvk.Kind, rootName) - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: iliName, Namespace: ns}, ili); err != nil { t.Fatalf("ILI %s not created: %v", iliName, err) } @@ -165,8 +177,8 @@ func TestLineageController_AllGVKs_LineageSyncedTransitionsToTrue(t *testing.T) c := fake.NewClientBuilder(). WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, buildRootLabeledCRD(gvk)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{Client: c, Scheme: s, GVK: gvk} @@ -216,15 +228,15 @@ func TestLineageController_AllGVKs_ILINameFormat(t *testing.T) { c := fake.NewClientBuilder(). WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, buildRootLabeledCRD(gvk)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{Client: c, Scheme: s, GVK: gvk} reconcileGVK(t, r, rootName, ns) wantName := strings.ToLower(gvk.Kind) + "-" + rootName - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: wantName, Namespace: ns}, ili); err != nil { t.Errorf("ILI with expected name %q not found: %v", wantName, err) } @@ -236,7 +248,7 @@ func TestLineageController_AllGVKs_ILINameFormat(t *testing.T) { // Guards against silent additions or removals. seam-core-schema.md §7. func TestLineageController_GVKCount(t *testing.T) { // 1 platform infra + 10 platform operational + 2 platform CAPI + - // 3 wrapper + 5 guardian = 21 + // 3 dispatcher + 5 guardian = 21 const expected = 21 if got := len(controller.RootDeclarationGVKs); got != expected { t.Errorf("RootDeclarationGVKs count = %d, want %d", got, expected) diff --git a/test/unit/ac4_lineage_controller_test.go b/test/unit/ac4_lineage_controller_test.go index 83e5203..de73639 100644 --- a/test/unit/ac4_lineage_controller_test.go +++ b/test/unit/ac4_lineage_controller_test.go @@ -2,14 +2,14 @@ package unit_test // AC-4: LineageController manifest tracking acceptance contract. // -// AC-4: When a root declaration CR is created, the InfrastructureLineageController +// AC-4: When a root declaration CR is created, the LineageController // must: -// - Create exactly one InfrastructureLineageIndex with the deterministic name +// - Create exactly one LineageRecord with the deterministic name // {lowercasekind}-{name} in the same namespace as the root declaration. // - Set governance.infrastructure.ontai.dev/lineage-index-ref annotation on the root. // - Transition LineageSynced from False/LineageControllerAbsent to True/LineageIndexCreated. // - Initialize DescendantRegistry as nil (empty at creation). -// - Be idempotent: a second reconcile must not create a duplicate ILI. +// - Be idempotent: a second reconcile must not create a duplicate LineageRecord. // - Cover all 9 root declaration GVKs registered in RootDeclarationGVKs. // // These tests constitute the acceptance contract gate for AC-4. @@ -24,9 +24,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" - seamconditions "github.com/ontai-dev/seam-core/pkg/conditions" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" + seamconditions "github.com/ontai-dev/seam/pkg/conditions" ) // buildAC4ReconcilerWithClient returns a reconciler and the fake client. @@ -35,8 +35,8 @@ func buildAC4ReconcilerWithClient(t *testing.T, gvk schema.GroupVersionKind, roo s := newTestScheme(t) c := fake.NewClientBuilder(). WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(gvk, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() return &controller.LineageReconciler{ Client: c, @@ -46,24 +46,24 @@ func buildAC4ReconcilerWithClient(t *testing.T, gvk schema.GroupVersionKind, roo } // TestAC4_LineageReconciler_CreatesILIWithDeterministicName verifies that reconciling -// a root declaration creates an InfrastructureLineageIndex named {lowercasekind}-{name} +// a root declaration creates a LineageRecord named {lowercasekind}-{name} // in the same namespace, with rootBinding populated correctly. -// AC-4 gate: ILI creation and naming contract. CLAUDE.md §14 Decision 4. +// AC-4 gate: LineageRecord creation and naming contract. CLAUDE.md §14 Decision 4. func TestAC4_LineageReconciler_CreatesILIWithDeterministicName(t *testing.T) { root := newRootDeclaration(talosClusterGVK, "prod-cluster", "seam-system") r, c := buildAC4ReconcilerWithClient(t, talosClusterGVK, root) reconcileRoot(t, r, "prod-cluster", "seam-system") - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ - Name: "infrastructuretaloscluster-prod-cluster", + Name: "taloscluster-prod-cluster", Namespace: "seam-system", }, ili); err != nil { - t.Fatalf("AC-4: InfrastructureLineageIndex infrastructuretaloscluster-prod-cluster not found: %v", err) + t.Fatalf("AC-4: LineageRecord taloscluster-prod-cluster not found: %v", err) } - if ili.Spec.RootBinding.RootKind != "InfrastructureTalosCluster" { - t.Errorf("AC-4: ILI rootBinding.rootKind = %q, want InfrastructureTalosCluster", ili.Spec.RootBinding.RootKind) + if ili.Spec.RootBinding.RootKind != "TalosCluster" { + t.Errorf("AC-4: ILI rootBinding.rootKind = %q, want TalosCluster", ili.Spec.RootBinding.RootKind) } if ili.Spec.RootBinding.RootName != "prod-cluster" { t.Errorf("AC-4: ILI rootBinding.rootName = %q, want prod-cluster", ili.Spec.RootBinding.RootName) @@ -123,7 +123,7 @@ func TestAC4_LineageReconciler_TransitionsLineageSyncedToTrue(t *testing.T) { // TestAC4_LineageReconciler_GovernanceAnnotationOnRoot verifies that the // governance.infrastructure.ontai.dev/lineage-index-ref annotation is written // onto the root declaration after reconcile. This annotation is the controller's -// idempotency guard and the cross-object reference to the ILI. +// idempotency guard and the cross-object reference to the LineageRecord. // AC-4 gate: governance annotation contract. CLAUDE.md §14 Decision 3. func TestAC4_LineageReconciler_GovernanceAnnotationOnRoot(t *testing.T) { root := newRootDeclaration(rbacPolicyGVK, "platform-policy", "seam-system") @@ -143,7 +143,7 @@ func TestAC4_LineageReconciler_GovernanceAnnotationOnRoot(t *testing.T) { } // TestAC4_LineageReconciler_Idempotent verifies that a second reconcile does not -// create a duplicate ILI. The total ILI count in the namespace must be exactly 1 +// create a duplicate LineageRecord. The total LineageRecord count in the namespace must be exactly 1 // after two reconcile calls. CLAUDE.md §14 Decision 4. // AC-4 gate: idempotency contract. func TestAC4_LineageReconciler_Idempotent(t *testing.T) { @@ -153,7 +153,7 @@ func TestAC4_LineageReconciler_Idempotent(t *testing.T) { reconcileRoot(t, r, "exec-001", "infra-system") reconcileRoot(t, r, "exec-001", "infra-system") - iliList := &seamv1alpha1.InfrastructureLineageIndexList{} + iliList := &seamv1alpha1.LineageRecordList{} if err := c.List(context.Background(), iliList, client.InNamespace("infra-system")); err != nil { t.Fatalf("AC-4: list ILIs: %v", err) } @@ -168,9 +168,9 @@ func TestAC4_LineageReconciler_Idempotent(t *testing.T) { // AC-4 gate: GVK coverage contract. seam-core-schema.md §3. func TestAC4_AllNineRootDeclarationGVKsAreRegistered(t *testing.T) { required := []schema.GroupVersionKind{ - // Platform — infrastructure.ontai.dev (Decision G) - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"}, - // Platform operational — platform.ontai.dev + // Platform -- seam.ontai.dev (MIGRATION-3.1) + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"}, + // Platform operational -- platform.ontai.dev {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "UpgradePolicy"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "NodeMaintenance"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "ClusterMaintenance"}, @@ -181,19 +181,19 @@ func TestAC4_AllNineRootDeclarationGVKsAreRegistered(t *testing.T) { {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "TalosMachineConfigBackup"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "TalosMachineConfigRestore"}, {Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "HardeningProfile"}, - // Platform CAPI provider — infrastructure.ontai.dev + // Platform CAPI provider -- infrastructure.ontai.dev {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "SeamInfrastructureCluster"}, {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "SeamInfrastructureMachine"}, - // Wrapper — infrastructure.ontai.dev (Decision G) - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureClusterPack"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackExecution"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, - // Guardian - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "RBACProfile"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "PermissionSet"}, + // Dispatcher -- seam.ontai.dev (MIGRATION-3.3-3.7) + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackExecution"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, + // Guardian -- guardian.ontai.dev (constitutional refactor 2026-05-12) + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACProfile"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "PermissionSet"}, } if len(controller.RootDeclarationGVKs) != len(required) { diff --git a/test/unit/conditions/conditions_test.go b/test/unit/conditions/conditions_test.go index 26f3ee1..2cc344c 100644 --- a/test/unit/conditions/conditions_test.go +++ b/test/unit/conditions/conditions_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/ontai-dev/seam-core/pkg/conditions" + "github.com/ontai-dev/seam/pkg/conditions" ) // TestValidateCondition_AcceptsKnownPairs verifies that every declared constant diff --git a/test/unit/descendant_reconciler_test.go b/test/unit/descendant_reconciler_test.go index bc78c9c..24d3797 100644 --- a/test/unit/descendant_reconciler_test.go +++ b/test/unit/descendant_reconciler_test.go @@ -12,15 +12,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ctrl "sigs.k8s.io/controller-runtime" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" - "github.com/ontai-dev/seam-core/pkg/lineage" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" + "github.com/ontai-dev/seam/pkg/lineage" ) var runnerConfigGVK = schema.GroupVersionKind{ - Group: "infrastructure.ontai.dev", + Group: "seam.ontai.dev", Version: "v1alpha1", - Kind: "InfrastructureRunnerConfig", + Kind: "RunnerConfig", } // newRunnerConfig builds a minimal unstructured RunnerConfig with descendant labels. @@ -60,15 +60,15 @@ func newRunnerConfigCrossNS(name, rcNamespace, iliName, iliNamespace string) *un } // newILIForDescendant builds a pre-existing ILI with nil DescendantRegistry. -func newILIForDescendant(t *testing.T, name, namespace string) *seamv1alpha1.InfrastructureLineageIndex { +func newILIForDescendant(t *testing.T, name, namespace string) *seamv1alpha1.LineageRecord { t.Helper() - return &seamv1alpha1.InfrastructureLineageIndex{ + return &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ RootKind: "TalosCluster", RootName: "prod-cluster", RootNamespace: namespace, @@ -113,7 +113,7 @@ func TestDescendantReconciler_AppendsEntryToILI(t *testing.T) { t.Errorf("expected no requeue") } - got := &seamv1alpha1.InfrastructureLineageIndex{} + got := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: iliName, Namespace: ns}, got); err != nil { t.Fatalf("get ILI: %v", err) } @@ -122,8 +122,8 @@ func TestDescendantReconciler_AppendsEntryToILI(t *testing.T) { } entry := got.Spec.DescendantRegistry[0] - if entry.Kind != "InfrastructureRunnerConfig" { - t.Errorf("entry.Kind = %q, want InfrastructureRunnerConfig", entry.Kind) + if entry.Kind != "RunnerConfig" { + t.Errorf("entry.Kind = %q, want RunnerConfig", entry.Kind) } if entry.Name != "rc-etcd-001" { t.Errorf("entry.Name = %q, want rc-etcd-001", entry.Name) @@ -162,7 +162,7 @@ func TestDescendantReconciler_Idempotent(t *testing.T) { t.Fatalf("second Reconcile error: %v", err) } - got := &seamv1alpha1.InfrastructureLineageIndex{} + got := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: iliName, Namespace: ns}, got); err != nil { t.Fatalf("get ILI: %v", err) } @@ -196,7 +196,7 @@ func TestDescendantReconciler_CrossNamespaceILI(t *testing.T) { t.Errorf("expected no requeue: ILI should be found via cross-namespace label, RequeueAfter=%s", result.RequeueAfter) } - got := &seamv1alpha1.InfrastructureLineageIndex{} + got := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: iliName, Namespace: iliNamespace}, got); err != nil { t.Fatalf("get ILI in seam-system: %v", err) @@ -239,7 +239,7 @@ func TestDescendantReconciler_NoOpWhenLabelAbsent(t *testing.T) { t.Fatalf("Reconcile error: %v", err) } - got := &seamv1alpha1.InfrastructureLineageIndex{} + got := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{Name: iliName, Namespace: ns}, got); err != nil { t.Fatalf("get ILI: %v", err) } diff --git a/test/unit/dns/ac5_dsns_test.go b/test/unit/dns/ac5_dsns_test.go index 6828c3d..97c6ff2 100644 --- a/test/unit/dns/ac5_dsns_test.go +++ b/test/unit/dns/ac5_dsns_test.go @@ -29,8 +29,8 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/ontai-dev/seam-core/internal/controller" - idns "github.com/ontai-dev/seam-core/internal/dns" + "github.com/ontai-dev/seam/internal/controller" + idns "github.com/ontai-dev/seam/internal/dns" ) // reconcileAC5 reconciles obj and fails the test on error. @@ -58,7 +58,7 @@ func zoneAC5(t *testing.T, fc client.Client) string { // AC-5 gate: cluster-topology projection contract. seam-core-schema.md §8. func TestAC5_DSNS_TalosCluster_Ready_ProducesClusterTopologyRecord(t *testing.T) { t.Parallel() - tc := newUnstructured(schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"}, + tc := newUnstructured(schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"}, "ccs-mgmt", "ont-system") setField(tc, "10.10.0.1", "spec", "clusterEndpoint") setField(tc, "bootstrapped", "status", "origin") @@ -88,7 +88,7 @@ func TestAC5_DSNS_TalosCluster_Ready_ProducesClusterTopologyRecord(t *testing.T) // AC-5 gate: pack-lineage projection contract. seam-core-schema.md §8. func TestAC5_DSNS_PackInstance_Succeeded_ProducesPackLineageRecord(t *testing.T) { t.Parallel() - pi := newUnstructured(schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, + pi := newUnstructured(schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, "cilium-v1.0.0", "seam-tenant-ccs-dev") setField(pi, "cilium", "spec", "clusterPackRef") setField(pi, "ccs-dev", "spec", "targetClusterRef") @@ -116,7 +116,7 @@ func TestAC5_DSNS_PackInstance_Succeeded_ProducesPackLineageRecord(t *testing.T) // AC-5 gate: identity-plane projection contract. seam-core-schema.md §8. func TestAC5_DSNS_IdentityBinding_Resolved_ProducesIdentityPlaneRecord(t *testing.T) { t.Parallel() - ib := newUnstructured(schema.GroupVersionKind{Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, + ib := newUnstructured(schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, "alice-binding", "seam-tenant-ccs-dev") setField(ib, "alice@example.com", "spec", "subject") setField(ib, "admin-profile", "spec", "rbacProfileRef", "name") @@ -144,7 +144,7 @@ func TestAC5_DSNS_IdentityBinding_Resolved_ProducesIdentityPlaneRecord(t *testin // AC-5 gate: execution-authority projection contract. seam-core-schema.md §8. func TestAC5_DSNS_RunnerConfig_Completed_ProducesExecutionAuthorityRecord(t *testing.T) { t.Parallel() - rc := newUnstructured(schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureRunnerConfig"}, + rc := newUnstructured(schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "RunnerConfig"}, "ccs-dev", "ont-system") setField(rc, []interface{}{"talos-apply", "helm-install"}, "spec", "capabilities") setCondition(rc, "Ready", "True", "CapabilitiesPublished", "2026-04-20T00:00:00Z") @@ -197,11 +197,11 @@ func TestAC5_DSNS_Zone_AlwaysContainsSOAandNS(t *testing.T) { // AC-5 gate: GVK coverage contract. seam-core-schema.md §8 Decision 4. func TestAC5_DSNSGVKs_ContainsAllRequiredGVKs(t *testing.T) { required := []schema.GroupVersionKind{ - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, - {Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, - {Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureRunnerConfig"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"}, + {Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"}, + {Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "RunnerConfig"}, } registered := make(map[schema.GroupVersionKind]bool, len(controller.DSNSGVKs)) diff --git a/test/unit/dns/dsns_reconciler_test.go b/test/unit/dns/dsns_reconciler_test.go index 19dd5a1..214541f 100644 --- a/test/unit/dns/dsns_reconciler_test.go +++ b/test/unit/dns/dsns_reconciler_test.go @@ -11,18 +11,18 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/ontai-dev/seam-core/internal/controller" - idns "github.com/ontai-dev/seam-core/internal/dns" + "github.com/ontai-dev/seam/internal/controller" + idns "github.com/ontai-dev/seam/internal/dns" ) // ── test helpers ────────────────────────────────────────────────────────────── var ( - talosClusterGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"} - identityBindGVK = schema.GroupVersionKind{Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"} - identityProvGVK = schema.GroupVersionKind{Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"} - packInstanceGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"} - runnerConfigGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureRunnerConfig"} + talosClusterGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + identityBindGVK = schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"} + identityProvGVK = schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityProvider"} + packInstanceGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} + runnerConfigGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "RunnerConfig"} ) func newUnstructured(gvk schema.GroupVersionKind, name, ns string) *unstructured.Unstructured { diff --git a/test/unit/dns/sink_registry_test.go b/test/unit/dns/sink_registry_test.go index 28c8b04..ecfd45e 100644 --- a/test/unit/dns/sink_registry_test.go +++ b/test/unit/dns/sink_registry_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - idns "github.com/ontai-dev/seam-core/internal/dns" + idns "github.com/ontai-dev/seam/internal/dns" ) // ── DSNSEvent construction tests ───────────────────────────────────────────── diff --git a/test/unit/dns/zone_test.go b/test/unit/dns/zone_test.go index a5e6791..d0b1c37 100644 --- a/test/unit/dns/zone_test.go +++ b/test/unit/dns/zone_test.go @@ -15,7 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - idns "github.com/ontai-dev/seam-core/internal/dns" + idns "github.com/ontai-dev/seam/internal/dns" ) // ── helpers ─────────────────────────────────────────────────────────────────── diff --git a/test/unit/lineage_controller_test.go b/test/unit/lineage_controller_test.go index 7cc2042..af43331 100644 --- a/test/unit/lineage_controller_test.go +++ b/test/unit/lineage_controller_test.go @@ -15,18 +15,18 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" ) -// rootGVKs used in tests — covers one from each operator family. +// rootGVKs used in tests -- covers one from each operator family. var ( - talosClusterGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureTalosCluster"} - clusterPackGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructureClusterPack"} - rbacPolicyGVK = schema.GroupVersionKind{Group: "security.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"} - packExecutionGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackExecution"} - identityBindGVK = schema.GroupVersionKind{Group: "security.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"} - packInstanceGVK = schema.GroupVersionKind{Group: "infrastructure.ontai.dev", Version: "v1alpha1", Kind: "InfrastructurePackInstance"} + talosClusterGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + clusterPackGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"} + rbacPolicyGVK = schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"} + packExecutionGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackExecution"} + identityBindGVK = schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "IdentityBinding"} + packInstanceGVK = schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} ) func newTestScheme(t *testing.T) *runtime.Scheme { @@ -54,7 +54,7 @@ func newRootDeclaration(gvk schema.GroupVersionKind, name, namespace string) *un "type": "LineageSynced", "status": "False", "reason": "LineageControllerAbsent", - "message": "InfrastructureLineageController is not yet deployed.", + "message": "LineageController is not yet deployed.", "lastTransitionTime": metav1.Now().UTC().Format("2006-01-02T15:04:05Z"), }, }, "status", "conditions") @@ -73,15 +73,15 @@ func reconcileRoot(t *testing.T, r *controller.LineageReconciler, name, namespac } // TestLineageReconciler_CreatesILIForTalosCluster verifies that reconciling a -// TalosCluster root declaration creates an InfrastructureLineageIndex with +// TalosCluster root declaration creates a LineageRecord with // the correct rootBinding. func TestLineageReconciler_CreatesILIForTalosCluster(t *testing.T) { s := newTestScheme(t) root := newRootDeclaration(talosClusterGVK, "prod-cluster", "ont-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(talosClusterGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -95,17 +95,17 @@ func TestLineageReconciler_CreatesILIForTalosCluster(t *testing.T) { t.Errorf("expected no requeue, got %+v", result) } - // Verify ILI was created. - ili := &seamv1alpha1.InfrastructureLineageIndex{} - iliKey := client.ObjectKey{Name: "infrastructuretaloscluster-prod-cluster", Namespace: "ont-system"} + // Verify LineageRecord was created. + ili := &seamv1alpha1.LineageRecord{} + iliKey := client.ObjectKey{Name: "taloscluster-prod-cluster", Namespace: "ont-system"} if err := fakeClient.Get(context.Background(), iliKey, ili); err != nil { - t.Fatalf("expected InfrastructureLineageIndex to exist: %v", err) + t.Fatalf("expected LineageRecord to exist: %v", err) } // Verify rootBinding. rb := ili.Spec.RootBinding - if rb.RootKind != "InfrastructureTalosCluster" { - t.Errorf("expected RootKind=InfrastructureTalosCluster, got %q", rb.RootKind) + if rb.RootKind != "TalosCluster" { + t.Errorf("expected RootKind=TalosCluster, got %q", rb.RootKind) } if rb.RootName != "prod-cluster" { t.Errorf("expected RootName=prod-cluster, got %q", rb.RootName) @@ -128,8 +128,8 @@ func TestLineageReconciler_GovernanceAnnotationSet(t *testing.T) { root := newRootDeclaration(clusterPackGVK, "my-pack", "infra-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(clusterPackGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -153,7 +153,7 @@ func TestLineageReconciler_GovernanceAnnotationSet(t *testing.T) { if !ok { t.Fatalf("expected governance annotation %q to be set", controller.GovernanceAnnotationLineageIndexRef) } - expectedILIName := "infrastructureclusterpack-my-pack" + expectedILIName := "packdelivery-my-pack" if iliRef != expectedILIName { t.Errorf("expected annotation value %q, got %q", expectedILIName, iliRef) } @@ -166,8 +166,8 @@ func TestLineageReconciler_LineageSyncedTransitionedToTrue(t *testing.T) { root := newRootDeclaration(rbacPolicyGVK, "platform-policy", "security-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(rbacPolicyGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -230,7 +230,7 @@ func TestLineageReconciler_NotFound_NoError(t *testing.T) { t.Errorf("expected no requeue for not-found, got %+v", result) } // No ILI should be created. - iliList := &seamv1alpha1.InfrastructureLineageIndexList{} + iliList := &seamv1alpha1.LineageRecordList{} if err := fakeClient.List(context.Background(), iliList); err != nil { t.Fatalf("list ILIs: %v", err) } @@ -247,8 +247,8 @@ func TestLineageReconciler_Idempotent(t *testing.T) { root := newRootDeclaration(identityBindGVK, "admin-binding", "security-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(identityBindGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -264,7 +264,7 @@ func TestLineageReconciler_Idempotent(t *testing.T) { reconcileRoot(t, r, "admin-binding", "security-system") // Only one ILI should exist. - iliList := &seamv1alpha1.InfrastructureLineageIndexList{} + iliList := &seamv1alpha1.LineageRecordList{} if err := fakeClient.List(context.Background(), iliList, client.InNamespace("security-system")); err != nil { t.Fatalf("list ILIs: %v", err) @@ -283,18 +283,18 @@ func TestLineageReconciler_ILIRootBindingImmutable(t *testing.T) { root := newRootDeclaration(clusterPackGVK, "pack-v2", "infra-system") // Pre-populate governance annotation to simulate prior reconcile. root.SetAnnotations(map[string]string{ - controller.GovernanceAnnotationLineageIndexRef: "infrastructureclusterpack-pack-v2", + controller.GovernanceAnnotationLineageIndexRef: "packdelivery-pack-v2", }) // Create an existing ILI with matching rootBinding. - existingILI := &seamv1alpha1.InfrastructureLineageIndex{ + existingILI := &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ - Name: "infrastructureclusterpack-pack-v2", + Name: "packdelivery-pack-v2", Namespace: "infra-system", }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ - RootKind: "InfrastructureClusterPack", + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ + RootKind: "PackDelivery", RootName: "pack-v2", RootNamespace: "infra-system", RootUID: types.UID("uid-pack-v2"), @@ -304,8 +304,8 @@ func TestLineageReconciler_ILIRootBindingImmutable(t *testing.T) { } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, existingILI). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, existingILI, newCRDObject(clusterPackGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -321,9 +321,9 @@ func TestLineageReconciler_ILIRootBindingImmutable(t *testing.T) { } // ILI rootBinding must be unchanged. - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := fakeClient.Get(context.Background(), - client.ObjectKey{Name: "infrastructureclusterpack-pack-v2", Namespace: "infra-system"}, ili); err != nil { + client.ObjectKey{Name: "packdelivery-pack-v2", Namespace: "infra-system"}, ili); err != nil { t.Fatalf("get ILI: %v", err) } if ili.Spec.RootBinding.RootUID != types.UID("uid-pack-v2") { @@ -332,15 +332,15 @@ func TestLineageReconciler_ILIRootBindingImmutable(t *testing.T) { } // TestLineageReconciler_ControllerAuthoredAnnotation verifies that newly created -// InfrastructureLineageIndex instances carry the controller-authored governance +// LineageRecord instances carry the controller-authored governance // annotation per CLAUDE.md §14 Decision 3. func TestLineageReconciler_ControllerAuthoredAnnotation(t *testing.T) { s := newTestScheme(t) root := newRootDeclaration(rbacPolicyGVK, "tenant-policy", "security-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(rbacPolicyGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -351,7 +351,7 @@ func TestLineageReconciler_ControllerAuthoredAnnotation(t *testing.T) { reconcileRoot(t, r, "tenant-policy", "security-system") - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "rbacpolicy-tenant-policy", Namespace: "security-system"}, ili); err != nil { t.Fatalf("get ILI: %v", err) @@ -369,31 +369,31 @@ func TestLineageReconciler_ControllerAuthoredAnnotation(t *testing.T) { func TestLineageReconciler_AllRootDeclarationGVKsRegistered(t *testing.T) { expected := map[string]bool{ // Platform infra - "infrastructure.ontai.dev/v1alpha1/InfrastructureTalosCluster": false, + "seam.ontai.dev/v1alpha1/TalosCluster": false, // Platform operational - "platform.ontai.dev/v1alpha1/UpgradePolicy": false, - "platform.ontai.dev/v1alpha1/NodeMaintenance": false, - "platform.ontai.dev/v1alpha1/ClusterMaintenance": false, - "platform.ontai.dev/v1alpha1/PKIRotation": false, - "platform.ontai.dev/v1alpha1/ClusterReset": false, - "platform.ontai.dev/v1alpha1/NodeOperation": false, - "platform.ontai.dev/v1alpha1/EtcdMaintenance": false, - "platform.ontai.dev/v1alpha1/TalosMachineConfigBackup": false, - "platform.ontai.dev/v1alpha1/TalosMachineConfigRestore": false, - "platform.ontai.dev/v1alpha1/HardeningProfile": false, + "platform.ontai.dev/v1alpha1/UpgradePolicy": false, + "platform.ontai.dev/v1alpha1/NodeMaintenance": false, + "platform.ontai.dev/v1alpha1/ClusterMaintenance": false, + "platform.ontai.dev/v1alpha1/PKIRotation": false, + "platform.ontai.dev/v1alpha1/ClusterReset": false, + "platform.ontai.dev/v1alpha1/NodeOperation": false, + "platform.ontai.dev/v1alpha1/EtcdMaintenance": false, + "platform.ontai.dev/v1alpha1/TalosMachineConfigBackup": false, + "platform.ontai.dev/v1alpha1/TalosMachineConfigRestore": false, + "platform.ontai.dev/v1alpha1/HardeningProfile": false, // Platform CAPI provider - "infrastructure.ontai.dev/v1alpha1/SeamInfrastructureCluster": false, - "infrastructure.ontai.dev/v1alpha1/SeamInfrastructureMachine": false, - // Wrapper - "infrastructure.ontai.dev/v1alpha1/InfrastructureClusterPack": false, - "infrastructure.ontai.dev/v1alpha1/InfrastructurePackExecution": false, - "infrastructure.ontai.dev/v1alpha1/InfrastructurePackInstance": false, - // Guardian - "security.ontai.dev/v1alpha1/RBACPolicy": false, - "security.ontai.dev/v1alpha1/RBACProfile": false, - "security.ontai.dev/v1alpha1/IdentityBinding": false, - "security.ontai.dev/v1alpha1/IdentityProvider": false, - "security.ontai.dev/v1alpha1/PermissionSet": false, + "infrastructure.ontai.dev/v1alpha1/SeamInfrastructureCluster": false, + "infrastructure.ontai.dev/v1alpha1/SeamInfrastructureMachine": false, + // Dispatcher (MIGRATION-3.3-3.7) + "seam.ontai.dev/v1alpha1/PackDelivery": false, + "seam.ontai.dev/v1alpha1/PackExecution": false, + "seam.ontai.dev/v1alpha1/PackInstalled": false, + // Guardian (guardian.ontai.dev -- constitutional refactor 2026-05-12) + "guardian.ontai.dev/v1alpha1/RBACPolicy": false, + "guardian.ontai.dev/v1alpha1/RBACProfile": false, + "guardian.ontai.dev/v1alpha1/IdentityBinding": false, + "guardian.ontai.dev/v1alpha1/IdentityProvider": false, + "guardian.ontai.dev/v1alpha1/PermissionSet": false, } for _, gvk := range controller.RootDeclarationGVKs { @@ -418,12 +418,12 @@ func TestLineageReconciler_AllRootDeclarationGVKsRegistered(t *testing.T) { // --- Retention policy tests --- -// newILIWithDescendants builds an InfrastructureLineageIndex with a pre-populated +// newILIWithDescendants builds a LineageRecord with a pre-populated // DescendantRegistry for retention tests. Each entry's CreatedAt is set to the // provided age ago. -func newILIWithDescendants(t *testing.T, name, namespace string, entries []seamv1alpha1.DescendantEntry) *seamv1alpha1.InfrastructureLineageIndex { +func newILIWithDescendants(t *testing.T, name, namespace string, entries []seamv1alpha1.DescendantEntry) *seamv1alpha1.LineageRecord { t.Helper() - return &seamv1alpha1.InfrastructureLineageIndex{ + return &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, @@ -431,9 +431,9 @@ func newILIWithDescendants(t *testing.T, name, namespace string, entries []seamv controller.GovernanceAnnotationControllerAuthored: "true", }, }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ - RootKind: "InfrastructureTalosCluster", + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ + RootKind: "TalosCluster", RootName: name, RootNamespace: namespace, }, @@ -453,11 +453,11 @@ func TestLineageReconciler_RetentionPrunesStaleEntry(t *testing.T) { // Build an ILI with one stale entry: CreatedAt 31 days ago, retention=30 days. // The referenced object (some-runnerconfig) does not exist in the fake client. staleTime := metav1.NewTime(time.Now().Add(-31 * 24 * time.Hour)) - ili := newILIWithDescendants(t, "infrastructuretaloscluster-cluster-a", ns, []seamv1alpha1.DescendantEntry{ + ili := newILIWithDescendants(t, "taloscluster-cluster-a", ns, []seamv1alpha1.DescendantEntry{ { - Group: "infrastructure.ontai.dev", + Group: "seam.ontai.dev", Version: "v1alpha1", - Kind: "InfrastructureRunnerConfig", + Kind: "RunnerConfig", Name: "some-runnerconfig", Namespace: ns, UID: "uid-rc-1", @@ -471,7 +471,7 @@ func TestLineageReconciler_RetentionPrunesStaleEntry(t *testing.T) { } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, ili). + WithObjects(root, ili, newCRDObject(talosClusterGVK, true)). WithStatusSubresource(root, ili). Build() @@ -484,8 +484,8 @@ func TestLineageReconciler_RetentionPrunesStaleEntry(t *testing.T) { reconcileRoot(t, r, "cluster-a", ns) // After reconcile the stale entry must have been pruned. - updatedILI := &seamv1alpha1.InfrastructureLineageIndex{} - if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "infrastructuretaloscluster-cluster-a", Namespace: ns}, updatedILI); err != nil { + updatedILI := &seamv1alpha1.LineageRecord{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "taloscluster-cluster-a", Namespace: ns}, updatedILI); err != nil { t.Fatalf("get ILI: %v", err) } if len(updatedILI.Spec.DescendantRegistry) != 0 { @@ -503,11 +503,11 @@ func TestLineageReconciler_RetentionKeepsEntryWithinWindow(t *testing.T) { // CreatedAt 5 days ago, retention=30 days — entry is within window. recentTime := metav1.NewTime(time.Now().Add(-5 * 24 * time.Hour)) - ili := newILIWithDescendants(t, "infrastructuretaloscluster-cluster-b", ns, []seamv1alpha1.DescendantEntry{ + ili := newILIWithDescendants(t, "taloscluster-cluster-b", ns, []seamv1alpha1.DescendantEntry{ { - Group: "infrastructure.ontai.dev", + Group: "seam.ontai.dev", Version: "v1alpha1", - Kind: "InfrastructureRunnerConfig", + Kind: "RunnerConfig", Name: "rc-recent", Namespace: ns, UID: "uid-rc-2", @@ -521,7 +521,7 @@ func TestLineageReconciler_RetentionKeepsEntryWithinWindow(t *testing.T) { } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, ili). + WithObjects(root, ili, newCRDObject(talosClusterGVK, true)). WithStatusSubresource(root, ili). Build() @@ -534,8 +534,8 @@ func TestLineageReconciler_RetentionKeepsEntryWithinWindow(t *testing.T) { reconcileRoot(t, r, "cluster-b", ns) // Entry must still be present. - updatedILI := &seamv1alpha1.InfrastructureLineageIndex{} - if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "infrastructuretaloscluster-cluster-b", Namespace: ns}, updatedILI); err != nil { + updatedILI := &seamv1alpha1.LineageRecord{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "taloscluster-cluster-b", Namespace: ns}, updatedILI); err != nil { t.Fatalf("get ILI: %v", err) } if len(updatedILI.Spec.DescendantRegistry) != 1 { @@ -551,11 +551,11 @@ func TestLineageReconciler_RetentionKeepsEntryWithNilCreatedAt(t *testing.T) { root := newRootDeclaration(talosClusterGVK, "cluster-c", ns) // CreatedAt is nil — entry predates retention tracking. - ili := newILIWithDescendants(t, "infrastructuretaloscluster-cluster-c", ns, []seamv1alpha1.DescendantEntry{ + ili := newILIWithDescendants(t, "taloscluster-cluster-c", ns, []seamv1alpha1.DescendantEntry{ { - Group: "infrastructure.ontai.dev", + Group: "seam.ontai.dev", Version: "v1alpha1", - Kind: "InfrastructureRunnerConfig", + Kind: "RunnerConfig", Name: "rc-old", Namespace: ns, UID: "uid-rc-3", @@ -569,7 +569,7 @@ func TestLineageReconciler_RetentionKeepsEntryWithNilCreatedAt(t *testing.T) { } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, ili). + WithObjects(root, ili, newCRDObject(talosClusterGVK, true)). WithStatusSubresource(root, ili). Build() @@ -581,8 +581,8 @@ func TestLineageReconciler_RetentionKeepsEntryWithNilCreatedAt(t *testing.T) { reconcileRoot(t, r, "cluster-c", ns) - updatedILI := &seamv1alpha1.InfrastructureLineageIndex{} - if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "infrastructuretaloscluster-cluster-c", Namespace: ns}, updatedILI); err != nil { + updatedILI := &seamv1alpha1.LineageRecord{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "taloscluster-cluster-c", Namespace: ns}, updatedILI); err != nil { t.Fatalf("get ILI: %v", err) } // Entry without CreatedAt must never be pruned. @@ -600,14 +600,14 @@ func TestLineageReconciler_DeleteWithRoot_AddsOwnerReference(t *testing.T) { root := newRootDeclaration(talosClusterGVK, "cluster-d", ns) root.SetUID("uid-cluster-d") - ili := newILIWithDescendants(t, "infrastructuretaloscluster-cluster-d", ns, nil) + ili := newILIWithDescendants(t, "taloscluster-cluster-d", ns, nil) ili.Spec.RetentionPolicy = &seamv1alpha1.LineageRetentionPolicy{ DescendantRetentionDays: 30, DeleteWithRoot: true, } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, ili). + WithObjects(root, ili, newCRDObject(talosClusterGVK, true)). WithStatusSubresource(root, ili). Build() @@ -619,8 +619,8 @@ func TestLineageReconciler_DeleteWithRoot_AddsOwnerReference(t *testing.T) { reconcileRoot(t, r, "cluster-d", ns) - updatedILI := &seamv1alpha1.InfrastructureLineageIndex{} - if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "infrastructuretaloscluster-cluster-d", Namespace: ns}, updatedILI); err != nil { + updatedILI := &seamv1alpha1.LineageRecord{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "taloscluster-cluster-d", Namespace: ns}, updatedILI); err != nil { t.Fatalf("get ILI: %v", err) } refs := updatedILI.GetOwnerReferences() @@ -629,7 +629,7 @@ func TestLineageReconciler_DeleteWithRoot_AddsOwnerReference(t *testing.T) { } found := false for _, ref := range refs { - if ref.UID == "uid-cluster-d" && ref.Kind == "InfrastructureTalosCluster" { + if ref.UID == "uid-cluster-d" && ref.Kind == "TalosCluster" { found = true if ref.BlockOwnerDeletion == nil || !*ref.BlockOwnerDeletion { t.Error("expected BlockOwnerDeletion=true on ownerReference") @@ -649,14 +649,14 @@ func TestLineageReconciler_DeleteWithRoot_False_NoOwnerReference(t *testing.T) { root := newRootDeclaration(talosClusterGVK, "cluster-e", ns) root.SetUID("uid-cluster-e") - ili := newILIWithDescendants(t, "infrastructuretaloscluster-cluster-e", ns, nil) + ili := newILIWithDescendants(t, "taloscluster-cluster-e", ns, nil) ili.Spec.RetentionPolicy = &seamv1alpha1.LineageRetentionPolicy{ DescendantRetentionDays: 30, DeleteWithRoot: false, } fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root, ili). + WithObjects(root, ili, newCRDObject(talosClusterGVK, true)). WithStatusSubresource(root, ili). Build() @@ -668,8 +668,8 @@ func TestLineageReconciler_DeleteWithRoot_False_NoOwnerReference(t *testing.T) { reconcileRoot(t, r, "cluster-e", ns) - updatedILI := &seamv1alpha1.InfrastructureLineageIndex{} - if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "infrastructuretaloscluster-cluster-e", Namespace: ns}, updatedILI); err != nil { + updatedILI := &seamv1alpha1.LineageRecord{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "taloscluster-cluster-e", Namespace: ns}, updatedILI); err != nil { t.Fatalf("get ILI: %v", err) } // No ownerReference should be set. @@ -682,15 +682,15 @@ func TestLineageReconciler_DeleteWithRoot_False_NoOwnerReference(t *testing.T) { } // TestLineageReconciler_ILIHasDomainRef verifies that a newly created -// InfrastructureLineageIndex carries spec.domainRef set to the canonical +// LineageRecord carries spec.domainRef set to the canonical // infrastructure domain reference. CLAUDE.md §14 Decision 2. func TestLineageReconciler_ILIHasDomainRef(t *testing.T) { s := newTestScheme(t) root := newRootDeclaration(talosClusterGVK, "dc-cluster", "ont-system") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(talosClusterGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -701,9 +701,9 @@ func TestLineageReconciler_ILIHasDomainRef(t *testing.T) { reconcileRoot(t, r, "dc-cluster", "ont-system") - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := fakeClient.Get(context.Background(), - client.ObjectKey{Name: "infrastructuretaloscluster-dc-cluster", Namespace: "ont-system"}, ili); err != nil { + client.ObjectKey{Name: "taloscluster-dc-cluster", Namespace: "ont-system"}, ili); err != nil { t.Fatalf("get ILI: %v", err) } @@ -721,10 +721,10 @@ func TestLineageReconciler_ILINameDerivation(t *testing.T) { rootName string wantName string }{ - {talosClusterGVK, "prod", "infrastructuretaloscluster-prod"}, - {clusterPackGVK, "cilium-v1", "infrastructureclusterpack-cilium-v1"}, + {talosClusterGVK, "prod", "taloscluster-prod"}, + {clusterPackGVK, "cilium-v1", "packdelivery-cilium-v1"}, {rbacPolicyGVK, "platform", "rbacpolicy-platform"}, - {packExecutionGVK, "deploy-123", "infrastructurepackexecution-deploy-123"}, + {packExecutionGVK, "deploy-123", "packexecution-deploy-123"}, } for _, tc := range cases { @@ -732,8 +732,8 @@ func TestLineageReconciler_ILINameDerivation(t *testing.T) { root := newRootDeclaration(tc.gvk, tc.rootName, "test-ns") fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(tc.gvk, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -743,7 +743,7 @@ func TestLineageReconciler_ILINameDerivation(t *testing.T) { } reconcileRoot(t, r, tc.rootName, "test-ns") - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: tc.wantName, Namespace: "test-ns"}, ili); err != nil { t.Errorf("GVK %s name %q: expected ILI %q, not found: %v", @@ -753,7 +753,7 @@ func TestLineageReconciler_ILINameDerivation(t *testing.T) { } // TestLineageReconciler_PackInstanceCreatesILIAndSetsLineageSynced verifies the -// full reconcile path for infrastructure.ontai.dev/v1alpha1/InfrastructurePackInstance: an ILI is created +// full reconcile path for seam.ontai.dev/v1alpha1/PackInstalled: a LineageRecord is created // and LineageSynced is transitioned to True. // // PackInstance was identified in SEAM-CORE-BL-LINEAGE as having LineageSynced=False @@ -768,8 +768,8 @@ func TestLineageReconciler_PackInstanceCreatesILIAndSetsLineageSynced(t *testing // the Status().Patch() call in ensureLineageSyncedTrue is a no-op and // LineageSynced remains False. seam-core session 22 investigation. fakeClient := fake.NewClientBuilder().WithScheme(s). - WithObjects(root). - WithStatusSubresource(root, &seamv1alpha1.InfrastructureLineageIndex{}). + WithObjects(root, newCRDObject(packInstanceGVK, true)). + WithStatusSubresource(root, &seamv1alpha1.LineageRecord{}). Build() r := &controller.LineageReconciler{ @@ -783,14 +783,14 @@ func TestLineageReconciler_PackInstanceCreatesILIAndSetsLineageSynced(t *testing t.Errorf("expected no requeue, got %+v", result) } - // Verify ILI was created with correct rootBinding. - ili := &seamv1alpha1.InfrastructureLineageIndex{} - iliKey := client.ObjectKey{Name: "infrastructurepackinstance-cilium-v1-ccs-mgmt", Namespace: "ont-system"} + // Verify LineageRecord was created with correct rootBinding. + ili := &seamv1alpha1.LineageRecord{} + iliKey := client.ObjectKey{Name: "packinstalled-cilium-v1-ccs-mgmt", Namespace: "ont-system"} if err := fakeClient.Get(context.Background(), iliKey, ili); err != nil { - t.Fatalf("expected InfrastructureLineageIndex to exist: %v", err) + t.Fatalf("expected LineageRecord to exist: %v", err) } - if ili.Spec.RootBinding.RootKind != "InfrastructurePackInstance" { - t.Errorf("expected RootKind=InfrastructurePackInstance, got %q", ili.Spec.RootBinding.RootKind) + if ili.Spec.RootBinding.RootKind != "PackInstalled" { + t.Errorf("expected RootKind=PackInstalled, got %q", ili.Spec.RootBinding.RootKind) } if ili.Spec.RootBinding.RootName != "cilium-v1-ccs-mgmt" { t.Errorf("expected RootName=cilium-v1-ccs-mgmt, got %q", ili.Spec.RootBinding.RootName) diff --git a/test/unit/outcome_registry_test.go b/test/unit/outcome_registry_test.go index 1e1066b..90bce9b 100644 --- a/test/unit/outcome_registry_test.go +++ b/test/unit/outcome_registry_test.go @@ -11,9 +11,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" - "github.com/ontai-dev/seam-core/pkg/lineage" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" + "github.com/ontai-dev/seam/pkg/lineage" ) func newPackInstanceWithCondition(name, namespace, iliName, condType, condStatus, condReason string) *unstructured.Unstructured { @@ -41,14 +41,14 @@ func newPackInstanceWithCondition(name, namespace, iliName, condType, condStatus return u } -func newILIForOutcome(name, namespace string) *seamv1alpha1.InfrastructureLineageIndex { - return &seamv1alpha1.InfrastructureLineageIndex{ +func newILIForOutcome(name, namespace string) *seamv1alpha1.LineageRecord { + return &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ RootKind: "PackExecution", RootName: "exec-001", RootNamespace: namespace, @@ -83,7 +83,7 @@ func TestOutcomeRegistry_SucceededConditionAppendsEntry(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ Name: "packexecution-exec-001", Namespace: "seam-system", }, updated); err != nil { @@ -128,7 +128,7 @@ func TestOutcomeRegistry_FailedConditionAppendsFailedEntry(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ Name: "packexecution-exec-002", Namespace: "seam-system", }, updated); err != nil { @@ -177,7 +177,7 @@ func TestOutcomeRegistry_IdempotentOnSecondReconcile(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ Name: "packexecution-exec-003", Namespace: "seam-system", }, updated); err != nil { @@ -227,7 +227,7 @@ func TestOutcomeRegistry_DoesNotModifyDescendantRegistry(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ Name: "packexecution-exec-004", Namespace: "seam-system", }, updated); err != nil { diff --git a/test/unit/packoperationresult_types_test.go b/test/unit/packoperationresult_types_test.go deleted file mode 100644 index f0494ac..0000000 --- a/test/unit/packoperationresult_types_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package unit_test - -import ( - "encoding/json" - "testing" - - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" -) - -// TestPackOperationResultSpec_RevisionRequired verifies that Revision is -// marshalled without omitempty -- a zero value must appear in the JSON output. -func TestPackOperationResultSpec_RevisionRequired(t *testing.T) { - spec := seamv1alpha1.PackOperationResultSpec{ - Revision: 0, - Capability: "pack-deploy", - Status: seamv1alpha1.PackResultSucceeded, - } - - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("json.Marshal: %v", err) - } - - var m map[string]interface{} - if err := json.Unmarshal(data, &m); err != nil { - t.Fatalf("json.Unmarshal: %v", err) - } - - if _, ok := m["revision"]; !ok { - t.Error("revision field absent from JSON output; must not use omitempty") - } -} - -// TestPackOperationResultSpec_RevisionSerialization verifies round-trip for -// revision, previousRevisionRef, and talosClusterOperationResultRef. -func TestPackOperationResultSpec_RevisionSerialization(t *testing.T) { - spec := seamv1alpha1.PackOperationResultSpec{ - Revision: 7, - PreviousRevisionRef: "pack-deploy-result-exec-abc-r6", - TalosClusterOperationResultRef: "talos-op-result-xyz", - PackExecutionRef: "exec-abc", - ClusterPackRef: "cert-manager-v1.13.3", - Capability: "pack-deploy", - Status: seamv1alpha1.PackResultSucceeded, - } - - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("json.Marshal: %v", err) - } - - var out seamv1alpha1.PackOperationResultSpec - if err := json.Unmarshal(data, &out); err != nil { - t.Fatalf("json.Unmarshal: %v", err) - } - - if out.Revision != spec.Revision { - t.Errorf("Revision: got %d, want %d", out.Revision, spec.Revision) - } - if out.PreviousRevisionRef != spec.PreviousRevisionRef { - t.Errorf("PreviousRevisionRef: got %q, want %q", out.PreviousRevisionRef, spec.PreviousRevisionRef) - } - if out.TalosClusterOperationResultRef != spec.TalosClusterOperationResultRef { - t.Errorf("TalosClusterOperationResultRef: got %q, want %q", out.TalosClusterOperationResultRef, spec.TalosClusterOperationResultRef) - } -} - -// TestPackOperationResultSpec_TalosClusterOpRefDefaultsEmpty verifies that -// TalosClusterOperationResultRef is the empty string when not set, and is -// absent from the JSON output (omitempty semantics). -func TestPackOperationResultSpec_TalosClusterOpRefDefaultsEmpty(t *testing.T) { - spec := seamv1alpha1.PackOperationResultSpec{ - Revision: 1, - Capability: "pack-deploy", - Status: seamv1alpha1.PackResultSucceeded, - } - - if spec.TalosClusterOperationResultRef != "" { - t.Errorf("TalosClusterOperationResultRef: expected empty string default, got %q", spec.TalosClusterOperationResultRef) - } - - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("json.Marshal: %v", err) - } - - var m map[string]interface{} - if err := json.Unmarshal(data, &m); err != nil { - t.Fatalf("json.Unmarshal: %v", err) - } - - if _, present := m["talosClusterOperationResultRef"]; present { - t.Error("talosClusterOperationResultRef present in JSON when empty; expected omitted (omitempty)") - } - if _, present := m["previousRevisionRef"]; present { - t.Error("previousRevisionRef present in JSON when empty; expected omitted (omitempty)") - } -} - -// TestPackOperationResultSpec_FirstRevisionNopredecessor verifies that a -// first-write result (revision=1) has empty PreviousRevisionRef. -func TestPackOperationResultSpec_FirstRevisionNopredecessor(t *testing.T) { - spec := seamv1alpha1.PackOperationResultSpec{ - Revision: 1, - Capability: "pack-deploy", - Status: seamv1alpha1.PackResultSucceeded, - } - - if spec.PreviousRevisionRef != "" { - t.Errorf("PreviousRevisionRef: expected empty for revision 1, got %q", spec.PreviousRevisionRef) - } -} diff --git a/test/unit/principal_propagation_test.go b/test/unit/principal_propagation_test.go index 54cf6d7..f7ececd 100644 --- a/test/unit/principal_propagation_test.go +++ b/test/unit/principal_propagation_test.go @@ -11,9 +11,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - seamv1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/internal/controller" - "github.com/ontai-dev/seam-core/pkg/lineage" + seamv1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" + "github.com/ontai-dev/seam/internal/controller" + "github.com/ontai-dev/seam/pkg/lineage" ) func newTalosCluster(name, namespace string, annotations map[string]string) *unstructured.Unstructured { @@ -31,7 +31,7 @@ func newTalosCluster(name, namespace string, annotations map[string]string) *uns "type": "LineageSynced", "status": "False", "reason": "LineageControllerAbsent", - "message": "InfrastructureLineageController is not yet deployed.", + "message": "LineageController is not yet deployed.", "lastTransitionTime": metav1.Now().UTC().Format("2006-01-02T15:04:05Z"), }, }, "status", "conditions") @@ -55,7 +55,8 @@ func TestPrincipalPropagation_ILICreatedWithDeclaringPrincipal(t *testing.T) { lineage.AnnotationDeclaringPrincipal: "alice@example.com", }) c := fake.NewClientBuilder().WithScheme(newTestScheme(t)). - WithStatusSubresource(tc, &seamv1alpha1.InfrastructureLineageIndex{}).Build() + WithObjects(newCRDObject(talosClusterGVK, true)). + WithStatusSubresource(tc, &seamv1alpha1.LineageRecord{}).Build() r := newLineageReconcilerForPrincipal(t, c) if err := c.Create(context.Background(), tc); err != nil { t.Fatalf("create TalosCluster: %v", err) @@ -68,9 +69,9 @@ func TestPrincipalPropagation_ILICreatedWithDeclaringPrincipal(t *testing.T) { t.Fatalf("reconcile: %v", err) } - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ - Name: "infrastructuretaloscluster-prod", + Name: "taloscluster-prod", Namespace: "seam-system", }, ili); err != nil { t.Fatalf("get ILI: %v", err) @@ -87,7 +88,8 @@ func TestPrincipalPropagation_ILICreatedWithDeclaringPrincipal(t *testing.T) { func TestPrincipalPropagation_AnnotationAbsentSetsSystemUnknown(t *testing.T) { tc := newTalosCluster("dev", "seam-system", nil) c := fake.NewClientBuilder().WithScheme(newTestScheme(t)). - WithStatusSubresource(tc, &seamv1alpha1.InfrastructureLineageIndex{}).Build() + WithObjects(newCRDObject(talosClusterGVK, true)). + WithStatusSubresource(tc, &seamv1alpha1.LineageRecord{}).Build() r := newLineageReconcilerForPrincipal(t, c) if err := c.Create(context.Background(), tc); err != nil { t.Fatalf("create TalosCluster: %v", err) @@ -99,9 +101,9 @@ func TestPrincipalPropagation_AnnotationAbsentSetsSystemUnknown(t *testing.T) { t.Fatalf("reconcile: %v", err) } - ili := &seamv1alpha1.InfrastructureLineageIndex{} + ili := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ - Name: "infrastructuretaloscluster-dev", Namespace: "seam-system", + Name: "taloscluster-dev", Namespace: "seam-system", }, ili); err != nil { t.Fatalf("get ILI: %v", err) } @@ -118,14 +120,14 @@ func TestPrincipalPropagation_DescendantActorRefMatchesILI(t *testing.T) { c := fake.NewClientBuilder().WithScheme(newTestScheme(t)).Build() // Pre-create an ILI with a known declaringPrincipal. - ili := &seamv1alpha1.InfrastructureLineageIndex{ + ili := &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ - Name: "infrastructuretaloscluster-prod", + Name: "taloscluster-prod", Namespace: "seam-system", }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ - RootKind: "InfrastructureTalosCluster", + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ + RootKind: "TalosCluster", RootName: "prod", RootNamespace: "seam-system", RootUID: "uid-tc-prod", @@ -138,7 +140,7 @@ func TestPrincipalPropagation_DescendantActorRefMatchesILI(t *testing.T) { } // Create a RunnerConfig with the root-ili label pointing to this ILI. - rc := newRunnerConfigWithActorRef("rc-001", "ont-system", "infrastructuretaloscluster-prod", "seam-system", "alice@example.com") + rc := newRunnerConfigWithActorRef("rc-001", "ont-system", "taloscluster-prod", "seam-system", "alice@example.com") if err := c.Create(context.Background(), rc); err != nil { t.Fatalf("create RunnerConfig: %v", err) } @@ -154,9 +156,9 @@ func TestPrincipalPropagation_DescendantActorRefMatchesILI(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ - Name: "infrastructuretaloscluster-prod", Namespace: "seam-system", + Name: "taloscluster-prod", Namespace: "seam-system", }, updated); err != nil { t.Fatalf("get ILI: %v", err) } @@ -175,14 +177,14 @@ func TestPrincipalPropagation_DescendantActorRefMatchesILI(t *testing.T) { func TestPrincipalPropagation_DescendantCreatedAtIsSet(t *testing.T) { c := fake.NewClientBuilder().WithScheme(newTestScheme(t)).Build() - ili := &seamv1alpha1.InfrastructureLineageIndex{ + ili := &seamv1alpha1.LineageRecord{ ObjectMeta: metav1.ObjectMeta{ - Name: "infrastructuretaloscluster-prod", + Name: "taloscluster-prod", Namespace: "seam-system", }, - Spec: seamv1alpha1.InfrastructureLineageIndexSpec{ - RootBinding: seamv1alpha1.InfrastructureLineageIndexRootBinding{ - RootKind: "InfrastructureTalosCluster", + Spec: seamv1alpha1.LineageRecordSpec{ + RootBinding: seamv1alpha1.LineageRecordRootBinding{ + RootKind: "TalosCluster", RootName: "prod", RootNamespace: "seam-system", }, @@ -192,7 +194,7 @@ func TestPrincipalPropagation_DescendantCreatedAtIsSet(t *testing.T) { t.Fatalf("create ILI: %v", err) } - rc := newRunnerConfig("rc-002", "ont-system", "infrastructuretaloscluster-prod") + rc := newRunnerConfig("rc-002", "ont-system", "taloscluster-prod") rc.SetLabels(addLabel(rc.GetLabels(), controller.LabelRootILINamespace, "seam-system")) if err := c.Create(context.Background(), rc); err != nil { t.Fatalf("create RunnerConfig: %v", err) @@ -209,9 +211,9 @@ func TestPrincipalPropagation_DescendantCreatedAtIsSet(t *testing.T) { t.Fatalf("reconcile: %v", err) } - updated := &seamv1alpha1.InfrastructureLineageIndex{} + updated := &seamv1alpha1.LineageRecord{} if err := c.Get(context.Background(), client.ObjectKey{ - Name: "infrastructuretaloscluster-prod", Namespace: "seam-system", + Name: "taloscluster-prod", Namespace: "seam-system", }, updated); err != nil { t.Fatalf("get ILI: %v", err) } diff --git a/test/unit/root_filter_test.go b/test/unit/root_filter_test.go new file mode 100644 index 0000000..149e0da --- /dev/null +++ b/test/unit/root_filter_test.go @@ -0,0 +1,314 @@ +package unit_test + +// Tests for the lineage-root CRD label filter and the 3-hop ownerReference resolver +// introduced in the LineageController admission filter (MIGRATION-3.8 Part 3). +// +// IsRootDeclaration reads the CRD object's metadata.labels to determine whether a +// GVK is a lineage root (infrastructure.ontai.dev/lineage-root="true"). +// +// ResolveRootOwner walks ownerReferences up to 3 hops to find the nearest root. + +import ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/ontai-dev/seam/internal/controller" + "github.com/ontai-dev/seam/pkg/lineage" +) + +// crdGVK is the GVK for CustomResourceDefinition objects. +var crdGVK = schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", +} + +// newCRDObject builds a minimal unstructured CRD object for a given GVK, optionally +// carrying the lineage-root label. +func newCRDObject(gvk schema.GroupVersionKind, isRoot bool) *unstructured.Unstructured { + crd := &unstructured.Unstructured{} + crd.SetGroupVersionKind(crdGVK) + crd.SetName(controller.CRDNameForGVK(gvk)) + if isRoot { + crd.SetLabels(map[string]string{ + lineage.LabelLineageRoot: "true", + }) + } + return crd +} + +// newUnstructuredObj builds a minimal unstructured object of the given GVK with +// optional ownerReferences. +func newUnstructuredObj(gvk schema.GroupVersionKind, name, ns string, ownerRefs []metav1.OwnerReference) *unstructured.Unstructured { + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(gvk) + u.SetName(name) + u.SetNamespace(ns) + u.SetUID(types.UID("uid-" + name)) + u.SetGeneration(1) + if len(ownerRefs) > 0 { + u.SetOwnerReferences(ownerRefs) + } + return u +} + +// ownerRef builds an OwnerReference with Controller=true. +func ownerRef(apiVersion, kind, name string, uid types.UID) metav1.OwnerReference { + isController := true + return metav1.OwnerReference{ + APIVersion: apiVersion, + Kind: kind, + Name: name, + UID: uid, + Controller: &isController, + } +} + +func buildFakeClientForFilter(t *testing.T, objs ...client.Object) client.Client { + t.Helper() + s := newTestScheme(t) + return fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).Build() +} + +// ── CRDNameForGVK tests ─────────────────────────────────────────────────────── + +func TestCRDNameForGVK_StandardKind(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "LineageRecord"} + got := controller.CRDNameForGVK(gvk) + if got != "lineagerecords.seam.ontai.dev" { + t.Errorf("CRDNameForGVK = %q, want lineagerecords.seam.ontai.dev", got) + } +} + +func TestCRDNameForGVK_KindEndingInY(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"} + got := controller.CRDNameForGVK(gvk) + if got != "packdeliveries.seam.ontai.dev" { + t.Errorf("CRDNameForGVK = %q, want packdeliveries.seam.ontai.dev", got) + } +} + +func TestCRDNameForGVK_KindEndingInS(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "platform.ontai.dev", Version: "v1alpha1", Kind: "ClusterMaintenance"} + got := controller.CRDNameForGVK(gvk) + if got != "clustermaintenances.platform.ontai.dev" { + t.Errorf("CRDNameForGVK = %q, want clustermaintenances.platform.ontai.dev", got) + } +} + +func TestCRDNameForGVK_TalosCluster(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + got := controller.CRDNameForGVK(gvk) + if got != "talosclusters.seam.ontai.dev" { + t.Errorf("CRDNameForGVK = %q, want talosclusters.seam.ontai.dev", got) + } +} + +// ── IsRootDeclaration tests ─────────────────────────────────────────────────── + +// TestIsRootDeclaration_CRDWithLabel verifies that a CRD carrying the lineage-root +// label causes IsRootDeclaration to return true. +func TestIsRootDeclaration_CRDWithLabel(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + crd := newCRDObject(gvk, true) + + c := buildFakeClientForFilter(t, crd) + got, err := controller.IsRootDeclaration(context.Background(), c, gvk) + if err != nil { + t.Fatalf("IsRootDeclaration: %v", err) + } + if !got { + t.Error("expected IsRootDeclaration=true for CRD with lineage-root label") + } +} + +// TestIsRootDeclaration_CRDWithoutLabel verifies that a CRD without the lineage-root +// label causes IsRootDeclaration to return false. +func TestIsRootDeclaration_CRDWithoutLabel(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "guardian.ontai.dev", Version: "v1alpha1", Kind: "RBACPolicy"} + crd := newCRDObject(gvk, false) + + c := buildFakeClientForFilter(t, crd) + got, err := controller.IsRootDeclaration(context.Background(), c, gvk) + if err != nil { + t.Fatalf("IsRootDeclaration: %v", err) + } + if got { + t.Error("expected IsRootDeclaration=false for CRD without lineage-root label") + } +} + +// TestIsRootDeclaration_CRDNotFound verifies that when the CRD does not exist, +// IsRootDeclaration returns false without an error (NotFound is not an error). +func TestIsRootDeclaration_CRDNotFound(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackExecution"} + // Do not add any CRD object to the fake client. + c := buildFakeClientForFilter(t) + + got, err := controller.IsRootDeclaration(context.Background(), c, gvk) + if err != nil { + t.Fatalf("IsRootDeclaration returned error for missing CRD: %v", err) + } + if got { + t.Error("expected IsRootDeclaration=false when CRD not found") + } +} + +// ── ResolveRootOwner tests ──────────────────────────────────────────────────── + +// TestResolveRootOwner_DirectOwnerIsRoot verifies that a 1-hop ownerRef pointing +// to a root-labelled GVK returns the owner on the first hop. +func TestResolveRootOwner_DirectOwnerIsRoot(t *testing.T) { + const ns = "seam-system" + rootGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + derivedGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} + + rootCRD := newCRDObject(rootGVK, true) + rootObj := newUnstructuredObj(rootGVK, "prod-cluster", ns, nil) + derived := newUnstructuredObj(derivedGVK, "rc-001", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "TalosCluster", "prod-cluster", rootObj.GetUID()), + }) + + c := buildFakeClientForFilter(t, rootCRD, rootObj, derived) + + found, err := controller.ResolveRootOwner(context.Background(), c, derived, 3) + if err != nil { + t.Fatalf("ResolveRootOwner: %v", err) + } + if found == nil { + t.Fatal("expected root to be found, got nil") + } + if found.GetName() != "prod-cluster" { + t.Errorf("found.Name = %q, want prod-cluster", found.GetName()) + } +} + +// TestResolveRootOwner_TwoHopsToRoot verifies that a 2-hop chain (derived → intermediate → root) +// resolves the root at hop 2. +func TestResolveRootOwner_TwoHopsToRoot(t *testing.T) { + const ns = "seam-system" + rootGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + midGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"} + leafGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} + + rootCRD := newCRDObject(rootGVK, true) + midCRD := newCRDObject(midGVK, false) + rootObj := newUnstructuredObj(rootGVK, "root-cluster", ns, nil) + midObj := newUnstructuredObj(midGVK, "pack-del-001", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "TalosCluster", "root-cluster", rootObj.GetUID()), + }) + leafObj := newUnstructuredObj(leafGVK, "pack-inst-001", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackDelivery", "pack-del-001", midObj.GetUID()), + }) + + c := buildFakeClientForFilter(t, rootCRD, midCRD, rootObj, midObj, leafObj) + + found, err := controller.ResolveRootOwner(context.Background(), c, leafObj, 3) + if err != nil { + t.Fatalf("ResolveRootOwner: %v", err) + } + if found == nil { + t.Fatal("expected root to be found at hop 2, got nil") + } + if found.GetName() != "root-cluster" { + t.Errorf("found.Name = %q, want root-cluster", found.GetName()) + } +} + +// TestResolveRootOwner_NoOwnerRefs verifies that an object with no ownerReferences +// returns nil without error. +func TestResolveRootOwner_NoOwnerRefs(t *testing.T) { + const ns = "seam-system" + leafGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackExecution"} + leafObj := newUnstructuredObj(leafGVK, "exec-001", ns, nil) // no ownerRefs + + c := buildFakeClientForFilter(t, leafObj) + + found, err := controller.ResolveRootOwner(context.Background(), c, leafObj, 3) + if err != nil { + t.Fatalf("ResolveRootOwner: %v", err) + } + if found != nil { + t.Errorf("expected nil when no ownerRefs present, got %s", found.GetName()) + } +} + +// TestResolveRootOwner_ExceedsMaxHops verifies that a chain deeper than maxHops +// returns nil without error (walk stops at the hop limit). +func TestResolveRootOwner_ExceedsMaxHops(t *testing.T) { + const ns = "seam-system" + gvk := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} + crd := newCRDObject(gvk, false) // none of these are roots + + // Build a chain with 4 non-root hops before the root: A -> B -> C -> X -> D (root). + // With maxHops=3, the walker examines owners at hop 1 (B), hop 2 (C), hop 3 (X) + // and stops before reaching D (hop 4). Returns nil. + rootGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + rootCRD := newCRDObject(rootGVK, true) + dObj := newUnstructuredObj(rootGVK, "deep-root", ns, nil) + xObj := newUnstructuredObj(gvk, "hop-x", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "TalosCluster", "deep-root", dObj.GetUID()), + }) + cObj := newUnstructuredObj(gvk, "hop-c", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackInstalled", "hop-x", xObj.GetUID()), + }) + bObj := newUnstructuredObj(gvk, "hop-b", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackInstalled", "hop-c", cObj.GetUID()), + }) + aObj := newUnstructuredObj(gvk, "hop-a", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackInstalled", "hop-b", bObj.GetUID()), + }) + + c := buildFakeClientForFilter(t, crd, rootCRD, dObj, xObj, cObj, bObj, aObj) + + found, err := controller.ResolveRootOwner(context.Background(), c, aObj, 3) + if err != nil { + t.Fatalf("ResolveRootOwner: %v", err) + } + if found != nil { + t.Errorf("expected nil when root is beyond maxHops, got %s", found.GetName()) + } +} + +// TestResolveRootOwner_ThreeHopsExact verifies that a 3-hop chain where the root +// is at exactly hop 3 is resolved successfully (boundary condition). +func TestResolveRootOwner_ThreeHopsExact(t *testing.T) { + const ns = "seam-system" + rootGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "TalosCluster"} + midGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackDelivery"} + leafGVK := schema.GroupVersionKind{Group: "seam.ontai.dev", Version: "v1alpha1", Kind: "PackInstalled"} + + rootCRD := newCRDObject(rootGVK, true) + midCRD := newCRDObject(midGVK, false) + + rootObj := newUnstructuredObj(rootGVK, "exact-root", ns, nil) + mid1 := newUnstructuredObj(midGVK, "mid1", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "TalosCluster", "exact-root", rootObj.GetUID()), + }) + mid2 := newUnstructuredObj(midGVK, "mid2", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackDelivery", "mid1", mid1.GetUID()), + }) + leafObj := newUnstructuredObj(leafGVK, "leaf", ns, []metav1.OwnerReference{ + ownerRef("seam.ontai.dev/v1alpha1", "PackDelivery", "mid2", mid2.GetUID()), + }) + + c := buildFakeClientForFilter(t, rootCRD, midCRD, rootObj, mid1, mid2, leafObj) + + found, err := controller.ResolveRootOwner(context.Background(), c, leafObj, 3) + if err != nil { + t.Fatalf("ResolveRootOwner: %v", err) + } + if found == nil { + t.Fatal("expected root to be found at exactly 3 hops, got nil") + } + if found.GetName() != "exact-root" { + t.Errorf("found.Name = %q, want exact-root", found.GetName()) + } +} diff --git a/test/unit/t2b5_types_test.go b/test/unit/t2b5_types_test.go index 58bbc20..e82b956 100644 --- a/test/unit/t2b5_types_test.go +++ b/test/unit/t2b5_types_test.go @@ -1,8 +1,7 @@ -// Package unit contains unit and serialization integrity tests for the T-2B-5 -// Go type additions: InfrastructureRunnerConfig, InfrastructureClusterPack, -// InfrastructurePackExecution, InfrastructurePackInstance, InfrastructurePackReceipt, -// InfrastructurePackBuild, InfrastructureTalosCluster, and DriftSignal. -// seam-core-schema.md. Decision I. +// Package unit contains unit and serialization integrity tests for T-2B-5 +// Go type additions that remain in seam-core: RunnerConfig and DriftSignal. +// Pack lifecycle types and TalosCluster have been migrated out of seam-core. +// seam-core-schema.md. Decision I, MIGRATION-3.1. package unit import ( @@ -11,16 +10,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/pkg/lineage" + v1alpha1 "github.com/ontai-dev/seam/api/v1alpha1" ) -// --- InfrastructureRunnerConfig --- +// --- RunnerConfig --- -func TestInfrastructureRunnerConfig_RequiredFields(t *testing.T) { +func TestRunnerConfig_RequiredFields(t *testing.T) { t.Parallel() - rc := v1alpha1.InfrastructureRunnerConfig{ - Spec: v1alpha1.InfrastructureRunnerConfigSpec{ + rc := v1alpha1.RunnerConfig{ + Spec: v1alpha1.RunnerConfigSpec{ ClusterRef: "ccs-mgmt", RunnerImage: "10.20.0.1:5000/ontai-dev/conductor:v1.9.3-dev", }, @@ -33,15 +31,15 @@ func TestInfrastructureRunnerConfig_RequiredFields(t *testing.T) { } } -func TestInfrastructureRunnerConfig_RoundTrip(t *testing.T) { +func TestRunnerConfig_RoundTrip(t *testing.T) { t.Parallel() - rc := v1alpha1.InfrastructureRunnerConfig{ + rc := v1alpha1.RunnerConfig{ TypeMeta: metav1.TypeMeta{ - APIVersion: "infrastructure.ontai.dev/v1alpha1", - Kind: "InfrastructureRunnerConfig", + APIVersion: "seam.ontai.dev/v1alpha1", + Kind: "RunnerConfig", }, ObjectMeta: metav1.ObjectMeta{Name: "ccs-mgmt", Namespace: "ont-system"}, - Spec: v1alpha1.InfrastructureRunnerConfigSpec{ + Spec: v1alpha1.RunnerConfigSpec{ ClusterRef: "ccs-mgmt", RunnerImage: "10.20.0.1:5000/ontai-dev/conductor:v1.9.3-dev", Steps: []v1alpha1.RunnerConfigStep{ @@ -54,7 +52,7 @@ func TestInfrastructureRunnerConfig_RoundTrip(t *testing.T) { if err != nil { t.Fatalf("marshal: %v", err) } - var got v1alpha1.InfrastructureRunnerConfig + var got v1alpha1.RunnerConfig if err := json.Unmarshal(data, &got); err != nil { t.Fatalf("unmarshal: %v", err) } @@ -66,7 +64,7 @@ func TestInfrastructureRunnerConfig_RoundTrip(t *testing.T) { } } -func TestInfrastructureRunnerConfig_StepResultPhaseEnum(t *testing.T) { +func TestRunnerConfig_StepResultPhaseEnum(t *testing.T) { t.Parallel() cases := []v1alpha1.RunnerStepResultPhase{ v1alpha1.RunnerStepSucceeded, @@ -80,268 +78,6 @@ func TestInfrastructureRunnerConfig_StepResultPhaseEnum(t *testing.T) { } } -// --- InfrastructureClusterPack --- - -func TestInfrastructureClusterPack_RequiredFields(t *testing.T) { - t.Parallel() - cp := v1alpha1.InfrastructureClusterPack{ - Spec: v1alpha1.InfrastructureClusterPackSpec{ - Version: "v1.14.0-r1", - RegistryRef: v1alpha1.InfrastructurePackRegistryRef{ - URL: "10.20.0.1:5000/ontai-dev/packs/cert-manager-helm", - Digest: "sha256:abc123", - }, - }, - } - if cp.Spec.Version == "" { - t.Fatal("Version must be set") - } - if cp.Spec.RegistryRef.URL == "" { - t.Fatal("RegistryRef.URL must be set") - } -} - -func TestInfrastructureClusterPack_WS8bDigestFields(t *testing.T) { - t.Parallel() - cp := v1alpha1.InfrastructureClusterPack{ - Spec: v1alpha1.InfrastructureClusterPackSpec{ - Version: "v1.14.0-r1", - RegistryRef: v1alpha1.InfrastructurePackRegistryRef{URL: "r", Digest: "sha256:a"}, - RBACDigest: "sha256:rbac", - WorkloadDigest: "sha256:workload", - ClusterScopedDigest: "sha256:clusterscoped", - ChartURL: "http://10.20.0.1:8888/cert-manager-v1.14.0.tgz", - ChartName: "cert-manager", - ChartVersion: "v1.14.0", - HelmVersion: "v3.17.3", - }, - } - data, err := json.Marshal(cp) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureClusterPack - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Spec.RBACDigest != "sha256:rbac" { - t.Errorf("RBACDigest: got %q", got.Spec.RBACDigest) - } - if got.Spec.ClusterScopedDigest != "sha256:clusterscoped" { - t.Errorf("ClusterScopedDigest: got %q", got.Spec.ClusterScopedDigest) - } - if got.Spec.HelmVersion != "v3.17.3" { - t.Errorf("HelmVersion: got %q", got.Spec.HelmVersion) - } -} - -// --- InfrastructurePackExecution --- - -func TestInfrastructurePackExecution_RequiredFields(t *testing.T) { - t.Parallel() - pe := v1alpha1.InfrastructurePackExecution{ - Spec: v1alpha1.InfrastructurePackExecutionSpec{ - ClusterPackRef: v1alpha1.InfrastructureClusterPackRef{ - Name: "cert-manager-helm-v1.14.0-r1", - Version: "v1.14.0-r1", - }, - TargetClusterRef: "ccs-mgmt", - }, - } - if pe.Spec.ClusterPackRef.Name == "" { - t.Fatal("ClusterPackRef.Name must be set") - } - if pe.Spec.TargetClusterRef == "" { - t.Fatal("TargetClusterRef must be set") - } -} - -func TestInfrastructurePackExecution_LineageFieldPresent(t *testing.T) { - t.Parallel() - chain := &lineage.SealedCausalChain{ - RootKind: "InfrastructurePackExecution", - RootName: "cert-manager-helm-v1.14.0-r1", - } - pe := v1alpha1.InfrastructurePackExecution{ - Spec: v1alpha1.InfrastructurePackExecutionSpec{ - ClusterPackRef: v1alpha1.InfrastructureClusterPackRef{ - Name: "cert-manager-helm-v1.14.0-r1", - Version: "v1.14.0-r1", - }, - TargetClusterRef: "ccs-mgmt", - Lineage: chain, - }, - } - data, err := json.Marshal(pe) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructurePackExecution - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Spec.Lineage == nil { - t.Fatal("Lineage must survive round trip") - } - if got.Spec.Lineage.RootKind != "InfrastructurePackExecution" { - t.Errorf("Lineage.RootKind: got %q", got.Spec.Lineage.RootKind) - } -} - -// --- InfrastructurePackInstance --- - -func TestInfrastructurePackInstance_RequiredFields(t *testing.T) { - t.Parallel() - pi := v1alpha1.InfrastructurePackInstance{ - Spec: v1alpha1.InfrastructurePackInstanceSpec{ - ClusterPackRef: "cert-manager-helm-v1.14.0-r1", - Version: "v1.14.0-r1", - TargetClusterRef: "ccs-mgmt", - }, - } - if pi.Spec.Version == "" { - t.Fatal("Version must be set") - } -} - -// --- InfrastructurePackReceipt --- - -func TestInfrastructurePackReceipt_SignatureFields(t *testing.T) { - t.Parallel() - pr := v1alpha1.InfrastructurePackReceipt{ - Spec: v1alpha1.InfrastructurePackReceiptSpec{ - PackInstanceRef: "cert-manager-ccs-dev", - SignatureRef: "seam-pack-signed-ccs-dev-cert-manager-ccs-dev", - ClusterPackRef: "cert-manager-helm-v1.14.0-r1", - TargetClusterRef: "ccs-mgmt", - RBACDigest: "sha256:rbac", - WorkloadDigest: "sha256:workload", - }, - Status: v1alpha1.InfrastructurePackReceiptStatus{ - Verified: true, - Signature: "base64sig==", - }, - } - data, err := json.Marshal(pr) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructurePackReceipt - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if !got.Status.Verified { - t.Error("Status.Verified must survive round trip") - } - if got.Status.Signature != "base64sig==" { - t.Errorf("Status.Signature: got %q", got.Status.Signature) - } - if got.Spec.RBACDigest != "sha256:rbac" { - t.Errorf("RBACDigest: got %q", got.Spec.RBACDigest) - } - if got.Spec.PackInstanceRef != "cert-manager-ccs-dev" { - t.Errorf("PackInstanceRef: got %q", got.Spec.PackInstanceRef) - } -} - -// --- InfrastructurePackBuild --- - -func TestInfrastructurePackBuild_CategoryEnum(t *testing.T) { - t.Parallel() - cases := []v1alpha1.InfrastructurePackBuildCategory{ - v1alpha1.InfrastructurePackBuildCategoryHelm, - v1alpha1.InfrastructurePackBuildCategoryKustomize, - v1alpha1.InfrastructurePackBuildCategoryRaw, - } - for _, c := range cases { - if c == "" { - t.Errorf("category constant is empty") - } - } -} - -func TestInfrastructurePackBuild_HelmSourceRoundTrip(t *testing.T) { - t.Parallel() - pb := v1alpha1.InfrastructurePackBuild{ - Spec: v1alpha1.InfrastructurePackBuildSpec{ - ComponentName: "cert-manager", - Category: v1alpha1.InfrastructurePackBuildCategoryHelm, - HelmSource: &v1alpha1.InfrastructurePackHelmSource{ - URL: "http://10.20.0.1:8888/cert-manager-v1.14.0.tgz", - Chart: "cert-manager", - Version: "v1.14.0", - }, - TargetClusters: []string{"ccs-mgmt"}, - }, - } - data, err := json.Marshal(pb) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructurePackBuild - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Spec.HelmSource == nil { - t.Fatal("HelmSource must survive round trip") - } - if got.Spec.HelmSource.Chart != "cert-manager" { - t.Errorf("HelmSource.Chart: got %q", got.Spec.HelmSource.Chart) - } -} - -// --- InfrastructureTalosCluster --- - -func TestInfrastructureTalosCluster_ModeEnum(t *testing.T) { - t.Parallel() - cases := []v1alpha1.InfrastructureTalosClusterMode{ - v1alpha1.InfrastructureTalosClusterModeBootstrap, - v1alpha1.InfrastructureTalosClusterModeImport, - } - for _, c := range cases { - if c == "" { - t.Errorf("mode constant is empty") - } - } -} - -func TestInfrastructureTalosCluster_ImportRoleRequired(t *testing.T) { - t.Parallel() - tc := v1alpha1.InfrastructureTalosCluster{ - Spec: v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeImport, - Role: v1alpha1.InfrastructureTalosClusterRoleManagement, - ClusterEndpoint: "https://10.20.0.10:6443", - }, - } - if tc.Spec.Role == "" { - t.Fatal("Role must be set for mode=import") - } -} - -func TestInfrastructureTalosCluster_LineageFieldPresent(t *testing.T) { - t.Parallel() - chain := &lineage.SealedCausalChain{RootKind: "InfrastructureTalosCluster", RootName: "ccs-mgmt"} - tc := v1alpha1.InfrastructureTalosCluster{ - Spec: v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeImport, - Role: v1alpha1.InfrastructureTalosClusterRoleManagement, - Lineage: chain, - }, - } - data, err := json.Marshal(tc) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosCluster - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Spec.Lineage == nil { - t.Fatal("Lineage must survive round trip") - } -} - // --- DriftSignal --- func TestDriftSignal_StateEnum(t *testing.T) { @@ -410,7 +146,6 @@ func TestDriftSignal_EscalationCounterRoundTrip(t *testing.T) { func TestDriftSignal_StateTransitionSequence(t *testing.T) { t.Parallel() - // Verify the four valid state values are distinct strings in the correct order. ordered := []v1alpha1.DriftSignalState{ v1alpha1.DriftSignalStatePending, v1alpha1.DriftSignalStateDelivered, diff --git a/test/unit/t2b8_taloscluster_types_test.go b/test/unit/t2b8_taloscluster_types_test.go deleted file mode 100644 index 2bc17c1..0000000 --- a/test/unit/t2b8_taloscluster_types_test.go +++ /dev/null @@ -1,454 +0,0 @@ -// Package unit contains T-2B-8 tests for InfrastructureTalosCluster type reconciliation. -// -// Covers: -// - InfrastructureProvider enum constants and serialization -// - InfrastructureTalosClusterOrigin typed enum -// - ClusterEndpoint rename from Endpoint -// - NodeAddresses field -// - Full InfrastructureCAPIConfig six-field struct -// - InfrastructureLocalObjectRef and status.CAPIClusterRef -// - status.Origin typed enum round-trip -// - New condition type and reason constants added to seam-core/pkg/conditions -package unit - -import ( - "encoding/json" - "testing" - - v1alpha1 "github.com/ontai-dev/seam-core/api/v1alpha1" - "github.com/ontai-dev/seam-core/pkg/conditions" -) - -// --- InfrastructureProvider enum --- - -func TestInfrastructureProvider_Constants(t *testing.T) { - t.Parallel() - cases := []struct { - name string - value v1alpha1.InfrastructureProvider - }{ - {"native", v1alpha1.InfrastructureProviderNative}, - {"capi", v1alpha1.InfrastructureProviderCAPI}, - {"screen", v1alpha1.InfrastructureProviderScreen}, - } - for _, tc := range cases { - if string(tc.value) != tc.name { - t.Errorf("InfrastructureProvider %q: got %q", tc.name, tc.value) - } - } -} - -func TestInfrastructureProvider_SerializationRoundTrip(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - InfrastructureProvider: v1alpha1.InfrastructureProviderCAPI, - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterSpec - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.InfrastructureProvider != v1alpha1.InfrastructureProviderCAPI { - t.Errorf("InfrastructureProvider: got %q want %q", got.InfrastructureProvider, v1alpha1.InfrastructureProviderCAPI) - } -} - -func TestInfrastructureProvider_AbsentWhenZero(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - // InfrastructureProvider not set -- should be absent in JSON (omitempty) - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - t.Fatalf("unmarshal to map: %v", err) - } - if _, ok := raw["infrastructureProvider"]; ok { - t.Error("infrastructureProvider present in JSON but should be absent (omitempty)") - } -} - -// --- ClusterEndpoint (renamed from Endpoint) --- - -func TestInfrastructureTalosCluster_ClusterEndpointRoundTrip(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeImport, - Role: v1alpha1.InfrastructureTalosClusterRoleManagement, - ClusterEndpoint: "https://10.20.0.10:6443", - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterSpec - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.ClusterEndpoint != "https://10.20.0.10:6443" { - t.Errorf("ClusterEndpoint: got %q want %q", got.ClusterEndpoint, "https://10.20.0.10:6443") - } -} - -func TestInfrastructureTalosCluster_ClusterEndpoint_JSONKey(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeImport, - ClusterEndpoint: "https://192.168.0.1:6443", - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - t.Fatalf("unmarshal to map: %v", err) - } - if _, ok := raw["clusterEndpoint"]; !ok { - t.Error("expected clusterEndpoint key in JSON, not found") - } - if _, ok := raw["endpoint"]; ok { - t.Error("old endpoint key must not be present in JSON") - } -} - -// --- NodeAddresses --- - -func TestInfrastructureTalosCluster_NodeAddressesRoundTrip(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeImport, - NodeAddresses: []string{"10.20.0.11", "10.20.0.12", "10.20.0.13"}, - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterSpec - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if len(got.NodeAddresses) != 3 { - t.Fatalf("NodeAddresses: got %d entries want 3", len(got.NodeAddresses)) - } - if got.NodeAddresses[0] != "10.20.0.11" { - t.Errorf("NodeAddresses[0]: got %q want %q", got.NodeAddresses[0], "10.20.0.11") - } -} - -func TestInfrastructureTalosCluster_NodeAddresses_AbsentWhenEmpty(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - t.Fatalf("unmarshal to map: %v", err) - } - if _, ok := raw["nodeAddresses"]; ok { - t.Error("nodeAddresses present in JSON but should be absent (omitempty)") - } -} - -// --- Full InfrastructureCAPIConfig (6-field struct) --- - -func TestInfrastructureCAPIConfig_FullFieldsRoundTrip(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - CAPI: &v1alpha1.InfrastructureCAPIConfig{ - Enabled: true, - TalosVersion: "v1.9.3", - KubernetesVersion: "v1.32.0", - ControlPlane: &v1alpha1.InfrastructureCAPIControlPlaneConfig{ - Replicas: 3, - }, - Workers: []v1alpha1.InfrastructureCAPIWorkerPool{ - { - Name: "workers", - Replicas: 2, - SeamInfrastructureMachineNames: []string{"sim-worker-01", "sim-worker-02"}, - }, - }, - CiliumPackRef: &v1alpha1.InfrastructureCAPICiliumPackRef{ - Name: "cilium-ccs-test-v1.16.6-r1", - Version: "v1.16.6-r1", - }, - }, - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterSpec - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.CAPI == nil { - t.Fatal("CAPI must survive round trip") - } - if !got.CAPI.Enabled { - t.Error("CAPI.Enabled: got false want true") - } - if got.CAPI.TalosVersion != "v1.9.3" { - t.Errorf("CAPI.TalosVersion: got %q want v1.9.3", got.CAPI.TalosVersion) - } - if got.CAPI.KubernetesVersion != "v1.32.0" { - t.Errorf("CAPI.KubernetesVersion: got %q want v1.32.0", got.CAPI.KubernetesVersion) - } - if got.CAPI.ControlPlane == nil || got.CAPI.ControlPlane.Replicas != 3 { - t.Errorf("CAPI.ControlPlane.Replicas: got %v", got.CAPI.ControlPlane) - } - if len(got.CAPI.Workers) != 1 || got.CAPI.Workers[0].Replicas != 2 { - t.Errorf("CAPI.Workers: got %+v", got.CAPI.Workers) - } - if len(got.CAPI.Workers[0].SeamInfrastructureMachineNames) != 2 { - t.Errorf("CAPI.Workers[0].SeamInfrastructureMachineNames: got %v", got.CAPI.Workers[0].SeamInfrastructureMachineNames) - } - if got.CAPI.CiliumPackRef == nil || got.CAPI.CiliumPackRef.Name != "cilium-ccs-test-v1.16.6-r1" { - t.Errorf("CAPI.CiliumPackRef: got %+v", got.CAPI.CiliumPackRef) - } -} - -func TestInfrastructureCAPIConfig_EnabledFalse_OptionalFieldsAbsent(t *testing.T) { - t.Parallel() - spec := v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - CAPI: &v1alpha1.InfrastructureCAPIConfig{ - Enabled: false, - }, - } - data, err := json.Marshal(spec) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - t.Fatalf("unmarshal to map: %v", err) - } - capi, ok := raw["capi"].(map[string]interface{}) - if !ok { - t.Fatal("capi field missing from JSON") - } - for _, field := range []string{"talosVersion", "kubernetesVersion", "controlPlane", "workers", "ciliumPackRef"} { - if _, ok := capi[field]; ok { - t.Errorf("capi.%s present in JSON but should be absent (omitempty)", field) - } - } -} - -// --- InfrastructureLocalObjectRef and status.CAPIClusterRef --- - -func TestInfrastructureLocalObjectRef_RoundTrip(t *testing.T) { - t.Parallel() - ref := v1alpha1.InfrastructureLocalObjectRef{ - Name: "ccs-test", - Namespace: "seam-tenant-ccs-test", - } - data, err := json.Marshal(ref) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureLocalObjectRef - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Name != "ccs-test" { - t.Errorf("Name: got %q want ccs-test", got.Name) - } - if got.Namespace != "seam-tenant-ccs-test" { - t.Errorf("Namespace: got %q want seam-tenant-ccs-test", got.Namespace) - } -} - -func TestInfrastructureTalosClusterStatus_CAPIClusterRef_RoundTrip(t *testing.T) { - t.Parallel() - status := v1alpha1.InfrastructureTalosClusterStatus{ - CAPIClusterRef: &v1alpha1.InfrastructureLocalObjectRef{ - Name: "ccs-test", - Namespace: "seam-tenant-ccs-test", - }, - } - data, err := json.Marshal(status) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterStatus - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.CAPIClusterRef == nil { - t.Fatal("CAPIClusterRef must survive round trip") - } - if got.CAPIClusterRef.Name != "ccs-test" { - t.Errorf("CAPIClusterRef.Name: got %q want ccs-test", got.CAPIClusterRef.Name) - } -} - -func TestInfrastructureTalosClusterStatus_CAPIClusterRef_AbsentWhenNil(t *testing.T) { - t.Parallel() - status := v1alpha1.InfrastructureTalosClusterStatus{ - ObservedGeneration: 1, - } - data, err := json.Marshal(status) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - t.Fatalf("unmarshal to map: %v", err) - } - if _, ok := raw["capiClusterRef"]; ok { - t.Error("capiClusterRef present in JSON but should be absent when nil (omitempty)") - } -} - -// --- InfrastructureTalosClusterOrigin typed enum --- - -func TestInfrastructureTalosClusterOrigin_Constants(t *testing.T) { - t.Parallel() - if string(v1alpha1.InfrastructureTalosClusterOriginBootstrapped) != "bootstrapped" { - t.Errorf("OriginBootstrapped: got %q", v1alpha1.InfrastructureTalosClusterOriginBootstrapped) - } - if string(v1alpha1.InfrastructureTalosClusterOriginImported) != "imported" { - t.Errorf("OriginImported: got %q", v1alpha1.InfrastructureTalosClusterOriginImported) - } -} - -func TestInfrastructureTalosClusterStatus_Origin_TypedEnum_RoundTrip(t *testing.T) { - t.Parallel() - status := v1alpha1.InfrastructureTalosClusterStatus{ - Origin: v1alpha1.InfrastructureTalosClusterOriginBootstrapped, - } - data, err := json.Marshal(status) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosClusterStatus - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Origin != v1alpha1.InfrastructureTalosClusterOriginBootstrapped { - t.Errorf("Origin: got %q want bootstrapped", got.Origin) - } -} - -// --- New conditions constants --- - -func TestConditionType_Bootstrapped(t *testing.T) { - t.Parallel() - if conditions.ConditionTypeBootstrapped != "Bootstrapped" { - t.Errorf("ConditionTypeBootstrapped: got %q", conditions.ConditionTypeBootstrapped) - } -} - -func TestConditionType_ScreenProviderNotImplemented(t *testing.T) { - t.Parallel() - if conditions.ConditionTypeScreenProviderNotImplemented != "ScreenProviderNotImplemented" { - t.Errorf("ConditionTypeScreenProviderNotImplemented: got %q", conditions.ConditionTypeScreenProviderNotImplemented) - } -} - -func TestConditionType_PhaseFailed(t *testing.T) { - t.Parallel() - if conditions.ConditionTypePhaseFailed != "PhaseFailed" { - t.Errorf("ConditionTypePhaseFailed: got %q", conditions.ConditionTypePhaseFailed) - } -} - -func TestConditionType_KubeconfigUnavailable(t *testing.T) { - t.Parallel() - if conditions.ConditionTypeKubeconfigUnavailable != "KubeconfigUnavailable" { - t.Errorf("ConditionTypeKubeconfigUnavailable: got %q", conditions.ConditionTypeKubeconfigUnavailable) - } -} - -func TestReason_ScreenNotImplemented(t *testing.T) { - t.Parallel() - if conditions.ReasonScreenNotImplemented != "ScreenNotImplemented" { - t.Errorf("ReasonScreenNotImplemented: got %q", conditions.ReasonScreenNotImplemented) - } -} - -func TestReason_TalosVersionRequired(t *testing.T) { - t.Parallel() - if conditions.ReasonTalosVersionRequired != "TalosVersionRequired" { - t.Errorf("ReasonTalosVersionRequired: got %q", conditions.ReasonTalosVersionRequired) - } -} - -func TestReason_TalosConfigSecretAbsent(t *testing.T) { - t.Parallel() - if conditions.ReasonTalosConfigSecretAbsent != "TalosConfigSecretAbsent" { - t.Errorf("ReasonTalosConfigSecretAbsent: got %q", conditions.ReasonTalosConfigSecretAbsent) - } -} - -// --- Full InfrastructureTalosCluster round-trip --- - -func TestInfrastructureTalosCluster_FullSpecRoundTrip(t *testing.T) { - t.Parallel() - tc := v1alpha1.InfrastructureTalosCluster{ - Spec: v1alpha1.InfrastructureTalosClusterSpec{ - Mode: v1alpha1.InfrastructureTalosClusterModeBootstrap, - TalosVersion: "v1.9.3", - ClusterEndpoint: "https://10.20.0.10:6443", - NodeAddresses: []string{"10.20.0.11", "10.20.0.12"}, - InfrastructureProvider: v1alpha1.InfrastructureProviderNative, - CAPI: &v1alpha1.InfrastructureCAPIConfig{ - Enabled: true, - TalosVersion: "v1.9.3", - KubernetesVersion: "v1.32.0", - ControlPlane: &v1alpha1.InfrastructureCAPIControlPlaneConfig{Replicas: 1}, - Workers: []v1alpha1.InfrastructureCAPIWorkerPool{{Name: "workers", Replicas: 2}}, - CiliumPackRef: &v1alpha1.InfrastructureCAPICiliumPackRef{Name: "cilium-ccs-test", Version: "v1.16.6-r1"}, - }, - }, - Status: v1alpha1.InfrastructureTalosClusterStatus{ - Origin: v1alpha1.InfrastructureTalosClusterOriginBootstrapped, - ObservedGeneration: 2, - CAPIClusterRef: &v1alpha1.InfrastructureLocalObjectRef{ - Name: "ccs-test", - Namespace: "seam-tenant-ccs-test", - }, - }, - } - data, err := json.Marshal(tc) - if err != nil { - t.Fatalf("marshal: %v", err) - } - var got v1alpha1.InfrastructureTalosCluster - if err := json.Unmarshal(data, &got); err != nil { - t.Fatalf("unmarshal: %v", err) - } - if got.Spec.ClusterEndpoint != "https://10.20.0.10:6443" { - t.Errorf("Spec.ClusterEndpoint: got %q", got.Spec.ClusterEndpoint) - } - if len(got.Spec.NodeAddresses) != 2 { - t.Errorf("Spec.NodeAddresses: got %d want 2", len(got.Spec.NodeAddresses)) - } - if got.Spec.InfrastructureProvider != v1alpha1.InfrastructureProviderNative { - t.Errorf("Spec.InfrastructureProvider: got %q", got.Spec.InfrastructureProvider) - } - if got.Spec.CAPI == nil || !got.Spec.CAPI.Enabled { - t.Error("Spec.CAPI.Enabled must be true") - } - if got.Status.Origin != v1alpha1.InfrastructureTalosClusterOriginBootstrapped { - t.Errorf("Status.Origin: got %q", got.Status.Origin) - } - if got.Status.CAPIClusterRef == nil || got.Status.CAPIClusterRef.Name != "ccs-test" { - t.Errorf("Status.CAPIClusterRef: got %v", got.Status.CAPIClusterRef) - } -} diff --git a/test/unit/webhook/authorship_gate_test.go b/test/unit/webhook/authorship_gate_test.go index 969cac2..28d082b 100644 --- a/test/unit/webhook/authorship_gate_test.go +++ b/test/unit/webhook/authorship_gate_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/ontai-dev/seam-core/internal/webhook" + "github.com/ontai-dev/seam/internal/webhook" ) // --- Non-intercepted kinds --- @@ -45,7 +45,7 @@ func TestEvaluateAuthorshipGate_NonInterceptedKind_Update_Allowed(t *testing.T) // The authorship gate covers CREATE and UPDATE only. func TestEvaluateAuthorshipGate_ILI_Delete_Allowed(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationDelete, RequestingUser: "system:admin", }) @@ -57,7 +57,7 @@ func TestEvaluateAuthorshipGate_ILI_Delete_Allowed(t *testing.T) { // Test A4 — ILI DELETE: allowed even for completely unauthorized user. func TestEvaluateAuthorshipGate_ILI_Delete_UnauthorizedUser_Allowed(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationDelete, RequestingUser: "unknown-human", }) @@ -71,7 +71,7 @@ func TestEvaluateAuthorshipGate_ILI_Delete_UnauthorizedUser_Allowed(t *testing.T // Test A5 — ILI CREATE from LineageController SA: allowed. CLAUDE.md §14 Decision 3. func TestEvaluateAuthorshipGate_ILI_Create_LineageControllerSA_Allowed(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: webhook.LineageControllerIdentity, }) @@ -83,7 +83,7 @@ func TestEvaluateAuthorshipGate_ILI_Create_LineageControllerSA_Allowed(t *testin // Test A6 — ILI UPDATE from LineageController SA: allowed. func TestEvaluateAuthorshipGate_ILI_Update_LineageControllerSA_Allowed(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, RequestingUser: webhook.LineageControllerIdentity, }) @@ -97,7 +97,7 @@ func TestEvaluateAuthorshipGate_ILI_Update_LineageControllerSA_Allowed(t *testin // Test A7 — ILI CREATE from human user: denied. CLAUDE.md §14 Decision 3. func TestEvaluateAuthorshipGate_ILI_Create_HumanUser_Denied(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "alice", }) @@ -112,7 +112,7 @@ func TestEvaluateAuthorshipGate_ILI_Create_HumanUser_Denied(t *testing.T) { // Test A8 — ILI UPDATE from human user: denied. func TestEvaluateAuthorshipGate_ILI_Update_HumanUser_Denied(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, RequestingUser: "bob", }) @@ -122,10 +122,10 @@ func TestEvaluateAuthorshipGate_ILI_Update_HumanUser_Denied(t *testing.T) { } // Test A9 — ILI CREATE from system:admin: denied. -// Even cluster-admin is not permitted to write InfrastructureLineageIndex. +// Even cluster-admin is not permitted to write LineageRecord. func TestEvaluateAuthorshipGate_ILI_Create_ClusterAdmin_Denied(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "system:admin", }) @@ -138,7 +138,7 @@ func TestEvaluateAuthorshipGate_ILI_Create_ClusterAdmin_Denied(t *testing.T) { // Only the specific lineage-controller SA is authorized — not any SA. func TestEvaluateAuthorshipGate_ILI_Create_OtherSA_Denied(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "system:serviceaccount:seam-system:some-other-controller", }) @@ -150,7 +150,7 @@ func TestEvaluateAuthorshipGate_ILI_Create_OtherSA_Denied(t *testing.T) { // Test A11 — ILI CREATE from empty user (unauthenticated): denied. func TestEvaluateAuthorshipGate_ILI_Create_EmptyUser_Denied(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "", }) @@ -164,7 +164,7 @@ func TestEvaluateAuthorshipGate_ILI_Create_EmptyUser_Denied(t *testing.T) { // Test A12 — Denial reason references CLAUDE.md §14 Decision 3. func TestEvaluateAuthorshipGate_DeniedReason_ReferencesDecision3(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "unauthorized-user", }) @@ -182,7 +182,7 @@ func TestEvaluateAuthorshipGate_DeniedReason_ReferencesDecision3(t *testing.T) { // Test A13 — Denial reason includes LineageControllerIdentity for observability. func TestEvaluateAuthorshipGate_DeniedReason_IncludesAuthorizedIdentity(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: "bad-actor", }) @@ -198,7 +198,7 @@ func TestEvaluateAuthorshipGate_DeniedReason_IncludesAuthorizedIdentity(t *testi func TestEvaluateAuthorshipGate_DeniedReason_IncludesRequestingUser(t *testing.T) { requester := "system:serviceaccount:default:some-controller" decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: requester, }) @@ -213,7 +213,7 @@ func TestEvaluateAuthorshipGate_DeniedReason_IncludesRequestingUser(t *testing.T // Test A15 — Reason is empty when allowed. func TestEvaluateAuthorshipGate_AllowedReason_IsEmpty(t *testing.T) { decision := webhook.EvaluateAuthorshipGate(webhook.AuthorshipGateRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, RequestingUser: webhook.LineageControllerIdentity, }) diff --git a/test/unit/webhook/domainref_validation_test.go b/test/unit/webhook/domainref_validation_test.go index 0dd8a24..1b3c4ab 100644 --- a/test/unit/webhook/domainref_validation_test.go +++ b/test/unit/webhook/domainref_validation_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/ontai-dev/seam-core/internal/webhook" + "github.com/ontai-dev/seam/internal/webhook" ) // TestEvaluateDomainRefValidation_NonILIKind_Allowed verifies that non-ILI kinds @@ -29,7 +29,7 @@ func TestEvaluateDomainRefValidation_NonILIKind_Allowed(t *testing.T) { // operations are always admitted — domainRef is validated only at CREATE. func TestEvaluateDomainRefValidation_UpdateOperation_Allowed(t *testing.T) { decision := webhook.EvaluateDomainRefValidation(webhook.DomainRefValidationRequest{ - Kind: "InfrastructureLineageIndex", + Kind: "LineageRecord", Operation: webhook.OperationUpdate, DomainRef: "some.unknown.ref", }) @@ -42,7 +42,7 @@ func TestEvaluateDomainRefValidation_UpdateOperation_Allowed(t *testing.T) { // operations are always admitted. func TestEvaluateDomainRefValidation_DeleteOperation_Allowed(t *testing.T) { decision := webhook.EvaluateDomainRefValidation(webhook.DomainRefValidationRequest{ - Kind: "InfrastructureLineageIndex", + Kind: "LineageRecord", Operation: webhook.OperationDelete, DomainRef: "some.unknown.ref", }) @@ -55,7 +55,7 @@ func TestEvaluateDomainRefValidation_DeleteOperation_Allowed(t *testing.T) { // with an empty domainRef is admitted — the LineageController will populate it. func TestEvaluateDomainRefValidation_EmptyDomainRef_Allowed(t *testing.T) { decision := webhook.EvaluateDomainRefValidation(webhook.DomainRefValidationRequest{ - Kind: "InfrastructureLineageIndex", + Kind: "LineageRecord", Operation: webhook.OperationCreate, DomainRef: "", }) @@ -68,7 +68,7 @@ func TestEvaluateDomainRefValidation_EmptyDomainRef_Allowed(t *testing.T) { // with domainRef="infrastructure.core.ontai.dev" is admitted. func TestEvaluateDomainRefValidation_ValidDomainRef_Allowed(t *testing.T) { decision := webhook.EvaluateDomainRefValidation(webhook.DomainRefValidationRequest{ - Kind: "InfrastructureLineageIndex", + Kind: "LineageRecord", Operation: webhook.OperationCreate, DomainRef: webhook.ValidInfrastructureDomainRef, }) @@ -83,7 +83,7 @@ func TestEvaluateDomainRefValidation_ValidDomainRef_Allowed(t *testing.T) { func TestEvaluateDomainRefValidation_UnknownDomainRef_Denied(t *testing.T) { unknown := "unknown.domain.example.com" decision := webhook.EvaluateDomainRefValidation(webhook.DomainRefValidationRequest{ - Kind: "InfrastructureLineageIndex", + Kind: "LineageRecord", Operation: webhook.OperationCreate, DomainRef: unknown, }) diff --git a/test/unit/webhook/rootbinding_immutability_test.go b/test/unit/webhook/rootbinding_immutability_test.go index d9f7a4c..fde2ef1 100644 --- a/test/unit/webhook/rootbinding_immutability_test.go +++ b/test/unit/webhook/rootbinding_immutability_test.go @@ -11,7 +11,7 @@ import ( "strings" "testing" - "github.com/ontai-dev/seam-core/internal/webhook" + "github.com/ontai-dev/seam/internal/webhook" ) // --- Non-intercepted kinds --- @@ -44,11 +44,11 @@ func TestEvaluateRootBindingImmutability_Deployment_Update_DifferentBinding_Allo // --- CREATE is always allowed --- -// Test R3 — InfrastructureLineageIndex CREATE: always allowed. +// Test R3 — LineageRecord CREATE: always allowed. // rootBinding is authored at creation time — CREATE is the authoritative event. func TestEvaluateRootBindingImmutability_ILI_Create_Allowed(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationCreate, OldRootBindingRaw: nil, NewRootBindingRaw: []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1","rootNamespace":"ont-system","rootUID":"abc","rootObservedGeneration":1}`), @@ -60,10 +60,10 @@ func TestEvaluateRootBindingImmutability_ILI_Create_Allowed(t *testing.T) { // --- DELETE is always allowed --- -// Test R4 — InfrastructureLineageIndex DELETE: always allowed. +// Test R4 — LineageRecord DELETE: always allowed. func TestEvaluateRootBindingImmutability_ILI_Delete_Allowed(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationDelete, OldRootBindingRaw: []byte(`{"rootKind":"TalosCluster"}`), NewRootBindingRaw: nil, @@ -78,7 +78,7 @@ func TestEvaluateRootBindingImmutability_ILI_Delete_Allowed(t *testing.T) { // Test R5 — ILI UPDATE: both rootBinding nil → allowed. func TestEvaluateRootBindingImmutability_ILI_Update_BothNil_Allowed(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: nil, NewRootBindingRaw: nil, @@ -92,7 +92,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_BothNil_Allowed(t *testing.T func TestEvaluateRootBindingImmutability_ILI_Update_IdenticalBinding_Allowed(t *testing.T) { binding := []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1","rootNamespace":"ont-system","rootUID":"abc-123","rootObservedGeneration":1}`) decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: binding, NewRootBindingRaw: binding, @@ -107,7 +107,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_WhitespaceDifference_Allowed old := []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1"}`) newVal := []byte(`{ "rootKind": "TalosCluster", "rootName": "cluster-1" }`) decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: old, NewRootBindingRaw: newVal, @@ -122,7 +122,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_WhitespaceDifference_Allowed // Test R8 — ILI UPDATE: rootBinding nil → present → denied. func TestEvaluateRootBindingImmutability_ILI_Update_NilToPresent_Denied(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: nil, NewRootBindingRaw: []byte(`{"rootKind":"TalosCluster"}`), @@ -138,7 +138,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_NilToPresent_Denied(t *testi // Test R9 — ILI UPDATE: rootBinding present → nil → denied. func TestEvaluateRootBindingImmutability_ILI_Update_PresentToNil_Denied(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: []byte(`{"rootKind":"TalosCluster"}`), NewRootBindingRaw: nil, @@ -153,7 +153,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_RootKindChanged_Denied(t *te old := []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1"}`) newVal := []byte(`{"rootKind":"PackExecution","rootName":"cluster-1"}`) decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: old, NewRootBindingRaw: newVal, @@ -169,7 +169,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_RootUIDChanged_Denied(t *tes old := []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1","rootUID":"original-uid"}`) newVal := []byte(`{"rootKind":"TalosCluster","rootName":"cluster-1","rootUID":"replacement-uid"}`) decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: old, NewRootBindingRaw: newVal, @@ -182,7 +182,7 @@ func TestEvaluateRootBindingImmutability_ILI_Update_RootUIDChanged_Denied(t *tes // Test R12 — JSON "null" value treated as absent (equal to nil) → allowed. func TestEvaluateRootBindingImmutability_Update_NullAndNil_TreatedEqual_Allowed(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: []byte("null"), NewRootBindingRaw: nil, @@ -197,7 +197,7 @@ func TestEvaluateRootBindingImmutability_Update_NullAndNil_TreatedEqual_Allowed( // Test R13 — Denial reason references seam-core-schema.md §3.1. func TestEvaluateRootBindingImmutability_DeniedReason_ReferencesSchema(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: nil, NewRootBindingRaw: []byte(`{"rootKind":"X"}`), @@ -213,7 +213,7 @@ func TestEvaluateRootBindingImmutability_DeniedReason_ReferencesSchema(t *testin // Test R14 — Reason is empty when allowed. func TestEvaluateRootBindingImmutability_AllowedReason_IsEmpty(t *testing.T) { decision := webhook.EvaluateRootBindingImmutability(webhook.RootBindingImmutabilityRequest{ - Kind: webhook.InfrastructureLineageIndexKind, + Kind: webhook.LineageRecordKind, Operation: webhook.OperationUpdate, OldRootBindingRaw: nil, NewRootBindingRaw: nil,