import { expect, test } from "bun:test"; import type { KubernetesObject } from "@kubernetes/client-node"; import { KubernetesAuditPersistence } from "../../server/kubernetes-state"; import type { AuditEvent } from "../../server/audit-store"; type Obj = KubernetesObject & { data?: Record }; class Objects { values = new Map(); revision = 0; deletes = 0; failReplace = false; failCreate = false; key(v: KubernetesObject) { return `${v.kind}:${v.metadata?.name}`; } async read(v: KubernetesObject) { const found = this.values.get(this.key(v)); if (!found) throw { code: 404 }; return structuredClone(found); } async create(v: Obj) { if (this.failCreate) throw new Error("write failed"); const key = this.key(v); if (this.values.has(key)) throw { code: 409 }; const saved = structuredClone(v); saved.metadata = { ...saved.metadata, resourceVersion: String(++this.revision) }; this.values.set(key, saved); return saved; } async replace(v: Obj) { if (this.failReplace) throw new Error("write failed"); const key = this.key(v), previous = this.values.get(key); if (!previous || previous.metadata?.resourceVersion !== v.metadata?.resourceVersion) throw { code: 409 }; const saved = structuredClone(v); saved.metadata = { ...saved.metadata, resourceVersion: String(++this.revision) }; this.values.set(key, saved); return saved; } async delete(v: KubernetesObject) { this.deletes++; this.values.delete(this.key(v)); } async list(_api: string, _kind: string, _ns: string, _p?: string, _e?: boolean, _x?: boolean, _f?: string, selector?: string) { const [label, expected] = selector?.split("=") ?? []; return { items: [...this.values.values()].filter((v) => !label || v.metadata?.labels?.[label] === expected) }; } api() { return this as never; } } function event(id: number, workspaceId?: string): AuditEvent { return { apiVersion: "kuber.astrxl.dev/v2", kind: "AuditEvent", metadata: { name: `audit-${id}`, uid: `uid-${id}`, resourceVersion: "1", creationTimestamp: new Date(id * 1000).toISOString() }, spec: { actor: { username: "user" }, action: `action-${id}`, outcome: "success", ...(workspaceId && { workspaceId }) } }; } test("Kubernetes audit persistence stores one bounded ring and filters workspaces", async () => { const objects = new Objects(), persistence = new KubernetesAuditPersistence(objects.api()); for (let i = 0; i < 105; i++) await persistence.append(event(i, i % 2 ? "one" : "two")); expect([...objects.values.values()].filter((v) => v.metadata?.labels?.["kuber.astrxl.dev/type"] === "audit-log")).toHaveLength(1); expect(await persistence.list()).toHaveLength(100); expect((await persistence.list("one")).every((v) => v.spec.workspaceId === "one")).toBe(true); expect((await persistence.list())[0]?.spec.action).toBe("action-5"); }); test("conflicting replicas preserve both appended events", async () => { const objects = new Objects(), a = new KubernetesAuditPersistence(objects.api()), b = new KubernetesAuditPersistence(objects.api()); await Promise.all(Array.from({ length: 40 }, (_, i) => (i % 2 ? a : b).append(event(i)))); expect((await a.list()).map((v) => v.metadata.uid)).toHaveLength(40); }); test("legacy records are migrated before deletion and newest 100 survive", async () => { const objects = new Objects(); for (let i = 0; i < 110; i++) await objects.create({ apiVersion: "v1", kind: "ConfigMap", metadata: { name: `audit-${i}`, namespace: "kuber-system", labels: { "kuber.astrxl.dev/type": "audit" } }, data: { payload: JSON.stringify(event(i)) } }); const persistence = new KubernetesAuditPersistence(objects.api()); objects.failCreate = true; await expect(persistence.list()).rejects.toThrow("write failed"); expect(objects.deletes).toBe(0); objects.failCreate = false; const migrated = await persistence.list(); expect(migrated).toHaveLength(100); expect(migrated[0]?.spec.action).toBe("action-10"); expect(objects.values.has("ConfigMap:audit-log")).toBe(true); });