feat: harden self-managed reconciliation
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { KubernetesObjectApi } from "@kubernetes/client-node";
|
||||
import { KubernetesTrustStore } from "../../server/kubernetes-state";
|
||||
import { MemoryTrustStore } from "../../server/trust-store";
|
||||
|
||||
type ConfigMap = {
|
||||
apiVersion: string;
|
||||
kind: string;
|
||||
metadata: {
|
||||
name: string;
|
||||
namespace?: string;
|
||||
labels?: Record<string, string>;
|
||||
};
|
||||
data?: Record<string, string>;
|
||||
};
|
||||
|
||||
class FakeObjects {
|
||||
readonly maps = new Map<string, ConfigMap>();
|
||||
readonly selectors: string[] = [];
|
||||
|
||||
async create(value: ConfigMap): Promise<void> {
|
||||
this.maps.set(value.metadata.name, structuredClone(value));
|
||||
}
|
||||
|
||||
async read(value: ConfigMap): Promise<ConfigMap> {
|
||||
const found = this.maps.get(value.metadata.name);
|
||||
if (!found) throw { code: 404 };
|
||||
return structuredClone(found);
|
||||
}
|
||||
|
||||
async delete(value: ConfigMap): Promise<void> {
|
||||
if (!this.maps.delete(value.metadata.name)) throw { code: 404 };
|
||||
}
|
||||
|
||||
async list(
|
||||
_apiVersion: string,
|
||||
_kind: string,
|
||||
_namespace?: string,
|
||||
_pretty?: string,
|
||||
_exact?: boolean,
|
||||
_exportValue?: boolean,
|
||||
_fieldSelector?: string,
|
||||
labelSelector?: string,
|
||||
): Promise<{ items: ConfigMap[] }> {
|
||||
this.selectors.push(labelSelector ?? "");
|
||||
const labels = Object.fromEntries(
|
||||
(labelSelector ?? "")
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((part) => part.split("=")),
|
||||
);
|
||||
return {
|
||||
items: [...this.maps.values()].filter((item) =>
|
||||
Object.entries(labels).every(
|
||||
([key, value]) => item.metadata.labels?.[key] === value,
|
||||
),
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
describe("namespace trust store", () => {
|
||||
test("rejects invalid namespace and fingerprint", async () => {
|
||||
const store = new MemoryTrustStore();
|
||||
await expect(store.grant("Demo", "a".repeat(64))).rejects.toThrow();
|
||||
await expect(store.grant("a".repeat(64), "a".repeat(64))).rejects.toThrow();
|
||||
await expect(store.grant("demo", "bad")).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("requires explicit registration for each CWD fingerprint", async () => {
|
||||
const store = new MemoryTrustStore();
|
||||
const first = "a".repeat(64);
|
||||
const second = "b".repeat(64);
|
||||
await store.grant("demo", first);
|
||||
expect(await store.has("demo", first)).toBe(true);
|
||||
expect(await store.has("demo", second)).toBe(false);
|
||||
await store.grant("demo", second);
|
||||
expect(await store.list("demo")).toEqual([first, second]);
|
||||
expect(await store.revoke("demo", first)).toBe(true);
|
||||
expect(await store.has("demo", first)).toBe(false);
|
||||
});
|
||||
|
||||
test("persists valid ConfigMap records and ignores malformed payloads", async () => {
|
||||
const objects = new FakeObjects();
|
||||
const store = new KubernetesTrustStore(
|
||||
objects as unknown as KubernetesObjectApi,
|
||||
);
|
||||
const fingerprint = "a".repeat(64);
|
||||
|
||||
await store.grant("demo", fingerprint);
|
||||
const [record] = [...objects.maps.values()];
|
||||
expect(record).toMatchObject({
|
||||
apiVersion: "v1",
|
||||
kind: "ConfigMap",
|
||||
metadata: {
|
||||
namespace: "kuber-system",
|
||||
labels: {
|
||||
"kuber.astrxl.dev/type": "trust",
|
||||
"kuber.astrxl.dev/workspace": "demo",
|
||||
},
|
||||
},
|
||||
data: { payload: JSON.stringify({ project: "demo", fingerprint }) },
|
||||
});
|
||||
expect(record?.metadata.name).toMatch(/^trust-[a-f0-9]{48}$/);
|
||||
expect(await store.list("demo")).toEqual([fingerprint]);
|
||||
expect(objects.selectors).toContain(
|
||||
"kuber.astrxl.dev/type=trust,kuber.astrxl.dev/workspace=demo",
|
||||
);
|
||||
|
||||
objects.maps.set("trust-malformed", {
|
||||
apiVersion: "v1",
|
||||
kind: "ConfigMap",
|
||||
metadata: {
|
||||
name: "trust-malformed",
|
||||
labels: {
|
||||
"kuber.astrxl.dev/type": "trust",
|
||||
"kuber.astrxl.dev/workspace": "demo",
|
||||
},
|
||||
},
|
||||
data: { payload: "not-json" },
|
||||
});
|
||||
objects.maps.set("trust-wrong-project", {
|
||||
apiVersion: "v1",
|
||||
kind: "ConfigMap",
|
||||
metadata: {
|
||||
name: "trust-wrong-project",
|
||||
labels: {
|
||||
"kuber.astrxl.dev/type": "trust",
|
||||
"kuber.astrxl.dev/workspace": "demo",
|
||||
},
|
||||
},
|
||||
data: {
|
||||
payload: JSON.stringify({
|
||||
project: "other",
|
||||
fingerprint: "b".repeat(64),
|
||||
}),
|
||||
},
|
||||
});
|
||||
expect(await store.list("demo")).toEqual([fingerprint]);
|
||||
|
||||
expect(await store.revoke("demo", fingerprint)).toBe(true);
|
||||
expect(await store.has("demo", fingerprint)).toBe(false);
|
||||
expect(await store.revoke("demo", fingerprint)).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user