Ctrl K
ComunidadGuías…

internal/resources/identity_reads_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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)
	}
}