mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-02-14 09:59:57 +00:00
* fix(controller): decode old object for delete requests Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * fix(config): remove usergroups default Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * fix(config): remove usergroups default Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * sec(ghsa-2ww6-hf35-mfjm): intercept namespace subresource Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: conflicts Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(api): add rulestatus api Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> --------- Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
159 lines
4.9 KiB
Go
159 lines
4.9 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
|
|
"github.com/projectcapsule/capsule/pkg/api"
|
|
"github.com/projectcapsule/capsule/pkg/api/meta"
|
|
corev1 "k8s.io/api/core/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
var _ = Describe("NamespaceStatus objects", Label("tenant", "rules"), func() {
|
|
ctx := context.Background()
|
|
|
|
// Two tenants, each with one owner (reuse your existing ownerClient/NamespaceCreation helpers)
|
|
tntA := &capsulev1beta2.Tenant{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "nsstatus-a"},
|
|
Spec: capsulev1beta2.TenantSpec{
|
|
Owners: api.OwnerListSpec{
|
|
{
|
|
CoreOwnerSpec: api.CoreOwnerSpec{
|
|
UserSpec: api.UserSpec{Name: "matt", Kind: "User"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
tntB := &capsulev1beta2.Tenant{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "nsstatus-b"},
|
|
Spec: capsulev1beta2.TenantSpec{
|
|
Owners: api.OwnerListSpec{
|
|
{
|
|
CoreOwnerSpec: api.CoreOwnerSpec{
|
|
UserSpec: api.UserSpec{Name: "matt", Kind: "User"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var (
|
|
nsA1 *corev1.Namespace
|
|
nsA2 *corev1.Namespace
|
|
nsB1 *corev1.Namespace
|
|
)
|
|
|
|
JustBeforeEach(func() {
|
|
// Create tenants
|
|
EventuallyCreation(func() error {
|
|
tntA.ResourceVersion = ""
|
|
return k8sClient.Create(ctx, tntA)
|
|
}).Should(Succeed())
|
|
|
|
EventuallyCreation(func() error {
|
|
tntB.ResourceVersion = ""
|
|
return k8sClient.Create(ctx, tntB)
|
|
}).Should(Succeed())
|
|
|
|
// Create namespaces for each tenant using your helper
|
|
nsA1 = NewNamespace("rule-status-ns1", map[string]string{
|
|
meta.TenantLabel: tntA.GetName(),
|
|
})
|
|
nsA2 = NewNamespace("rule-status-ns2", map[string]string{
|
|
meta.TenantLabel: tntA.GetName(),
|
|
})
|
|
nsB1 = NewNamespace("rule-status-ns3", map[string]string{
|
|
meta.TenantLabel: tntB.GetName(),
|
|
})
|
|
|
|
NamespaceCreation(nsA1, tntA.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
|
NamespaceCreation(nsA2, tntA.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
|
NamespaceCreation(nsB1, tntB.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
|
|
|
// Wait until tenants list their namespaces (optional but makes debugging easier)
|
|
TenantNamespaceList(tntA, defaultTimeoutInterval).Should(ContainElements(nsA1.GetName(), nsA2.GetName()))
|
|
TenantNamespaceList(tntB, defaultTimeoutInterval).Should(ContainElement(nsB1.GetName()))
|
|
})
|
|
|
|
JustAfterEach(func() {
|
|
// Best-effort cleanup namespaces first (your env may already handle this)
|
|
for _, n := range []*corev1.Namespace{nsA1, nsA2, nsB1} {
|
|
if n == nil {
|
|
continue
|
|
}
|
|
_ = k8sClient.Delete(ctx, n)
|
|
}
|
|
|
|
// Delete tenants
|
|
if tntA != nil {
|
|
_ = k8sClient.Delete(ctx, tntA)
|
|
}
|
|
if tntB != nil {
|
|
_ = k8sClient.Delete(ctx, tntB)
|
|
}
|
|
})
|
|
|
|
// --- Helpers ---
|
|
|
|
expectNamespaceStatusFor := func(ns *corev1.Namespace, tenantName string) {
|
|
By(fmt.Sprintf("verifying NamespaceStatus for namespace %q (tenant=%q)", ns.Name, tenantName))
|
|
|
|
Eventually(func(g Gomega) {
|
|
// Re-read namespace to get UID reliably (in case local object is stale)
|
|
curNS := &corev1.Namespace{}
|
|
g.Expect(k8sClient.Get(ctx, client.ObjectKey{Name: ns.Name}, curNS)).To(Succeed())
|
|
|
|
nsStatus := &capsulev1beta2.RuleStatus{}
|
|
g.Expect(k8sClient.Get(ctx, client.ObjectKey{Name: meta.NameForManagedRuleStatus(), Namespace: ns.Name}, nsStatus)).To(Succeed())
|
|
|
|
// 2) OwnerReference must point to the Namespace and be controller owner
|
|
g.Expect(nsStatus.OwnerReferences).NotTo(BeEmpty())
|
|
|
|
var found bool
|
|
for _, or := range nsStatus.OwnerReferences {
|
|
if or.APIVersion == "v1" &&
|
|
or.Kind == "Namespace" &&
|
|
or.Name == curNS.Name &&
|
|
or.UID == curNS.UID {
|
|
|
|
found = true
|
|
|
|
break
|
|
}
|
|
}
|
|
g.Expect(found).To(BeTrue(), "expected NamespaceStatus to have Namespace controller OwnerReference")
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
|
}
|
|
|
|
It("creates one NamespaceStatus per namespace, with correct Status.Tenant and Namespace controller OwnerReference", func() {
|
|
expectNamespaceStatusFor(nsA1, tntA.Name)
|
|
expectNamespaceStatusFor(nsA2, tntA.Name)
|
|
expectNamespaceStatusFor(nsB1, tntB.Name)
|
|
})
|
|
|
|
It("removes NamespaceStatus when the Namespace is deleted (ownerReference GC)", func() {
|
|
// Ensure it exists first
|
|
expectNamespaceStatusFor(nsA1, tntA.Name)
|
|
|
|
// Delete namespace
|
|
Expect(k8sClient.Delete(ctx, nsA1)).To(Succeed())
|
|
|
|
// Namespace deletion can take time; once it's gone, the status should be GC'd
|
|
Eventually(func() bool {
|
|
// confirm namespace gone or terminating; either way, check status disappears eventually
|
|
nsStatus := &capsulev1beta2.RuleStatus{}
|
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.NameForManagedRuleStatus(), Namespace: nsA1.Name}, nsStatus)
|
|
return apierrors.IsNotFound(err)
|
|
}, defaultTimeoutInterval, defaultPollInterval).Should(BeTrue())
|
|
})
|
|
})
|