internal/resources/identity_reads_test.go
Rama main · réplica de lectura del repositorio original.
package resources
import (
"errors"
"reflect"
"slices"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
k8stesting "k8s.io/client-go/testing"
"github.com/sophotechlabs/spinoza/internal/api"
"github.com/sophotechlabs/spinoza/internal/auth"
)
func TestSearchReadsOnlyTheNamespacesGrantedToTheCurrentIdentity(t *testing.T) {
for _, tc := range []struct {
name string
allowed []string
want []string
}{
{name: "one namespace", allowed: []string{"payments"}, want: []string{"web-payments"}},
{name: "two namespaces", allowed: []string{"payments", "storefront"}, want: []string{"web-payments", "web-storefront"}},
{name: "no namespaces", allowed: []string{}, want: []string{}},
} {
t.Run(tc.name, func(t *testing.T) {
client := fakeMeta(
t,
meta("", "v1", "Namespace", "", "payments"),
meta("", "v1", "Namespace", "", "storefront"),
meta("", "v1", "Namespace", "", "private"),
meta("", "v1", "Pod", "payments", "web-payments"),
meta("", "v1", "Pod", "storefront", "web-storefront"),
meta("", "v1", "Pod", "private", "web-private"),
)
manager := NewManager(t.Context(), Deps{
Metadata: client, Perms: boundTo(tc.allowed...),
Descriptors: map[string]api.ResourceDescriptor{"/v1/pods": descriptorsFor("/v1/pods")[0]},
})
unscoped := manager.Search(t.Context(), "web")
if len(unscoped.Hits) != 3 {
t.Fatalf("local search = %+v, want all three pods", unscoped)
}
client.ClearActions()
found := manager.Search(alice(t), "web")
if !reflect.DeepEqual(names(found), tc.want) || len(found.Errors) != 0 || found.Truncated {
t.Fatalf("scoped search = %+v, want %v without errors or truncation", found, tc.want)
}
requested := []string{}
for _, action := range client.Actions() {
if action.GetResource().Resource == "pods" {
requested = append(requested, action.GetNamespace())
}
}
slices.Sort(requested)
if !reflect.DeepEqual(requested, tc.allowed) {
t.Fatalf("pod reads = %v, want exactly the admitted namespaces %v", requested, tc.allowed)
}
})
}
}
func TestAScopedSearchKeepsReadableResultsAndNamesTheNamespaceThatRefused(t *testing.T) {
client := fakeMeta(
t,
meta("", "v1", "Namespace", "", "payments"),
meta("", "v1", "Namespace", "", "storefront"),
meta("", "v1", "Pod", "payments", "web-payments"),
)
refused := errors.New("storefront pod listing was forbidden")
client.PrependReactor("list", "pods", func(action k8stesting.Action) (bool, runtime.Object, error) {
if action.GetNamespace() == "storefront" {
return true, nil, refused
}
return false, nil, nil
})
manager := NewManager(t.Context(), Deps{
Metadata: client, Perms: boundTo("payments", "storefront"),
Descriptors: map[string]api.ResourceDescriptor{"/v1/pods": descriptorsFor("/v1/pods")[0]},
})
found := manager.Search(alice(t), "web")
if !reflect.DeepEqual(names(found), []string{"web-payments"}) {
t.Fatalf("hits = %+v, want the readable namespace preserved", found.Hits)
}
if !reflect.DeepEqual(found.Errors, map[string]string{"/v1/pods/storefront": refused.Error()}) {
t.Fatalf("errors = %v, want only the namespace refusal", found.Errors)
}
}
func TestIdentityCountsDoNotReuseOrOverwriteTheLocalCountCache(t *testing.T) {
client := fakeMeta(t, meta("", "v1", "ConfigMap", "payments", "first"))
manager := NewManager(t.Context(), Deps{
Metadata: client,
Descriptors: map[string]api.ResourceDescriptor{"/v1/configmaps": descriptorsFor("/v1/configmaps")[0]},
})
if got := manager.Counts(t.Context()).Counts["/v1/configmaps"]; got != 1 {
t.Fatalf("local count = %d, want 1", got)
}
gvr := schema.GroupVersionResource{Version: "v1", Resource: "configmaps"}
if err := client.Tracker().Create(gvr, meta("", "v1", "ConfigMap", "payments", "second"), "payments"); err != nil {
t.Fatalf("add second map: %v", err)
}
if got := manager.Counts(alice(t)).Counts["/v1/configmaps"]; got != 2 {
t.Fatalf("alice count = %d, want a fresh read of 2", got)
}
if err := client.Tracker().Create(gvr, meta("", "v1", "ConfigMap", "payments", "third"), "payments"); err != nil {
t.Fatalf("add third map: %v", err)
}
bob := auth.WithIdentity(t.Context(), auth.Identity{User: "bob"})
if got := manager.Counts(bob).Counts["/v1/configmaps"]; got != 3 {
t.Fatalf("bob count = %d, want 3 rather than alice's or the local result", got)
}
client.ClearActions()
if got := manager.Counts(t.Context()).Counts["/v1/configmaps"]; got != 1 {
t.Fatalf("local count = %d, want the original local cache", got)
}
if len(client.Actions()) != 0 {
t.Fatalf("local cache was replaced or invalidated: %v", client.Actions())
}
}
func TestARefusedIdentityCountCannotFallBackToTheLocalCount(t *testing.T) {
client := fakeMeta(t, meta("", "v1", "ConfigMap", "payments", "private"))
manager := NewManager(t.Context(), Deps{
Metadata: client,
Descriptors: map[string]api.ResourceDescriptor{"/v1/configmaps": descriptorsFor("/v1/configmaps")[0]},
})
if got := manager.Counts(t.Context()).Counts["/v1/configmaps"]; got != 1 {
t.Fatalf("seed count = %d, want 1", got)
}
refused := errors.New("this identity cannot list configmaps")
client.PrependReactor("list", "configmaps", func(k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, refused
})
found := manager.Counts(alice(t))
if !reflect.DeepEqual(found.Counts, map[string]int{"/v1/configmaps": -1}) {
t.Fatalf("counts = %v, want unknown rather than the privileged count", found.Counts)
}
if !reflect.DeepEqual(found.Errors, map[string]string{"/v1/configmaps": refused.Error()}) {
t.Fatalf("errors = %v, want the refusal", found.Errors)
}
}