internal/checks/corpus.go
Rama main · réplica de lectura del repositorio original.
package checks
import (
"slices"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/sophotechlabs/spinoza/internal/api"
)
type corpus struct {
items []held
byResource map[target][]*unstructured.Unstructured
names map[target]map[string]Named
absent map[target]bool
asked map[target]bool
unread []target
mentioned map[string]int
}
func newCorpus(
items []held, names []Named, absent []string, asked, unread []target, mentions map[string]int,
) *corpus {
out := &corpus{
items: items,
byResource: map[target][]*unstructured.Unstructured{},
names: map[target]map[string]Named{},
absent: map[target]bool{},
}
for _, item := range items {
key := target{group: item.desc.Group, resource: item.desc.Resource}
out.byResource[key] = append(out.byResource[key], item.obj)
}
for _, found := range names {
key := target{group: found.Ref.Group, resource: found.Ref.Resource}
if out.names[key] == nil {
out.names[key] = map[string]Named{}
}
out.names[key][found.Ref.Namespace+"/"+found.Ref.Name] = found
}
out.mentioned = mentionedStrings(items)
for name, seen := range mentions {
out.mentioned[name] += seen
}
requested := map[target]bool{}
for _, want := range asked {
requested[want] = true
}
out.asked = requested
for _, want := range allTargets() {
if !requested[want] {
out.absent[want] = true
}
}
for _, name := range absent {
for _, want := range allTargets() {
if want.resource == name {
out.absent[want] = true
}
}
}
for _, want := range unread {
out.absent[want] = true
}
out.unread = unread
return out
}
func (c *corpus) refused() string {
if len(c.unread) == 0 {
return ""
}
names := make([]string, 0, len(c.unread))
for _, want := range c.unread {
names = append(names, want.resource)
}
slices.Sort(names)
return strings.Join(names, ", ")
}
func mentionedStrings(items []held) map[string]int {
out := map[string]int{}
here := map[string]bool{}
for _, item := range items {
clear(here)
gatherStrings(item.obj.Object, here)
delete(here, item.obj.GetName())
for name := range here {
out[name]++
}
}
return out
}
func gatherStrings(value any, into map[string]bool) {
switch typed := value.(type) {
case string:
into[typed] = true
case map[string]any:
for _, entry := range typed {
gatherStrings(entry, into)
}
case []any:
for _, entry := range typed {
gatherStrings(entry, into)
}
default:
return
}
}
func (c *corpus) mentionedElsewhere(name string) bool {
return c.mentioned[name] > 0
}
func (c *corpus) everything() []held {
return c.items
}
func (c *corpus) read(group, resource string) bool {
key := target{group: group, resource: resource}
if _, held := c.byResource[key]; held {
return true
}
return c.asked[key] && !c.absent[key]
}
func (c *corpus) subjectsOfKind(kind string) []Subject {
out := []Subject{}
for _, item := range c.items {
if item.obj.GetKind() != kind {
continue
}
out = append(out, subjectFromHeld(item))
}
return out
}
func subjectFromHeld(item held) Subject {
origin, managedBy := originOf(item.obj)
return Subject{
Ref: api.ObjectRef{
Group: item.desc.Group,
Version: item.desc.Version,
Resource: item.desc.Resource,
Namespace: item.obj.GetNamespace(),
Name: item.obj.GetName(),
},
Kind: item.obj.GetKind(),
Object: item.obj,
Pod: map[string]any{},
Replicas: 1,
Origin: origin,
ManagedBy: managedBy,
}
}
func (c *corpus) of(group, resource string) []*unstructured.Unstructured {
return c.byResource[target{group: group, resource: resource}]
}
func (c *corpus) has(group, resource string) bool {
return !c.absent[target{group: group, resource: resource}]
}
func (c *corpus) named(group, resource, namespace, name string) bool {
key := target{group: group, resource: resource}
if held, ok := c.names[key]; ok {
_, found := held[namespace+"/"+name]
return found
}
for _, obj := range c.of(group, resource) {
if obj.GetName() != name {
continue
}
if obj.GetNamespace() != namespace {
continue
}
return true
}
return false
}
func (c *corpus) every(resource string) []Named {
out := []Named{}
for key, held := range c.names {
if key.resource != resource {
continue
}
for _, found := range held {
out = append(out, found)
}
}
for key, held := range c.byResource {
if key.resource != resource {
continue
}
for _, obj := range held {
ref := api.ObjectRef{
Group: key.group, Version: "v1", Resource: key.resource,
Namespace: obj.GetNamespace(), Name: obj.GetName(),
}
out = append(out, namedOf(ref, obj))
}
}
slices.SortFunc(out, func(left, right Named) int {
return strings.Compare(left.Ref.Namespace+"/"+left.Ref.Name, right.Ref.Namespace+"/"+right.Ref.Name)
})
return out
}
func (c *corpus) inNamespace(group, resource, namespace string) []*unstructured.Unstructured {
out := []*unstructured.Unstructured{}
for _, obj := range c.of(group, resource) {
if obj.GetNamespace() != namespace {
continue
}
out = append(out, obj)
}
return out
}
func (c *corpus) namespace(name string) *unstructured.Unstructured {
for _, obj := range c.of("", "namespaces") {
if obj.GetName() == name {
return obj
}
}
return nil
}
func missingResources(needs []target, held *corpus) []string {
out := []string{}
for _, want := range needs {
if held.has(want.group, want.resource) {
continue
}
out = append(out, want.resource)
}
return out
}
func skippedBecause(missing []string) string {
return "not audited: this cluster did not report " + strings.Join(missing, " or ")
}