From 7070a69711a021071e883451b23c83861be69033 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Mon, 19 Feb 2024 20:56:29 +0530 Subject: [PATCH] feat: made e2ee api test indepdent or stateless --- backend/e2e-test/routes/v1/identity.spec.ts | 111 ++++++- .../e2e-test/routes/v1/project-env.spec.ts | 113 +++---- .../e2e-test/routes/v1/secret-folder.spec.ts | 92 +++--- .../e2e-test/routes/v1/secret-import.spec.ts | 116 ++++--- .../e2e-test/routes/v2/service-token.spec.ts | 164 +++++++--- backend/e2e-test/routes/v3/secrets.spec.ts | 299 +++++++++++++----- 6 files changed, 601 insertions(+), 294 deletions(-) diff --git a/backend/e2e-test/routes/v1/identity.spec.ts b/backend/e2e-test/routes/v1/identity.spec.ts index 16ebb444e..9497655ca 100644 --- a/backend/e2e-test/routes/v1/identity.spec.ts +++ b/backend/e2e-test/routes/v1/identity.spec.ts @@ -2,8 +2,58 @@ import { SecretType } from "@app/db/schemas"; import { getUserPrivateKey, seedData1 } from "@app/db/seed-data"; import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto"; +const createRawSecret = async (dto: { + path: string; + key: string; + value: string; + comment: string; + type?: SecretType; + token: string; +}) => { + const createSecretReqBody = { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + type: dto.type || SecretType.Shared, + secretValue: dto.value, + secretComment: dto.comment, + secretPath: dto.path + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v3/secrets/raw/${dto.key}`, + headers: { + authorization: `Bearer ${dto.token}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + const createdSecretPayload = JSON.parse(createSecRes.payload); + expect(createdSecretPayload).toHaveProperty("secret"); + return createdSecretPayload.secret; +}; + +const deleteRawSecret = async (dto: { path: string; key: string; token: string }) => { + const deleteSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v3/secrets/raw/${dto.key}`, + headers: { + authorization: `Bearer ${dto.token}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + secretPath: dto.path + } + }); + expect(deleteSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(deleteSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + return updatedSecretPayload.secret; +}; + describe("Identity token secret ops", async () => { let identityToken = ""; + let folderId = ""; beforeAll(async () => { // enable bot const res = await testServer.inject({ @@ -90,6 +140,7 @@ describe("Identity token secret ops", async () => { } }); expect(folderCreate.statusCode).toBe(200); + folderId = folderCreate.json().folder.id; }); afterAll(async () => { @@ -116,6 +167,20 @@ describe("Identity token secret ops", async () => { } }); expect(setBotInActive.statusCode).toEqual(200); + + const deleteFolder = await testServer.inject({ + method: "DELETE", + url: `/api/v1/folders/${folderId}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/nested1/nested2" + } + }); + expect(deleteFolder.statusCode).toBe(200); }); const testRawSecrets = [ @@ -187,9 +252,13 @@ describe("Identity token secret ops", async () => { }) ]) ); + + await deleteRawSecret({ path, key: secret.key, token: identityToken }); }); test.each(testRawSecrets)("Get secret by name raw in path $path", async ({ secret, path }) => { + await createRawSecret({ path, ...secret, token: identityToken }); + const getSecByNameRes = await testServer.inject({ method: "GET", url: `/api/v3/secrets/raw/${secret.key}`, @@ -211,9 +280,37 @@ describe("Identity token secret ops", async () => { secretValue: secret.value }) ); + + await deleteRawSecret({ path, key: secret.key, token: identityToken }); + }); + + test.each(testRawSecrets)("List secret raw in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => + createRawSecret({ path, token: identityToken, ...secret, key: `BULK-${secret.key}-${i + 1}` }) + ) + ); + + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets.length).toEqual(5); + expect(secrets).toEqual( + expect.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ value: expect.any(String), key: `BULK-${secret.key}-${i + 1}` }) + ) + ) + ); + + await Promise.all( + Array.from(Array(5)).map((_e, i) => + deleteRawSecret({ path, token: identityToken, key: `BULK-${secret.key}-${i + 1}` }) + ) + ); }); test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => { + await createRawSecret({ path, ...secret, token: identityToken }); + const updateSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -221,7 +318,6 @@ describe("Identity token secret ops", async () => { secretValue: "new-value", secretPath: path }; - const updateSecRes = await testServer.inject({ method: "PATCH", url: `/api/v3/secrets/raw/${secret.key}`, @@ -246,9 +342,13 @@ describe("Identity token secret ops", async () => { }) ]) ); + + await deleteRawSecret({ path, key: secret.key, token: identityToken }); }); test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => { + await createRawSecret({ path, ...secret, token: identityToken }); + const deletedSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -269,13 +369,6 @@ describe("Identity token secret ops", async () => { // fetch secrets const secrets = await getSecrets(seedData1.environment.slug, path); - expect(secrets).toEqual( - expect.arrayContaining([ - expect.not.objectContaining({ - key: secret.key, - type: SecretType.Shared - }) - ]) - ); + expect(secrets).toEqual([]); }); }); diff --git a/backend/e2e-test/routes/v1/project-env.spec.ts b/backend/e2e-test/routes/v1/project-env.spec.ts index 936cfa859..ec06d6474 100644 --- a/backend/e2e-test/routes/v1/project-env.spec.ts +++ b/backend/e2e-test/routes/v1/project-env.spec.ts @@ -1,6 +1,40 @@ import { seedData1 } from "@app/db/seed-data"; import { DEFAULT_PROJECT_ENVS } from "@app/db/seeds/3-project"; +const createProjectEnvironment = async (name: string, slug: string) => { + const res = await testServer.inject({ + method: "POST", + url: `/api/v1/workspace/${seedData1.project.id}/environments`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + name, + slug + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("environment"); + return payload.environment; +}; + +const deleteProjectEnvironment = async (envId: string) => { + const res = await testServer.inject({ + method: "DELETE", + url: `/api/v1/workspace/${seedData1.project.id}/environments/${envId}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("environment"); + return payload.environment; +}; + describe("Project Environment Router", async () => { test("Get default environments", async () => { const res = await testServer.inject({ @@ -31,24 +65,10 @@ describe("Project Environment Router", async () => { expect(payload.workspace.environments.length).toBe(3); }); - const mockProjectEnv = { name: "temp", slug: "temp", id: "" }; // id will be filled in create op + const mockProjectEnv = { name: "temp", slug: "temp" }; // id will be filled in create op test("Create environment", async () => { - const res = await testServer.inject({ - method: "POST", - url: `/api/v1/workspace/${seedData1.project.id}/environments`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - name: mockProjectEnv.name, - slug: mockProjectEnv.slug - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("environment"); - expect(payload.environment).toEqual( + const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug); + expect(newEnvironment).toEqual( expect.objectContaining({ id: expect.any(String), name: mockProjectEnv.name, @@ -59,14 +79,15 @@ describe("Project Environment Router", async () => { updatedAt: expect.any(String) }) ); - mockProjectEnv.id = payload.environment.id; + await deleteProjectEnvironment(newEnvironment.id); }); test("Update environment", async () => { + const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug); const updatedName = { name: "temp#2", slug: "temp2" }; const res = await testServer.inject({ method: "PATCH", - url: `/api/v1/workspace/${seedData1.project.id}/environments/${mockProjectEnv.id}`, + url: `/api/v1/workspace/${seedData1.project.id}/environments/${newEnvironment.id}`, headers: { authorization: `Bearer ${jwtAuthToken}` }, @@ -82,7 +103,7 @@ describe("Project Environment Router", async () => { expect(payload).toHaveProperty("environment"); expect(payload.environment).toEqual( expect.objectContaining({ - id: expect.any(String), + id: newEnvironment.id, name: updatedName.name, slug: updatedName.slug, projectId: seedData1.project.id, @@ -91,61 +112,21 @@ describe("Project Environment Router", async () => { updatedAt: expect.any(String) }) ); - mockProjectEnv.name = updatedName.name; - mockProjectEnv.slug = updatedName.slug; + await deleteProjectEnvironment(newEnvironment.id); }); test("Delete environment", async () => { - const res = await testServer.inject({ - method: "DELETE", - url: `/api/v1/workspace/${seedData1.project.id}/environments/${mockProjectEnv.id}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("environment"); - expect(payload.environment).toEqual( + const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug); + const deletedProjectEnvironment = await deleteProjectEnvironment(newEnvironment.id); + expect(deletedProjectEnvironment).toEqual( expect.objectContaining({ - id: expect.any(String), + id: deletedProjectEnvironment.id, name: mockProjectEnv.name, slug: mockProjectEnv.slug, - position: 1, + position: 4, createdAt: expect.any(String), updatedAt: expect.any(String) }) ); }); - - // after all these opreations the list of environment should be still same - test("Default list of environment", async () => { - const res = await testServer.inject({ - method: "GET", - url: `/api/v1/workspace/${seedData1.project.id}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("workspace"); - // check for default environments - expect(payload).toEqual({ - workspace: expect.objectContaining({ - name: seedData1.project.name, - id: seedData1.project.id, - slug: seedData1.project.slug, - environments: expect.arrayContaining([ - expect.objectContaining(DEFAULT_PROJECT_ENVS[0]), - expect.objectContaining(DEFAULT_PROJECT_ENVS[1]), - expect.objectContaining(DEFAULT_PROJECT_ENVS[2]) - ]) - }) - }); - // ensure only two default environments exist - expect(payload.workspace.environments.length).toBe(3); - }); }); diff --git a/backend/e2e-test/routes/v1/secret-folder.spec.ts b/backend/e2e-test/routes/v1/secret-folder.spec.ts index 727c41bbb..4d4bd7ab4 100644 --- a/backend/e2e-test/routes/v1/secret-folder.spec.ts +++ b/backend/e2e-test/routes/v1/secret-folder.spec.ts @@ -1,5 +1,40 @@ import { seedData1 } from "@app/db/seed-data"; +const createFolder = async (dto: { path: string; name: string }) => { + const res = await testServer.inject({ + method: "POST", + url: `/api/v1/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + name: dto.name, + path: dto.path + } + }); + expect(res.statusCode).toBe(200); + return res.json().folder; +}; + +const deleteFolder = async (dto: { path: string; id: string }) => { + const res = await testServer.inject({ + method: "DELETE", + url: `/api/v1/folders/${dto.id}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: dto.path + } + }); + expect(res.statusCode).toBe(200); + return res.json().folder; +}; + describe("Secret Folder Router", async () => { test.each([ { name: "folder1", path: "/" }, // one in root @@ -7,30 +42,15 @@ describe("Secret Folder Router", async () => { { name: "folder2", path: "/" }, { name: "folder1", path: "/level1/level2" } // this should not create folder return same thing ])("Create folder $name in $path", async ({ name, path }) => { - const res = await testServer.inject({ - method: "POST", - url: `/api/v1/folders`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - name, - path - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("folder"); + const createdFolder = await createFolder({ path, name }); // check for default environments - expect(payload).toEqual({ - folder: expect.objectContaining({ + expect(createdFolder).toEqual( + expect.objectContaining({ name, id: expect.any(String) }) - }); + ); + await deleteFolder({ path, id: createdFolder.id }); }); test.each([ @@ -43,6 +63,8 @@ describe("Secret Folder Router", async () => { }, { path: "/level1/level2", expected: { folders: [{ name: "folder1" }], length: 1 } } ])("Get folders $path", async ({ path, expected }) => { + const newFolders = await Promise.all(expected.folders.map(({ name }) => createFolder({ name, path }))); + const res = await testServer.inject({ method: "GET", url: `/api/v1/folders`, @@ -59,37 +81,22 @@ describe("Secret Folder Router", async () => { expect(res.statusCode).toBe(200); const payload = JSON.parse(res.payload); expect(payload).toHaveProperty("folders"); + expect(payload.folders.length >= expected.folders.length).toBeTruthy(); expect(payload).toEqual({ folders: expect.arrayContaining(expected.folders.map((el) => expect.objectContaining(el))) }); + + await Promise.all(newFolders.map(({ id }) => deleteFolder({ path, id }))); }); - let toBeDeleteFolderId = ""; test("Update a deep folder", async () => { - const res = await testServer.inject({ - method: "PATCH", - url: `/api/v1/folders/folder1`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - name: "folder-updated", - path: "/level1/level2" - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("folder"); - expect(payload.folder).toEqual( + const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" }); + expect(newFolder).toEqual( expect.objectContaining({ id: expect.any(String), name: "folder-updated" }) ); - toBeDeleteFolderId = payload.folder.id; const resUpdatedFolders = await testServer.inject({ method: "GET", @@ -108,12 +115,15 @@ describe("Secret Folder Router", async () => { const updatedFolderList = JSON.parse(resUpdatedFolders.payload); expect(updatedFolderList).toHaveProperty("folders"); expect(updatedFolderList.folders[0].name).toEqual("folder-updated"); + + await deleteFolder({ path: "/level1/level2", id: newFolder.id }); }); test("Delete a deep folder", async () => { + const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" }); const res = await testServer.inject({ method: "DELETE", - url: `/api/v1/folders/${toBeDeleteFolderId}`, + url: `/api/v1/folders/${newFolder.id}`, headers: { authorization: `Bearer ${jwtAuthToken}` }, diff --git a/backend/e2e-test/routes/v1/secret-import.spec.ts b/backend/e2e-test/routes/v1/secret-import.spec.ts index f42c033c2..56a8aad51 100644 --- a/backend/e2e-test/routes/v1/secret-import.spec.ts +++ b/backend/e2e-test/routes/v1/secret-import.spec.ts @@ -1,32 +1,57 @@ import { seedData1 } from "@app/db/seed-data"; -describe("Secret Folder Router", async () => { +const createSecretImport = async (importPath: string, importEnv: string) => { + const res = await testServer.inject({ + method: "POST", + url: `/api/v1/secret-imports`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/", + import: { + environment: importEnv, + path: importPath + } + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("secretImport"); + return payload.secretImport; +}; + +const deleteSecretImport = async (id: string) => { + const res = await testServer.inject({ + method: "DELETE", + url: `/api/v1/secret-imports/${id}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/" + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("secretImport"); + return payload.secretImport; +}; + +describe("Secret Import Router", async () => { test.each([ { importEnv: "dev", importPath: "/" }, // one in root { importEnv: "staging", importPath: "/" } // then create a deep one creating intermediate ones ])("Create secret import $importEnv with path $importPath", async ({ importPath, importEnv }) => { - const res = await testServer.inject({ - method: "POST", - url: `/api/v1/secret-imports`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - path: "/", - import: { - environment: importEnv, - path: importPath - } - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("secretImport"); // check for default environments - expect(payload.secretImport).toEqual( + const payload = await createSecretImport(importPath, importEnv); + expect(payload).toEqual( expect.objectContaining({ id: expect.any(String), importPath: expect.any(String), @@ -37,10 +62,12 @@ describe("Secret Folder Router", async () => { }) }) ); + await deleteSecretImport(payload.id); }); - let testSecretImportId = ""; test("Get secret imports", async () => { + const createdImport1 = await createSecretImport("/", "dev"); + const createdImport2 = await createSecretImport("/", "staging"); const res = await testServer.inject({ method: "GET", url: `/api/v1/secret-imports`, @@ -58,7 +85,6 @@ describe("Secret Folder Router", async () => { const payload = JSON.parse(res.payload); expect(payload).toHaveProperty("secretImports"); expect(payload.secretImports.length).toBe(2); - testSecretImportId = payload.secretImports[0].id; expect(payload.secretImports).toEqual( expect.arrayContaining([ expect.objectContaining({ @@ -72,12 +98,17 @@ describe("Secret Folder Router", async () => { }) ]) ); + await deleteSecretImport(createdImport1.id); + await deleteSecretImport(createdImport2.id); }); test("Update secret import position", async () => { - const res = await testServer.inject({ + const createdImport1 = await createSecretImport("/", "dev"); + const createdImport2 = await createSecretImport("/", "staging"); + + const updateImportRes = await testServer.inject({ method: "PATCH", - url: `/api/v1/secret-imports/${testSecretImportId}`, + url: `/api/v1/secret-imports/${createdImport1.id}`, headers: { authorization: `Bearer ${jwtAuthToken}` }, @@ -91,8 +122,8 @@ describe("Secret Folder Router", async () => { } }); - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); + expect(updateImportRes.statusCode).toBe(200); + const payload = JSON.parse(updateImportRes.payload); expect(payload).toHaveProperty("secretImport"); // check for default environments expect(payload.secretImport).toEqual( @@ -124,28 +155,19 @@ describe("Secret Folder Router", async () => { expect(secretImportsListRes.statusCode).toBe(200); const secretImportList = JSON.parse(secretImportsListRes.payload); expect(secretImportList).toHaveProperty("secretImports"); - expect(secretImportList.secretImports[1].id).toEqual(testSecretImportId); + expect(secretImportList.secretImports[1].id).toEqual(createdImport1.id); + expect(secretImportList.secretImports[0].id).toEqual(createdImport2.id); + + await deleteSecretImport(createdImport1.id); + await deleteSecretImport(createdImport2.id); }); test("Delete secret import position", async () => { - const res = await testServer.inject({ - method: "DELETE", - url: `/api/v1/secret-imports/${testSecretImportId}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - path: "/" - } - }); - - expect(res.statusCode).toBe(200); - const payload = JSON.parse(res.payload); - expect(payload).toHaveProperty("secretImport"); + const createdImport1 = await createSecretImport("/", "dev"); + const createdImport2 = await createSecretImport("/", "staging"); + const deletedImport = await deleteSecretImport(createdImport1.id); // check for default environments - expect(payload.secretImport).toEqual( + expect(deletedImport).toEqual( expect.objectContaining({ id: expect.any(String), importPath: expect.any(String), @@ -175,5 +197,7 @@ describe("Secret Folder Router", async () => { expect(secretImportList).toHaveProperty("secretImports"); expect(secretImportList.secretImports.length).toEqual(1); expect(secretImportList.secretImports[0].position).toEqual(1); + + await deleteSecretImport(createdImport2.id); }); }); diff --git a/backend/e2e-test/routes/v2/service-token.spec.ts b/backend/e2e-test/routes/v2/service-token.spec.ts index e9843a2e7..a07eda4b9 100644 --- a/backend/e2e-test/routes/v2/service-token.spec.ts +++ b/backend/e2e-test/routes/v2/service-token.spec.ts @@ -83,9 +83,59 @@ const deleteServiceToken = async () => { expect(deleteTokenRes.statusCode).toBe(200); }; +const createSecret = async (dto: { + projectKey: string; + path: string; + key: string; + value: string; + comment: string; + type?: SecretType; + token: string; +}) => { + const createSecretReqBody = { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + type: dto.type || SecretType.Shared, + secretPath: dto.path, + ...encryptSecret(dto.projectKey, dto.key, dto.value, dto.comment) + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v3/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${dto.token}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + const createdSecretPayload = JSON.parse(createSecRes.payload); + expect(createdSecretPayload).toHaveProperty("secret"); + return createdSecretPayload.secret; +}; + +const deleteSecret = async (dto: { path: string; key: string; token: string }) => { + const deleteSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v3/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${dto.token}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + secretPath: dto.path + } + }); + expect(deleteSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(deleteSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + return updatedSecretPayload.secret; +}; + describe("Service token secret ops", async () => { let serviceToken = ""; let projectKey = ""; + let folderId = ""; beforeAll(async () => { serviceToken = await createServiceToken( [{ secretPath: "/**", environment: seedData1.environment.slug }], @@ -125,10 +175,26 @@ describe("Service token secret ops", async () => { } }); expect(folderCreate.statusCode).toBe(200); + folderId = folderCreate.json().folder.id; }); afterAll(async () => { await deleteServiceToken(); + + // create a deep folder + const deleteFolder = await testServer.inject({ + method: "DELETE", + url: `/api/v1/folders/${folderId}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/nested1/nested2" + } + }); + expect(deleteFolder.statusCode).toBe(200); }); const testSecrets = [ @@ -168,25 +234,8 @@ describe("Service token secret ops", async () => { }; test.each(testSecrets)("Create secret in path $path", async ({ secret, path }) => { - const createSecretReqBody = { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - type: SecretType.Shared, - secretPath: path, - ...encryptSecret(projectKey, secret.key, secret.value, secret.comment) - }; - const createSecRes = await testServer.inject({ - method: "POST", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${serviceToken}` - }, - body: createSecretReqBody - }); - expect(createSecRes.statusCode).toBe(200); - const createdSecretPayload = JSON.parse(createSecRes.payload); - expect(createdSecretPayload).toHaveProperty("secret"); - const decryptedSecret = decryptSecret(projectKey, createdSecretPayload.secret); + const createdSecret = await createSecret({ projectKey, path, ...secret, token: serviceToken }); + const decryptedSecret = decryptSecret(projectKey, createdSecret); expect(decryptedSecret.key).toEqual(secret.key); expect(decryptedSecret.value).toEqual(secret.value); expect(decryptedSecret.comment).toEqual(secret.comment); @@ -202,9 +251,12 @@ describe("Service token secret ops", async () => { }) ]) ); + await deleteSecret({ path, key: secret.key, token: serviceToken }); }); test.each(testSecrets)("Get secret by name in path $path", async ({ secret, path }) => { + await createSecret({ projectKey, path, ...secret, token: serviceToken }); + const getSecByNameRes = await testServer.inject({ method: "GET", url: `/api/v3/secrets/${secret.key}`, @@ -224,9 +276,12 @@ describe("Service token secret ops", async () => { expect(decryptedSecret.key).toEqual(secret.key); expect(decryptedSecret.value).toEqual(secret.value); expect(decryptedSecret.comment).toEqual(secret.comment); + + await deleteSecret({ path, key: secret.key, token: serviceToken }); }); test.each(testSecrets)("Update secret in path $path", async ({ path, secret }) => { + await createSecret({ projectKey, path, ...secret, token: serviceToken }); const updateSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -261,25 +316,14 @@ describe("Service token secret ops", async () => { }) ]) ); + + await deleteSecret({ path, key: secret.key, token: serviceToken }); }); test.each(testSecrets)("Delete secret in path $path", async ({ secret, path }) => { - const deleteSecRes = await testServer.inject({ - method: "DELETE", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${serviceToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - secretPath: path - } - }); - expect(deleteSecRes.statusCode).toBe(200); - const updatedSecretPayload = JSON.parse(deleteSecRes.payload); - expect(updatedSecretPayload).toHaveProperty("secret"); - const decryptedSecret = decryptSecret(projectKey, updatedSecretPayload.secret); + await createSecret({ projectKey, path, ...secret, token: serviceToken }); + const deletedSecret = await deleteSecret({ path, key: secret.key, token: serviceToken }); + const decryptedSecret = decryptSecret(projectKey, deletedSecret); expect(decryptedSecret.key).toEqual(secret.key); // shared secret deletion should delete personal ones also @@ -305,7 +349,7 @@ describe("Service token secret ops", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment) })) @@ -319,7 +363,7 @@ describe("Service token secret ops", async () => { const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.key}-${i + 1}`, type: SecretType.Shared @@ -327,9 +371,17 @@ describe("Service token secret ops", async () => { ) ) ); + + await Promise.all( + Array.from(Array(5)).map((_e, i) => + deleteSecret({ path, token: serviceToken, key: `BULK-${secret.key}-${i + 1}` }) + ) + ); }); test.each(testSecrets)("Bulk create fail on existing secret in path $path", async ({ secret, path }) => { + await createSecret({ projectKey, ...secret, key: `BULK-${secret.key}-1`, path, token: serviceToken }); + const createSharedSecRes = await testServer.inject({ method: "POST", url: `/api/v3/secrets/batch`, @@ -340,16 +392,24 @@ describe("Service token secret ops", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment) })) } }); expect(createSharedSecRes.statusCode).toBe(400); + + await deleteSecret({ path, key: `BULK-${secret.key}-1`, token: serviceToken }); }); test.each(testSecrets)("Bulk update secrets in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => + createSecret({ projectKey, token: serviceToken, ...secret, key: `BULK-${secret.key}-${i + 1}`, path }) + ) + ); + const updateSharedSecRes = await testServer.inject({ method: "PATCH", url: `/api/v3/secrets/batch`, @@ -360,7 +420,7 @@ describe("Service token secret ops", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, "update-value", secret.comment) })) @@ -374,7 +434,7 @@ describe("Service token secret ops", async () => { const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.key}-${i + 1}`, value: "update-value", @@ -383,10 +443,21 @@ describe("Service token secret ops", async () => { ) ) ); + await Promise.all( + Array.from(Array(5)).map((_e, i) => + deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}`, token: serviceToken }) + ) + ); }); test.each(testSecrets)("Bulk delete secrets in path $path", async ({ secret, path }) => { - const updateSharedSecRes = await testServer.inject({ + await Promise.all( + Array.from(Array(5)).map((_e, i) => + createSecret({ projectKey, token: serviceToken, ...secret, key: `BULK-${secret.key}-${i + 1}`, path }) + ) + ); + + const deletedSharedSecRes = await testServer.inject({ method: "DELETE", url: `/api/v3/secrets/batch`, headers: { @@ -396,20 +467,21 @@ describe("Service token secret ops", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}` })) } }); - expect(updateSharedSecRes.statusCode).toBe(200); - const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload); - expect(updateSharedSecPayload).toHaveProperty("secrets"); + + expect(deletedSharedSecRes.statusCode).toBe(200); + const deletedSecretPayload = JSON.parse(deletedSharedSecRes.payload); + expect(deletedSecretPayload).toHaveProperty("secrets"); // bulk ones should exist const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.not.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.value}-${i + 1}`, type: SecretType.Shared diff --git a/backend/e2e-test/routes/v3/secrets.spec.ts b/backend/e2e-test/routes/v3/secrets.spec.ts index 02d239825..b0a8ea04c 100644 --- a/backend/e2e-test/routes/v3/secrets.spec.ts +++ b/backend/e2e-test/routes/v3/secrets.spec.ts @@ -2,6 +2,54 @@ import { SecretType, TSecrets } from "@app/db/schemas"; import { decryptSecret, encryptSecret, getUserPrivateKey, seedData1 } from "@app/db/seed-data"; import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto"; +const createSecret = async (dto: { + projectKey: string; + path: string; + key: string; + value: string; + comment: string; + type?: SecretType; +}) => { + const createSecretReqBody = { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + type: dto.type || SecretType.Shared, + secretPath: dto.path, + ...encryptSecret(dto.projectKey, dto.key, dto.value, dto.comment) + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v3/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + const createdSecretPayload = JSON.parse(createSecRes.payload); + expect(createdSecretPayload).toHaveProperty("secret"); + return createdSecretPayload.secret; +}; + +const deleteSecret = async (dto: { path: string; key: string }) => { + const deleteSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v3/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + secretPath: dto.path + } + }); + expect(deleteSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(deleteSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + return updatedSecretPayload.secret; +}; + describe("Secret V3 Router", async () => { const testSecrets = [ { @@ -23,6 +71,7 @@ describe("Secret V3 Router", async () => { ]; let projectKey = ""; + let folderId = ""; beforeAll(async () => { const projectKeyRes = await testServer.inject({ method: "GET", @@ -64,6 +113,23 @@ describe("Secret V3 Router", async () => { } }); expect(folderCreate.statusCode).toBe(200); + folderId = folderCreate.json().folder.id; + }); + + afterAll(async () => { + const deleteFolder = await testServer.inject({ + method: "DELETE", + url: `/api/v1/folders/${folderId}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/nested1/nested2" + } + }); + expect(deleteFolder.statusCode).toBe(200); }); const getSecrets = async (environment: string, secretPath = "/") => { @@ -84,25 +150,8 @@ describe("Secret V3 Router", async () => { }; test.each(testSecrets)("Create secret in path $path", async ({ secret, path }) => { - const createSecretReqBody = { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - type: SecretType.Shared, - secretPath: path, - ...encryptSecret(projectKey, secret.key, secret.value, secret.comment) - }; - const createSecRes = await testServer.inject({ - method: "POST", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: createSecretReqBody - }); - expect(createSecRes.statusCode).toBe(200); - const createdSecretPayload = JSON.parse(createSecRes.payload); - expect(createdSecretPayload).toHaveProperty("secret"); - const decryptedSecret = decryptSecret(projectKey, createdSecretPayload.secret); + const createdSecret = await createSecret({ projectKey, path, ...secret }); + const decryptedSecret = decryptSecret(projectKey, createdSecret); expect(decryptedSecret.key).toEqual(secret.key); expect(decryptedSecret.value).toEqual(secret.value); expect(decryptedSecret.comment).toEqual(secret.comment); @@ -118,9 +167,12 @@ describe("Secret V3 Router", async () => { }) ]) ); + await deleteSecret({ path, key: secret.key }); }); test.each(testSecrets)("Get secret by name in path $path", async ({ secret, path }) => { + await createSecret({ projectKey, path, ...secret }); + const getSecByNameRes = await testServer.inject({ method: "GET", url: `/api/v3/secrets/${secret.key}`, @@ -140,6 +192,8 @@ describe("Secret V3 Router", async () => { expect(decryptedSecret.key).toEqual(secret.key); expect(decryptedSecret.value).toEqual(secret.value); expect(decryptedSecret.comment).toEqual(secret.comment); + + await deleteSecret({ path, key: secret.key }); }); test.each(testSecrets)("Creating personal secret without shared throw error in path $path", async ({ secret }) => { @@ -164,6 +218,8 @@ describe("Secret V3 Router", async () => { }); test.each(testSecrets)("Creating personal secret in path $path", async ({ secret, path }) => { + await createSecret({ projectKey, path, ...secret }); + const createSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -197,9 +253,12 @@ describe("Secret V3 Router", async () => { }) ]) ); + + await deleteSecret({ path, key: secret.key }); }); test.each(testSecrets)("Update secret in path $path", async ({ path, secret }) => { + await createSecret({ projectKey, path, ...secret }); const updateSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -234,25 +293,14 @@ describe("Secret V3 Router", async () => { }) ]) ); + + await deleteSecret({ path, key: secret.key }); }); test.each(testSecrets)("Delete secret in path $path", async ({ secret, path }) => { - const deleteSecRes = await testServer.inject({ - method: "DELETE", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - secretPath: path - } - }); - expect(deleteSecRes.statusCode).toBe(200); - const updatedSecretPayload = JSON.parse(deleteSecRes.payload); - expect(updatedSecretPayload).toHaveProperty("secret"); - const decryptedSecret = decryptSecret(projectKey, updatedSecretPayload.secret); + await createSecret({ projectKey, path, ...secret }); + const deletedSecret = await deleteSecret({ path, key: secret.key }); + const decryptedSecret = decryptSecret(projectKey, deletedSecret); expect(decryptedSecret.key).toEqual(secret.key); // shared secret deletion should delete personal ones also @@ -274,37 +322,8 @@ describe("Secret V3 Router", async () => { test.each(testSecrets)( "Deleting personal one should not delete shared secret in path $path", async ({ secret, path }) => { - const createSharedSecRes = await testServer.inject({ - method: "POST", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - type: SecretType.Shared, - secretPath: path, - ...encryptSecret(projectKey, secret.key, secret.value, secret.comment) - } - }); - expect(createSharedSecRes.statusCode).toBe(200); - - const createPersonalSecRes = await testServer.inject({ - method: "POST", - url: `/api/v3/secrets/${secret.key}`, - headers: { - authorization: `Bearer ${jwtAuthToken}` - }, - body: { - workspaceId: seedData1.project.id, - environment: seedData1.environment.slug, - secretPath: path, - type: SecretType.Personal, - ...encryptSecret(projectKey, secret.key, secret.value, secret.comment) - } - }); - expect(createPersonalSecRes.statusCode).toBe(200); + await createSecret({ projectKey, path, ...secret }); // shared one + await createSecret({ projectKey, path, ...secret, type: SecretType.Personal }); // shared secret deletion should delete personal ones also const secrets = await getSecrets(seedData1.environment.slug, path); @@ -320,6 +339,7 @@ describe("Secret V3 Router", async () => { }) ]) ); + await deleteSecret({ path, key: secret.key }); } ); @@ -334,7 +354,7 @@ describe("Secret V3 Router", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment) })) @@ -348,7 +368,7 @@ describe("Secret V3 Router", async () => { const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.key}-${i + 1}`, type: SecretType.Shared @@ -356,9 +376,13 @@ describe("Secret V3 Router", async () => { ) ) ); + + await Promise.all(Array.from(Array(5)).map((_e, i) => deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}` }))); }); test.each(testSecrets)("Bulk create fail on existing secret in path $path", async ({ secret, path }) => { + await createSecret({ projectKey, ...secret, key: `BULK-${secret.key}-1`, path }); + const createSharedSecRes = await testServer.inject({ method: "POST", url: `/api/v3/secrets/batch`, @@ -369,16 +393,24 @@ describe("Secret V3 Router", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment) })) } }); expect(createSharedSecRes.statusCode).toBe(400); + + await deleteSecret({ path, key: `BULK-${secret.key}-1` }); }); test.each(testSecrets)("Bulk update secrets in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => + createSecret({ projectKey, ...secret, key: `BULK-${secret.key}-${i + 1}`, path }) + ) + ); + const updateSharedSecRes = await testServer.inject({ method: "PATCH", url: `/api/v3/secrets/batch`, @@ -389,7 +421,7 @@ describe("Secret V3 Router", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}`, ...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, "update-value", secret.comment) })) @@ -403,7 +435,7 @@ describe("Secret V3 Router", async () => { const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.key}-${i + 1}`, value: "update-value", @@ -412,10 +444,17 @@ describe("Secret V3 Router", async () => { ) ) ); + await Promise.all(Array.from(Array(5)).map((_e, i) => deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}` }))); }); test.each(testSecrets)("Bulk delete secrets in path $path", async ({ secret, path }) => { - const updateSharedSecRes = await testServer.inject({ + await Promise.all( + Array.from(Array(5)).map((_e, i) => + createSecret({ projectKey, ...secret, key: `BULK-${secret.key}-${i + 1}`, path }) + ) + ); + + const deletedSharedSecRes = await testServer.inject({ method: "DELETE", url: `/api/v3/secrets/batch`, headers: { @@ -425,20 +464,21 @@ describe("Secret V3 Router", async () => { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, secretPath: path, - secrets: Array.from(Array(10)).map((_e, i) => ({ + secrets: Array.from(Array(5)).map((_e, i) => ({ secretName: `BULK-${secret.key}-${i + 1}` })) } }); - expect(updateSharedSecRes.statusCode).toBe(200); - const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload); - expect(updateSharedSecPayload).toHaveProperty("secrets"); + + expect(deletedSharedSecRes.statusCode).toBe(200); + const deletedSecretPayload = JSON.parse(deletedSharedSecRes.payload); + expect(deletedSecretPayload).toHaveProperty("secrets"); // bulk ones should exist const secrets = await getSecrets(seedData1.environment.slug, path); expect(secrets).toEqual( expect.not.arrayContaining( - Array.from(Array(10)).map((_e, i) => + Array.from(Array(5)).map((_e, i) => expect.objectContaining({ key: `BULK-${secret.value}-${i + 1}`, type: SecretType.Shared @@ -449,8 +489,57 @@ describe("Secret V3 Router", async () => { }); }); +const createRawSecret = async (dto: { + path: string; + key: string; + value: string; + comment: string; + type?: SecretType; +}) => { + const createSecretReqBody = { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + type: dto.type || SecretType.Shared, + secretValue: dto.value, + secretComment: dto.comment, + secretPath: dto.path + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v3/secrets/raw/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + const createdSecretPayload = JSON.parse(createSecRes.payload); + expect(createdSecretPayload).toHaveProperty("secret"); + return createdSecretPayload.secret; +}; + +const deleteRawSecret = async (dto: { path: string; key: string }) => { + const deleteSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v3/secrets/raw/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + secretPath: dto.path + } + }); + expect(deleteSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(deleteSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + return updatedSecretPayload.secret; +}; + // raw secret endpoints describe("Secret V3 Raw Router", async () => { + let folderId = ""; const testRawSecrets = [ { path: "/", @@ -543,6 +632,7 @@ describe("Secret V3 Raw Router", async () => { } }); expect(folderCreate.statusCode).toBe(200); + folderId = folderCreate.json().folder.id; }); afterAll(async () => { @@ -569,6 +659,19 @@ describe("Secret V3 Raw Router", async () => { } }); expect(setBotInActive.statusCode).toEqual(200); + const deleteFolder = await testServer.inject({ + method: "DELETE", + url: `/api/v1/folders/${folderId}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + workspaceId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/nested1/nested2" + } + }); + expect(deleteFolder.statusCode).toBe(200); }); const getSecrets = async (environment: string, secretPath = "/") => { @@ -621,9 +724,13 @@ describe("Secret V3 Raw Router", async () => { }) ]) ); + + await deleteRawSecret({ path, key: secret.key }); }); test.each(testRawSecrets)("Get secret by name raw in path $path", async ({ secret, path }) => { + await createRawSecret({ path, ...secret }); + const getSecByNameRes = await testServer.inject({ method: "GET", url: `/api/v3/secrets/raw/${secret.key}`, @@ -645,9 +752,33 @@ describe("Secret V3 Raw Router", async () => { secretValue: secret.value }) ); + + await deleteRawSecret({ path, key: secret.key }); + }); + + test.each(testRawSecrets)("List secret raw in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => createRawSecret({ path, ...secret, key: `BULK-${secret.key}-${i + 1}` })) + ); + + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets.length).toEqual(5); + expect(secrets).toEqual( + expect.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ value: expect.any(String), key: `BULK-${secret.key}-${i + 1}` }) + ) + ) + ); + + await Promise.all( + Array.from(Array(5)).map((_e, i) => deleteRawSecret({ path, key: `BULK-${secret.key}-${i + 1}` })) + ); }); test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => { + await createRawSecret({ path, ...secret }); + const updateSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -655,7 +786,6 @@ describe("Secret V3 Raw Router", async () => { secretValue: "new-value", secretPath: path }; - const updateSecRes = await testServer.inject({ method: "PATCH", url: `/api/v3/secrets/raw/${secret.key}`, @@ -680,9 +810,13 @@ describe("Secret V3 Raw Router", async () => { }) ]) ); + + await deleteRawSecret({ path, key: secret.key }); }); test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => { + await createRawSecret({ path, ...secret }); + const deletedSecretReqBody = { workspaceId: seedData1.project.id, environment: seedData1.environment.slug, @@ -703,14 +837,7 @@ describe("Secret V3 Raw Router", async () => { // fetch secrets const secrets = await getSecrets(seedData1.environment.slug, path); - expect(secrets).toEqual( - expect.arrayContaining([ - expect.not.objectContaining({ - key: secret.key, - type: SecretType.Shared - }) - ]) - ); + expect(secrets).toEqual([]); }); });