Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import type { LegacyApiKeySimple } from "@toolctrl/db/api-keys.server";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createServicePrincipal } from "../auth.js";
|
||||
import { authorizeApiScope, createStoredApiKeyPrincipal, type ApiScopeResult } from "./scope.js";
|
||||
|
||||
const NOW = new Date("2026-01-15T12:00:00.000Z");
|
||||
|
||||
function buildApiKey(overrides: Partial<LegacyApiKeySimple> = {}): LegacyApiKeySimple {
|
||||
return {
|
||||
id: "api-key-1",
|
||||
alias: "Production key",
|
||||
expires: new Date("2026-02-01T00:00:00.000Z"),
|
||||
tenantId: "tenant-1",
|
||||
active: true,
|
||||
entities: [
|
||||
{
|
||||
entityId: "entity-1",
|
||||
create: true,
|
||||
read: true,
|
||||
update: true,
|
||||
delete: false,
|
||||
},
|
||||
],
|
||||
tenant: {
|
||||
id: "tenant-1",
|
||||
name: "Tenant One",
|
||||
slug: "tenant-one",
|
||||
deactivatedReason: null,
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function authorize(apiKey: LegacyApiKeySimple, overrides: Partial<Parameters<typeof authorizeApiScope>[1]> = {}): ApiScopeResult {
|
||||
return authorizeApiScope(createStoredApiKeyPrincipal(apiKey), {
|
||||
tenantId: "tenant-1",
|
||||
entityId: "entity-1",
|
||||
operation: "read",
|
||||
now: NOW,
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
|
||||
function expectRedactedDeny(result: ApiScopeResult, reason: string) {
|
||||
expect(result).toEqual({
|
||||
allowed: false,
|
||||
principalType: "api-key",
|
||||
reason,
|
||||
code: "FORBIDDEN_API_KEY_SCOPE",
|
||||
});
|
||||
const serialized = JSON.stringify(result);
|
||||
expect(serialized).not.toContain("plaintext-secret");
|
||||
expect(serialized).not.toContain("hash-value");
|
||||
expect(serialized).not.toContain("service-token");
|
||||
}
|
||||
|
||||
describe("authorizeApiScope", () => {
|
||||
test("allows service-token principals for every scoped operation", () => {
|
||||
const principal = createServicePrincipal();
|
||||
|
||||
expect(
|
||||
authorizeApiScope(principal, {
|
||||
tenantId: "other-tenant",
|
||||
entityId: "unknown-entity",
|
||||
operation: "delete",
|
||||
now: NOW,
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: true,
|
||||
principalType: "service-token",
|
||||
});
|
||||
});
|
||||
|
||||
test("allows active stored API keys with matching tenant, entity, and CRUD permission", () => {
|
||||
expect(authorize(buildApiKey(), { operation: "create" })).toEqual({
|
||||
allowed: true,
|
||||
principalType: "api-key",
|
||||
});
|
||||
});
|
||||
|
||||
test("denies inactive stored API keys", () => {
|
||||
expectRedactedDeny(authorize(buildApiKey({ active: false })), "api_key_inactive");
|
||||
});
|
||||
|
||||
test("denies expired stored API keys", () => {
|
||||
expectRedactedDeny(authorize(buildApiKey({ expires: new Date("2026-01-01T00:00:00.000Z") })), "api_key_expired");
|
||||
});
|
||||
|
||||
test("denies stored API keys for deactivated tenants", () => {
|
||||
expectRedactedDeny(
|
||||
authorize(
|
||||
buildApiKey({
|
||||
tenant: {
|
||||
id: "tenant-1",
|
||||
name: "Tenant One",
|
||||
slug: "tenant-one",
|
||||
deactivatedReason: "billing_issue",
|
||||
},
|
||||
}),
|
||||
),
|
||||
"tenant_deactivated",
|
||||
);
|
||||
});
|
||||
|
||||
test("denies stored API keys whose tenant does not match the request tenant", () => {
|
||||
expectRedactedDeny(authorize(buildApiKey(), { tenantId: "tenant-2" }), "tenant_mismatch");
|
||||
expectRedactedDeny(
|
||||
authorize(
|
||||
buildApiKey({
|
||||
tenant: {
|
||||
id: "tenant-2",
|
||||
name: "Tenant Two",
|
||||
slug: "tenant-two",
|
||||
deactivatedReason: null,
|
||||
},
|
||||
}),
|
||||
),
|
||||
"tenant_mismatch",
|
||||
);
|
||||
});
|
||||
|
||||
test("denies stored API keys missing the requested entity permission", () => {
|
||||
expectRedactedDeny(authorize(buildApiKey(), { entityId: "entity-2" }), "entity_permission_missing");
|
||||
});
|
||||
|
||||
test("denies stored API keys missing the requested CRUD operation permission", () => {
|
||||
expectRedactedDeny(authorize(buildApiKey(), { operation: "delete" }), "operation_permission_missing");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user