diff --git a/apps/api/src/routes/v1_keys_addPermissions.ts b/apps/api/src/routes/v1_keys_addPermissions.ts index efe080f233..8fc7345f3e 100644 --- a/apps/api/src/routes/v1_keys_addPermissions.ts +++ b/apps/api/src/routes/v1_keys_addPermissions.ts @@ -99,8 +99,12 @@ export const registerV1KeysAddPermissions = (app: App) => const [key, existingPermissions, connectedPermissions] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { eq, and }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, req.keyId)), + where: (table, { eq, and, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, req.keyId), + isNull(table.deletedAt), + ), }), db.primary.query.permissions.findMany({ where: (table, { eq, or, and, inArray }) => diff --git a/apps/api/src/routes/v1_keys_addRoles.ts b/apps/api/src/routes/v1_keys_addRoles.ts index 6d8cd5a8cf..7ee04f5134 100644 --- a/apps/api/src/routes/v1_keys_addRoles.ts +++ b/apps/api/src/routes/v1_keys_addRoles.ts @@ -112,8 +112,12 @@ export const registerV1KeysAddRoles = (app: App) => const [key, existingRoles, connectedRoles] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { eq, and }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, req.keyId)), + where: (table, { eq, and, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, req.keyId), + isNull(table.deletedAt), + ), }), db.primary.query.roles.findMany({ where: (table, { eq, or, and, inArray }) => diff --git a/apps/api/src/routes/v1_keys_removePermissions.ts b/apps/api/src/routes/v1_keys_removePermissions.ts index 4631a24139..900a67d501 100644 --- a/apps/api/src/routes/v1_keys_removePermissions.ts +++ b/apps/api/src/routes/v1_keys_removePermissions.ts @@ -85,8 +85,12 @@ export const registerV1KeysRemovePermissions = (app: App) => const [key, connectedPermissions] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { and, eq }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, req.keyId)), + where: (table, { and, eq, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, req.keyId), + isNull(table.deletedAt), + ), }), await db.primary.query.keysPermissions.findMany({ diff --git a/apps/api/src/routes/v1_keys_removeRoles.ts b/apps/api/src/routes/v1_keys_removeRoles.ts index c0477b790d..e98371b224 100644 --- a/apps/api/src/routes/v1_keys_removeRoles.ts +++ b/apps/api/src/routes/v1_keys_removeRoles.ts @@ -85,8 +85,12 @@ export const registerV1KeysRemoveRoles = (app: App) => const [key, connectedRoles] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { and, eq }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, req.keyId)), + where: (table, { and, eq, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, req.keyId), + isNull(table.deletedAt), + ), }), await db.primary.query.keysRoles.findMany({ diff --git a/apps/api/src/routes/v1_keys_setPermissions.ts b/apps/api/src/routes/v1_keys_setPermissions.ts index b5cbd93af4..21968450f1 100644 --- a/apps/api/src/routes/v1_keys_setPermissions.ts +++ b/apps/api/src/routes/v1_keys_setPermissions.ts @@ -130,8 +130,12 @@ export async function setPermissions( const [key, existingPermissions, connectedPermissions] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { eq, and }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, keyId)), + where: (table, { eq, and, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, keyId), + isNull(table.deletedAt), + ), }), db.primary.query.permissions.findMany({ where: (table, { eq, or, and, inArray }) => diff --git a/apps/api/src/routes/v1_keys_setRoles.ts b/apps/api/src/routes/v1_keys_setRoles.ts index 00064ac103..d1b6c0e832 100644 --- a/apps/api/src/routes/v1_keys_setRoles.ts +++ b/apps/api/src/routes/v1_keys_setRoles.ts @@ -126,8 +126,12 @@ export async function setRoles( const [key, existingRoles, connectedRoles] = await Promise.all([ db.primary.query.keys.findFirst({ - where: (table, { eq, and }) => - and(eq(table.workspaceId, auth.authorizedWorkspaceId), eq(table.id, keyId)), + where: (table, { eq, and, isNull }) => + and( + eq(table.workspaceId, auth.authorizedWorkspaceId), + eq(table.id, keyId), + isNull(table.deletedAt), + ), }), db.primary.query.roles.findMany({ where: (table, { eq, or, and, inArray }) => diff --git a/apps/api/src/routes/v1_keys_updateKey.error.test.ts b/apps/api/src/routes/v1_keys_updateKey.error.test.ts index 396b0564cd..596416cd48 100644 --- a/apps/api/src/routes/v1_keys_updateKey.error.test.ts +++ b/apps/api/src/routes/v1_keys_updateKey.error.test.ts @@ -78,3 +78,40 @@ test("reject invalid refill config", async (t) => { }, }); }); + +test("when the key has been deleted", async (t) => { + const h = await IntegrationHarness.init(t); + const key = { + id: newId("test"), + keyAuthId: h.resources.userKeyAuth.id, + workspaceId: h.resources.userWorkspace.id, + start: "test", + name: "test", + hash: await sha256(new KeyV1({ byteLength: 16 }).toString()), + createdAt: new Date(), + deletedAt: new Date(), + }; + await h.db.primary.insert(schema.keys).values(key); + + const root = await h.createRootKey([`api.${h.resources.userApi.id}.update_key`]); + + const res = await h.post({ + url: "/v1/keys.updateKey", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${root.key}`, + }, + body: { + keyId: key.id, + enabled: false, + }, + }); + expect(res.status).toEqual(404); + expect(res.body).toMatchObject({ + error: { + code: "NOT_FOUND", + docs: "https://unkey.dev/docs/api-reference/errors/code/NOT_FOUND", + message: `key ${key.id} not found`, + }, + }); +}); diff --git a/apps/api/src/routes/v1_keys_updateKey.ts b/apps/api/src/routes/v1_keys_updateKey.ts index 302d3e194e..8329ca93f2 100644 --- a/apps/api/src/routes/v1_keys_updateKey.ts +++ b/apps/api/src/routes/v1_keys_updateKey.ts @@ -282,7 +282,7 @@ export const registerV1KeysUpdate = (app: App) => const { cache, db, usageLimiter, rbac } = c.get("services"); const auth = await rootKeyAuth(c); const key = await db.primary.query.keys.findFirst({ - where: (table, { eq }) => eq(table.id, req.keyId), + where: (table, { eq, and, isNull }) => and(eq(table.id, req.keyId), isNull(table.deletedAt)), with: { keyAuth: { with: { diff --git a/apps/api/src/routes/v1_keys_updateRemaining.ts b/apps/api/src/routes/v1_keys_updateRemaining.ts index 46ebc3d813..c976c53e88 100644 --- a/apps/api/src/routes/v1_keys_updateRemaining.ts +++ b/apps/api/src/routes/v1_keys_updateRemaining.ts @@ -68,7 +68,7 @@ export const registerV1KeysUpdateRemaining = (app: App) => const { cache, db, usageLimiter } = c.get("services"); const key = await db.readonly.query.keys.findFirst({ - where: (table, { eq }) => eq(table.id, req.keyId), + where: (table, { eq, isNull, and }) => and(eq(table.id, req.keyId), isNull(table.deletedAt)), with: { keyAuth: { with: {