feat: improve API keys and build workflows

This commit is contained in:
2026-10-04 20:05:13 +00:00 Unverified
parent 62f2362a2e
commit e4623efe86
27 changed files with 2080 additions and 235 deletions
+60 -1
View File
@@ -26,7 +26,7 @@ function encode(value: string): string {
}
function secret(
recordType: "user" | "session",
recordType: "user" | "session" | "api-key",
name: string,
values: Record<string, string>,
): StoredSecret {
@@ -111,6 +111,65 @@ function setup(): {
}
describe("KubernetesAuthStore", () => {
test("persists absent expiry, reads finite legacy keys, and rejects malformed expiries", async () => {
const { fake, store } = setup();
await store.putUser({
username: "alice",
passwordHash: "hash",
roles: ["viewer"],
});
const never = {
id: "never-expiring-key-123",
tokenHash: hashToken("never"),
username: "alice",
capabilities: ["kubernetes:read" as const],
};
await store.createApiKey(never);
expect(fake.patches.at(-1)?.stringData).not.toHaveProperty("expiresAt");
expect(await store.getApiKey(never.tokenHash)).toMatchObject(never);
const finite = {
...never,
id: "finite-expiry-key-123",
tokenHash: hashToken("finite"),
expiresAt: "2020-01-01T00:00:00.000Z",
};
await store.createApiKey(finite);
expect(
(await store.listApiKeys("alice")).map((key) => key.expiresAt),
).toEqual([finite.expiresAt, undefined]);
expect(await store.deleteExpiredApiKeys()).toBe(1);
expect(await store.getApiKey(never.tokenHash)).toMatchObject(never);
const active = {
...finite,
id: "active-finite-key-123",
tokenHash: hashToken("active-finite"),
expiresAt: new Date(Date.now() + 60_000).toISOString(),
};
await store.createApiKey(active);
expect(await store.getApiKey(active.tokenHash)).toMatchObject(active);
const name = objectName("api-key", never.tokenHash);
for (const expiry of ["none", "", "2026-09-03"]) {
fake.secrets.set(
name,
secret("api-key", name, {
id: never.id,
tokenHash: never.tokenHash,
username: never.username,
capabilities: JSON.stringify(never.capabilities),
workspace: "",
disabled: "false",
expiresAt: expiry,
}),
);
expect(await store.getApiKey(never.tokenHash)).toBeUndefined();
}
expect(await store.revokeApiKey("bob", finite.id)).toBe(false);
await expect(
store.createApiKey({ ...never, username: "missing" }),
).rejects.toThrow("not active");
await store.updateUser("alice", { disabled: true });
await expect(store.createApiKey(never)).rejects.toThrow("not active");
});
test("validates the session and user from the store on every request", async () => {
const { fake, store } = setup();
const tokenHash = hashToken("fresh");