mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
test(01-01): keep bearer regression lint-clean
- avoid React hook-name classification for token fixture helpers
This commit is contained in:
1 parent
8b5e928efa
commit
0c29e6e6b0
1 file changed
+18
-18
@@ -71,7 +71,7 @@ beforeEach(async () => {
|
||||
});
|
||||
|
||||
/** Mint a real `ApiToken` row with the given scopes and arm the Bearer header. */
|
||||
async function useToken(permissions: string[], label = "t"): Promise<string> {
|
||||
async function armToken(permissions: string[], label = "t"): Promise<string> {
|
||||
const raw = `hlk_${label}_${"0".repeat(48)}`;
|
||||
await getPrismaClient().apiToken.create({
|
||||
data: {
|
||||
@@ -85,12 +85,12 @@ async function useToken(permissions: string[], label = "t"): Promise<string> {
|
||||
return raw;
|
||||
}
|
||||
|
||||
async function useExpiringToken(
|
||||
async function armExpiringToken(
|
||||
permissions: string[],
|
||||
label: string,
|
||||
state: { expiresAt?: Date; revoked?: boolean } = {},
|
||||
): Promise<string> {
|
||||
const raw = await useToken(permissions, label);
|
||||
const raw = await armToken(permissions, label);
|
||||
await getPrismaClient().apiToken.update({
|
||||
where: { tokenHash: hashToken(raw) },
|
||||
data: state,
|
||||
@@ -149,7 +149,7 @@ describe("B1 — a narrow token cannot read the full-account export", () => {
|
||||
// The vulnerability in one request: this is the token the settings card
|
||||
// told users to hand to third-party automations, reading every row the
|
||||
// account holds.
|
||||
await useToken(["medication:ingest"], "narrow");
|
||||
await armToken(["medication:ingest"], "narrow");
|
||||
const { GET } = await import("@/app/api/export/full-backup/route");
|
||||
|
||||
const res = await GET(req("/api/export/full-backup"));
|
||||
@@ -166,7 +166,7 @@ describe("B1 — a narrow token cannot read the full-account export", () => {
|
||||
});
|
||||
|
||||
it("refuses the same token on GET /api/labs with 403", async () => {
|
||||
await useToken(["medication:ingest"], "narrow2");
|
||||
await armToken(["medication:ingest"], "narrow2");
|
||||
const { GET } = await import("@/app/api/labs/route");
|
||||
const res = await GET(req("/api/labs"));
|
||||
expect(res.status).toBe(403);
|
||||
@@ -187,7 +187,7 @@ describe("B2/B3 — the medication-ingest surface is unchanged", () => {
|
||||
// resolution — so the fail-closed default cannot reach it. This is the
|
||||
// one flow a fail-closed default could plausibly have broken.
|
||||
const medId = await seedMedication();
|
||||
await useToken(["medication:ingest", `medication:${medId}:ingest`], "pair");
|
||||
await armToken(["medication:ingest", `medication:${medId}:ingest`], "pair");
|
||||
const { POST } = await import("@/app/api/ingest/medication/route");
|
||||
|
||||
const request = new NextRequest(
|
||||
@@ -217,7 +217,7 @@ describe("B2/B3 — the medication-ingest surface is unchanged", () => {
|
||||
// The pre-existing second gate. This is why the retired `/api/tokens`
|
||||
// mint never worked for its advertised purpose.
|
||||
await seedMedication();
|
||||
await useToken(["medication:ingest"], "familyonly");
|
||||
await armToken(["medication:ingest"], "familyonly");
|
||||
const { POST } = await import("@/app/api/ingest/medication/route");
|
||||
|
||||
const request = new NextRequest(
|
||||
@@ -245,14 +245,14 @@ describe("B4 — the native client is not broken", () => {
|
||||
// Login, passkey login-verify and refresh rotation all mint `["*"]`, so
|
||||
// this is exactly the credential the iOS app holds. If this case ever
|
||||
// goes red, the native client is down.
|
||||
await useToken(["*"], "wildcard");
|
||||
await armToken(["*"], "wildcard");
|
||||
const { GET } = await import("@/app/api/export/full-backup/route");
|
||||
const res = await GET(req("/api/export/full-backup"));
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("admits a ['*'] token on a batch ingest route", async () => {
|
||||
await useToken(["*"], "wildcardbatch");
|
||||
await armToken(["*"], "wildcardbatch");
|
||||
const { POST } = await import("@/app/api/measurements/batch/route");
|
||||
const request = new NextRequest(
|
||||
"https://health.example/api/measurements/batch",
|
||||
@@ -285,14 +285,14 @@ describe("B5 — an MCP token is audience-bound to /mcp", () => {
|
||||
it("refuses ['health:read'] on a REST read", async () => {
|
||||
// Narrowing, not breakage: the token's REST read leg was never a feature
|
||||
// an MCP client used. Its audience is now /mcp alone.
|
||||
await useToken(["health:read"], "mcpread");
|
||||
await armToken(["health:read"], "mcpread");
|
||||
const { GET } = await import("@/app/api/export/full-backup/route");
|
||||
const res = await GET(req("/api/export/full-backup"));
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
|
||||
it("still resolves the same token on the /mcp wire", async () => {
|
||||
const raw = await useToken(["health:read"], "mcpread2");
|
||||
const raw = await armToken(["health:read"], "mcpread2");
|
||||
const { resolveMcpAuthContext } = await import("@/lib/mcp/auth");
|
||||
|
||||
const ctx = await resolveMcpAuthContext(raw);
|
||||
@@ -304,7 +304,7 @@ describe("B5 — an MCP token is audience-bound to /mcp", () => {
|
||||
});
|
||||
|
||||
it("grants write on /mcp only for a consented health:write token", async () => {
|
||||
const raw = await useToken(["health:read", "health:write"], "mcprw");
|
||||
const raw = await armToken(["health:read", "health:write"], "mcprw");
|
||||
const { resolveMcpAuthContext } = await import("@/lib/mcp/auth");
|
||||
const ctx = await resolveMcpAuthContext(raw);
|
||||
expect(ctx.canWrite).toBe(true);
|
||||
@@ -325,7 +325,7 @@ describe("B5b — MCP health reads require an explicit read grant", () => {
|
||||
["health:read", ["health:read"]],
|
||||
["wildcard", ["*"]],
|
||||
])("admits %s through capability registration", async (_label, scopes) => {
|
||||
const raw = await useToken(scopes, `mcp-positive-${_label}`);
|
||||
const raw = await armToken(scopes, `mcp-positive-${_label}`);
|
||||
|
||||
const res = await postMcp(raw, "tools/list");
|
||||
|
||||
@@ -345,7 +345,7 @@ describe("B5b — MCP health reads require an explicit read grant", () => {
|
||||
])(
|
||||
"denies a same-user %s token before a real lab read",
|
||||
async (_label, scopes) => {
|
||||
const raw = await useToken(scopes, `mcp-negative-${_label}`);
|
||||
const raw = await armToken(scopes, `mcp-negative-${_label}`);
|
||||
await getPrismaClient().labResult.create({
|
||||
data: {
|
||||
userId: USER_ID,
|
||||
@@ -373,7 +373,7 @@ describe("B5b — MCP health reads require an explicit read grant", () => {
|
||||
],
|
||||
["revoked", { revoked: true }],
|
||||
])("denies an explicit but %s health:read credential", async (_label, state) => {
|
||||
const raw = await useExpiringToken(
|
||||
const raw = await armExpiringToken(
|
||||
["health:read"],
|
||||
`mcp-${_label}`,
|
||||
state,
|
||||
@@ -387,7 +387,7 @@ describe("B5b — MCP health reads require an explicit read grant", () => {
|
||||
|
||||
describe("B6 — a declared scope grants only what it names", () => {
|
||||
it("admits ['fhir:read'] on the FHIR face", async () => {
|
||||
await useToken(["fhir:read"], "fhir");
|
||||
await armToken(["fhir:read"], "fhir");
|
||||
const { GET } = await import("@/app/api/fhir/Observation/route");
|
||||
const res = await GET(req("/api/fhir/Observation"));
|
||||
expect(res.status).toBe(200);
|
||||
@@ -396,7 +396,7 @@ describe("B6 — a declared scope grants only what it names", () => {
|
||||
it("refuses the same token on /api/labs, which declares no scope", async () => {
|
||||
// The whole point of the inversion: holding a scope buys the routes that
|
||||
// name it, and nothing else.
|
||||
await useToken(["fhir:read"], "fhir2");
|
||||
await armToken(["fhir:read"], "fhir2");
|
||||
const { GET } = await import("@/app/api/labs/route");
|
||||
const res = await GET(req("/api/labs"));
|
||||
expect(res.status).toBe(403);
|
||||
@@ -425,7 +425,7 @@ describe("B7 — cookie sessions are untouched", () => {
|
||||
where: { id: USER_ID },
|
||||
data: { role: "ADMIN" },
|
||||
});
|
||||
await useToken(["*"], "adminwild");
|
||||
await armToken(["*"], "adminwild");
|
||||
|
||||
const { requireAdmin, HttpError } = await import("@/lib/api-handler");
|
||||
await expect(requireAdmin()).rejects.toBeInstanceOf(HttpError);
|
||||
|
||||
Reference in new issue
Block a user