Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions api/v1alpha1/tenant_compatibility_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package v1alpha1

import (
"encoding/json"
"os"
"testing"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"sigs.k8s.io/yaml"
)

func TestTenantCompatibility_NetworkPolicyEnforcementReasonIsAdditive(t *testing.T) {
legacy := []byte(`{"apiVersion":"agentic.clawdlinux.org/v1alpha1","kind":"Tenant","metadata":{"name":"legacy"},"spec":{"displayName":"Legacy","namespace":"tenant-a","providers":["openai"]},"status":{"networkPolicyActive":true}}`)
var tenant Tenant
if err := json.Unmarshal(legacy, &tenant); err != nil {
t.Fatalf("unmarshal legacy Tenant: %v", err)
}
if tenant.Status.NetworkPolicyEnforcementReason != "" {
t.Fatalf("legacy enforcement reason = %q, want empty", tenant.Status.NetworkPolicyEnforcementReason)
}

current := []byte(`{"status":{"networkPolicyEnforcementReason":"Enforcing"}}`)
if err := json.Unmarshal(current, &tenant); err != nil {
t.Fatalf("unmarshal current Tenant status: %v", err)
}
if tenant.Status.NetworkPolicyEnforcementReason != "Enforcing" {
t.Fatalf("enforcement reason = %q, want Enforcing", tenant.Status.NetworkPolicyEnforcementReason)
}
}

func TestTenantCompatibility_CRDNetworkPolicyEnforcementReason(t *testing.T) {
data, err := os.ReadFile("../../config/crd/bases/agentic.clawdlinux.org_tenants.yaml")
if err != nil {
t.Fatalf("read Tenant CRD: %v", err)
}
var crd apiextensionsv1.CustomResourceDefinition
if err := yaml.Unmarshal(data, &crd); err != nil {
t.Fatalf("decode Tenant CRD: %v", err)
}
if len(crd.Spec.Versions) != 1 || crd.Spec.Versions[0].Schema == nil || crd.Spec.Versions[0].Schema.OpenAPIV3Schema == nil {
t.Fatal("Tenant CRD has no v1alpha1 OpenAPI schema")
}
statusSchema, ok := crd.Spec.Versions[0].Schema.OpenAPIV3Schema.Properties["status"]
if !ok {
t.Fatal("Tenant CRD schema has no status property")
}
reasonSchema, ok := statusSchema.Properties["networkPolicyEnforcementReason"]
if !ok || reasonSchema.Type != "string" {
t.Fatalf("Tenant CRD status.networkPolicyEnforcementReason = %#v, want string", reasonSchema)
}
}
4 changes: 4 additions & 0 deletions api/v1alpha1/tenant_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ type TenantStatus struct {
// NetworkPolicyActive indicates if network policies are active
NetworkPolicyActive bool `json:"networkPolicyActive,omitempty"`

// NetworkPolicyEnforcementReason describes passive CNI evidence. It does not
// represent an active packet-flow verification.
NetworkPolicyEnforcementReason string `json:"networkPolicyEnforcementReason,omitempty"`

// WorkloadCount is the number of active workloads for this tenant
WorkloadCount int `json:"workloadCount,omitempty"`

Expand Down
4 changes: 4 additions & 0 deletions charts/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ rules:
- configmaps
- secrets
- namespaces
- resourcequotas
- serviceaccounts
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Sandbox node readiness checks
Expand Down Expand Up @@ -64,16 +65,19 @@ rules:
resources:
- agentworkloads
- agentcards
- tenants
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["agentic.clawdlinux.org"]
resources:
- agentworkloads/status
- agentcards/status
- tenants/status
verbs: ["get", "update", "patch"]
- apiGroups: ["agentic.clawdlinux.org"]
resources:
- agentworkloads/finalizers
- agentcards/finalizers
- tenants/finalizers
verbs: ["update"]
# RBAC (for sub-agent service accounts — namespace-scoped only)
- apiGroups: ["rbac.authorization.k8s.io"]
Expand Down
30 changes: 29 additions & 1 deletion charts/tests/operator_rbac_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ suite: operator controller RBAC
templates:
- templates/rbac.yaml
tests:
- it: grants the running controllers access to AgentWorkload and AgentCard resources
- it: grants the running controllers access to AgentWorkload, AgentCard, and Tenant resources
set:
license.key: dev-license
asserts:
Expand All @@ -14,6 +14,32 @@ tests:
resources:
- agentworkloads
- agentcards
- tenants
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
documentIndex: 1
- contains:
path: rules[0].resources
content: resourcequotas
documentIndex: 1
- contains:
path: rules[0].verbs
content: watch
documentIndex: 1
- contains:
path: rules
content:
apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
- rolebindings
verbs:
- get
- list
Expand All @@ -31,6 +57,7 @@ tests:
resources:
- agentworkloads/status
- agentcards/status
- tenants/status
verbs:
- get
- update
Expand All @@ -44,6 +71,7 @@ tests:
resources:
- agentworkloads/finalizers
- agentcards/finalizers
- tenants/finalizers
verbs:
- update
documentIndex: 1
Expand Down
24 changes: 24 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"

"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
Expand All @@ -52,6 +55,7 @@ import (
agenticv1alpha1 "github.com/Clawdlinux/agentic-operator-core/api/v1alpha1"
runtimeadmission "github.com/Clawdlinux/agentic-operator-core/internal/admission"
"github.com/Clawdlinux/agentic-operator-core/internal/controller"
"github.com/Clawdlinux/agentic-operator-core/internal/netpolicy"
"github.com/Clawdlinux/agentic-operator-core/pkg/evaluation"
"github.com/Clawdlinux/agentic-operator-core/pkg/finops"
"github.com/Clawdlinux/agentic-operator-core/pkg/governance"
Expand Down Expand Up @@ -289,6 +293,26 @@ func main() {
os.Exit(1)
}

discoveryClient, err := discovery.NewDiscoveryClientForConfig(ctrl.GetConfigOrDie())
if err != nil {
setupLog.Error(err, "Failed to create discovery client")
os.Exit(1)
}
kubeClient, err := kubernetes.NewForConfig(ctrl.GetConfigOrDie())
if err != nil {
setupLog.Error(err, "Failed to create Kubernetes client")
os.Exit(1)
}
if err := (&controller.TenantReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
DiscoveryClient: netpolicy.DiscoveryClient(discoveryClient),
DaemonSets: kubeClient.AppsV1().DaemonSets(metav1.NamespaceSystem),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Tenant")
os.Exit(1)
}

if os.Getenv("ENABLE_WEBHOOKS") != "false" {
if err := (&agenticv1alpha1.AgentWorkload{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to setup webhook", "webhook", "AgentWorkload")
Expand Down
7 changes: 6 additions & 1 deletion config/crd/bases/agentic.clawdlinux.org_tenants.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.1
controller-gen.kubebuilder.io/version: v0.22.0
name: tenants.agentic.clawdlinux.org
spec:
group: agentic.clawdlinux.org
Expand Down Expand Up @@ -175,6 +175,11 @@ spec:
description: NetworkPolicyActive indicates if network policies are
active
type: boolean
networkPolicyEnforcementReason:
description: |-
NetworkPolicyEnforcementReason describes passive CNI evidence. It does not
represent an active packet-flow verification.
type: string
phase:
description: Phase is the current provisioning phase
enum:
Expand Down
19 changes: 13 additions & 6 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ rules:
- ""
resources:
- resourcequotas
- serviceaccounts
verbs:
- create
- get
- list
- patch
- watch
- apiGroups:
- ""
resources:
Expand All @@ -42,6 +42,15 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- list
- patch
- apiGroups:
- agentic.clawdlinux.org
resources:
Expand Down Expand Up @@ -75,14 +84,11 @@ rules:
- patch
- update
- apiGroups:
- networking.k8s.io
- apps
resources:
- networkpolicies
- daemonsets
verbs:
- create
- get
- list
- patch
- apiGroups:
- rbac.authorization.k8s.io
resources:
Expand All @@ -93,3 +99,4 @@ rules:
- get
- list
- patch
- watch
Loading
Loading