mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 13:28:27 +00:00
feat: made e2ee api test indepdent or stateless
This commit is contained in:
@@ -2,8 +2,58 @@ import { SecretType } from "@app/db/schemas";
|
|||||||
import { getUserPrivateKey, seedData1 } from "@app/db/seed-data";
|
import { getUserPrivateKey, seedData1 } from "@app/db/seed-data";
|
||||||
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
|
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 () => {
|
describe("Identity token secret ops", async () => {
|
||||||
let identityToken = "";
|
let identityToken = "";
|
||||||
|
let folderId = "";
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// enable bot
|
// enable bot
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
@@ -90,6 +140,7 @@ describe("Identity token secret ops", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(folderCreate.statusCode).toBe(200);
|
expect(folderCreate.statusCode).toBe(200);
|
||||||
|
folderId = folderCreate.json().folder.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -116,6 +167,20 @@ describe("Identity token secret ops", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(setBotInActive.statusCode).toEqual(200);
|
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 = [
|
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 }) => {
|
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({
|
const getSecByNameRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v3/secrets/raw/${secret.key}`,
|
url: `/api/v3/secrets/raw/${secret.key}`,
|
||||||
@@ -211,9 +280,37 @@ describe("Identity token secret ops", async () => {
|
|||||||
secretValue: secret.value
|
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 }) => {
|
test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => {
|
||||||
|
await createRawSecret({ path, ...secret, token: identityToken });
|
||||||
|
|
||||||
const updateSecretReqBody = {
|
const updateSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
@@ -221,7 +318,6 @@ describe("Identity token secret ops", async () => {
|
|||||||
secretValue: "new-value",
|
secretValue: "new-value",
|
||||||
secretPath: path
|
secretPath: path
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSecRes = await testServer.inject({
|
const updateSecRes = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: `/api/v3/secrets/raw/${secret.key}`,
|
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 }) => {
|
test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => {
|
||||||
|
await createRawSecret({ path, ...secret, token: identityToken });
|
||||||
|
|
||||||
const deletedSecretReqBody = {
|
const deletedSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
@@ -269,13 +369,6 @@ describe("Identity token secret ops", async () => {
|
|||||||
|
|
||||||
// fetch secrets
|
// fetch secrets
|
||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual([]);
|
||||||
expect.arrayContaining([
|
|
||||||
expect.not.objectContaining({
|
|
||||||
key: secret.key,
|
|
||||||
type: SecretType.Shared
|
|
||||||
})
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,40 @@
|
|||||||
import { seedData1 } from "@app/db/seed-data";
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
import { DEFAULT_PROJECT_ENVS } from "@app/db/seeds/3-project";
|
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 () => {
|
describe("Project Environment Router", async () => {
|
||||||
test("Get default environments", async () => {
|
test("Get default environments", async () => {
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
@@ -31,24 +65,10 @@ describe("Project Environment Router", async () => {
|
|||||||
expect(payload.workspace.environments.length).toBe(3);
|
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 () => {
|
test("Create environment", async () => {
|
||||||
const res = await testServer.inject({
|
const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug);
|
||||||
method: "POST",
|
expect(newEnvironment).toEqual(
|
||||||
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(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
name: mockProjectEnv.name,
|
name: mockProjectEnv.name,
|
||||||
@@ -59,14 +79,15 @@ describe("Project Environment Router", async () => {
|
|||||||
updatedAt: expect.any(String)
|
updatedAt: expect.any(String)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
mockProjectEnv.id = payload.environment.id;
|
await deleteProjectEnvironment(newEnvironment.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Update environment", async () => {
|
test("Update environment", async () => {
|
||||||
|
const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug);
|
||||||
const updatedName = { name: "temp#2", slug: "temp2" };
|
const updatedName = { name: "temp#2", slug: "temp2" };
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: `/api/v1/workspace/${seedData1.project.id}/environments/${mockProjectEnv.id}`,
|
url: `/api/v1/workspace/${seedData1.project.id}/environments/${newEnvironment.id}`,
|
||||||
headers: {
|
headers: {
|
||||||
authorization: `Bearer ${jwtAuthToken}`
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
},
|
},
|
||||||
@@ -82,7 +103,7 @@ describe("Project Environment Router", async () => {
|
|||||||
expect(payload).toHaveProperty("environment");
|
expect(payload).toHaveProperty("environment");
|
||||||
expect(payload.environment).toEqual(
|
expect(payload.environment).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: newEnvironment.id,
|
||||||
name: updatedName.name,
|
name: updatedName.name,
|
||||||
slug: updatedName.slug,
|
slug: updatedName.slug,
|
||||||
projectId: seedData1.project.id,
|
projectId: seedData1.project.id,
|
||||||
@@ -91,61 +112,21 @@ describe("Project Environment Router", async () => {
|
|||||||
updatedAt: expect.any(String)
|
updatedAt: expect.any(String)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
mockProjectEnv.name = updatedName.name;
|
await deleteProjectEnvironment(newEnvironment.id);
|
||||||
mockProjectEnv.slug = updatedName.slug;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete environment", async () => {
|
test("Delete environment", async () => {
|
||||||
const res = await testServer.inject({
|
const newEnvironment = await createProjectEnvironment(mockProjectEnv.name, mockProjectEnv.slug);
|
||||||
method: "DELETE",
|
const deletedProjectEnvironment = await deleteProjectEnvironment(newEnvironment.id);
|
||||||
url: `/api/v1/workspace/${seedData1.project.id}/environments/${mockProjectEnv.id}`,
|
expect(deletedProjectEnvironment).toEqual(
|
||||||
headers: {
|
|
||||||
authorization: `Bearer ${jwtAuthToken}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
|
||||||
const payload = JSON.parse(res.payload);
|
|
||||||
expect(payload).toHaveProperty("environment");
|
|
||||||
expect(payload.environment).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: deletedProjectEnvironment.id,
|
||||||
name: mockProjectEnv.name,
|
name: mockProjectEnv.name,
|
||||||
slug: mockProjectEnv.slug,
|
slug: mockProjectEnv.slug,
|
||||||
position: 1,
|
position: 4,
|
||||||
createdAt: expect.any(String),
|
createdAt: expect.any(String),
|
||||||
updatedAt: 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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,40 @@
|
|||||||
import { seedData1 } from "@app/db/seed-data";
|
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 () => {
|
describe("Secret Folder Router", async () => {
|
||||||
test.each([
|
test.each([
|
||||||
{ name: "folder1", path: "/" }, // one in root
|
{ name: "folder1", path: "/" }, // one in root
|
||||||
@@ -7,30 +42,15 @@ describe("Secret Folder Router", async () => {
|
|||||||
{ name: "folder2", path: "/" },
|
{ name: "folder2", path: "/" },
|
||||||
{ name: "folder1", path: "/level1/level2" } // this should not create folder return same thing
|
{ name: "folder1", path: "/level1/level2" } // this should not create folder return same thing
|
||||||
])("Create folder $name in $path", async ({ name, path }) => {
|
])("Create folder $name in $path", async ({ name, path }) => {
|
||||||
const res = await testServer.inject({
|
const createdFolder = await createFolder({ path, name });
|
||||||
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");
|
|
||||||
// check for default environments
|
// check for default environments
|
||||||
expect(payload).toEqual({
|
expect(createdFolder).toEqual(
|
||||||
folder: expect.objectContaining({
|
expect.objectContaining({
|
||||||
name,
|
name,
|
||||||
id: expect.any(String)
|
id: expect.any(String)
|
||||||
})
|
})
|
||||||
});
|
);
|
||||||
|
await deleteFolder({ path, id: createdFolder.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
@@ -43,6 +63,8 @@ describe("Secret Folder Router", async () => {
|
|||||||
},
|
},
|
||||||
{ path: "/level1/level2", expected: { folders: [{ name: "folder1" }], length: 1 } }
|
{ path: "/level1/level2", expected: { folders: [{ name: "folder1" }], length: 1 } }
|
||||||
])("Get folders $path", async ({ path, expected }) => {
|
])("Get folders $path", async ({ path, expected }) => {
|
||||||
|
const newFolders = await Promise.all(expected.folders.map(({ name }) => createFolder({ name, path })));
|
||||||
|
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v1/folders`,
|
url: `/api/v1/folders`,
|
||||||
@@ -59,37 +81,22 @@ describe("Secret Folder Router", async () => {
|
|||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
const payload = JSON.parse(res.payload);
|
const payload = JSON.parse(res.payload);
|
||||||
expect(payload).toHaveProperty("folders");
|
expect(payload).toHaveProperty("folders");
|
||||||
|
expect(payload.folders.length >= expected.folders.length).toBeTruthy();
|
||||||
expect(payload).toEqual({
|
expect(payload).toEqual({
|
||||||
folders: expect.arrayContaining(expected.folders.map((el) => expect.objectContaining(el)))
|
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 () => {
|
test("Update a deep folder", async () => {
|
||||||
const res = await testServer.inject({
|
const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" });
|
||||||
method: "PATCH",
|
expect(newFolder).toEqual(
|
||||||
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(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
name: "folder-updated"
|
name: "folder-updated"
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
toBeDeleteFolderId = payload.folder.id;
|
|
||||||
|
|
||||||
const resUpdatedFolders = await testServer.inject({
|
const resUpdatedFolders = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -108,12 +115,15 @@ describe("Secret Folder Router", async () => {
|
|||||||
const updatedFolderList = JSON.parse(resUpdatedFolders.payload);
|
const updatedFolderList = JSON.parse(resUpdatedFolders.payload);
|
||||||
expect(updatedFolderList).toHaveProperty("folders");
|
expect(updatedFolderList).toHaveProperty("folders");
|
||||||
expect(updatedFolderList.folders[0].name).toEqual("folder-updated");
|
expect(updatedFolderList.folders[0].name).toEqual("folder-updated");
|
||||||
|
|
||||||
|
await deleteFolder({ path: "/level1/level2", id: newFolder.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete a deep folder", async () => {
|
test("Delete a deep folder", async () => {
|
||||||
|
const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" });
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/v1/folders/${toBeDeleteFolderId}`,
|
url: `/api/v1/folders/${newFolder.id}`,
|
||||||
headers: {
|
headers: {
|
||||||
authorization: `Bearer ${jwtAuthToken}`
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,32 +1,57 @@
|
|||||||
import { seedData1 } from "@app/db/seed-data";
|
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([
|
test.each([
|
||||||
{ importEnv: "dev", importPath: "/" }, // one in root
|
{ importEnv: "dev", importPath: "/" }, // one in root
|
||||||
{ importEnv: "staging", importPath: "/" } // then create a deep one creating intermediate ones
|
{ importEnv: "staging", importPath: "/" } // then create a deep one creating intermediate ones
|
||||||
])("Create secret import $importEnv with path $importPath", async ({ importPath, importEnv }) => {
|
])("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
|
// check for default environments
|
||||||
expect(payload.secretImport).toEqual(
|
const payload = await createSecretImport(importPath, importEnv);
|
||||||
|
expect(payload).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
importPath: 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 () => {
|
test("Get secret imports", async () => {
|
||||||
|
const createdImport1 = await createSecretImport("/", "dev");
|
||||||
|
const createdImport2 = await createSecretImport("/", "staging");
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v1/secret-imports`,
|
url: `/api/v1/secret-imports`,
|
||||||
@@ -58,7 +85,6 @@ describe("Secret Folder Router", async () => {
|
|||||||
const payload = JSON.parse(res.payload);
|
const payload = JSON.parse(res.payload);
|
||||||
expect(payload).toHaveProperty("secretImports");
|
expect(payload).toHaveProperty("secretImports");
|
||||||
expect(payload.secretImports.length).toBe(2);
|
expect(payload.secretImports.length).toBe(2);
|
||||||
testSecretImportId = payload.secretImports[0].id;
|
|
||||||
expect(payload.secretImports).toEqual(
|
expect(payload.secretImports).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
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 () => {
|
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",
|
method: "PATCH",
|
||||||
url: `/api/v1/secret-imports/${testSecretImportId}`,
|
url: `/api/v1/secret-imports/${createdImport1.id}`,
|
||||||
headers: {
|
headers: {
|
||||||
authorization: `Bearer ${jwtAuthToken}`
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
},
|
},
|
||||||
@@ -91,8 +122,8 @@ describe("Secret Folder Router", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(updateImportRes.statusCode).toBe(200);
|
||||||
const payload = JSON.parse(res.payload);
|
const payload = JSON.parse(updateImportRes.payload);
|
||||||
expect(payload).toHaveProperty("secretImport");
|
expect(payload).toHaveProperty("secretImport");
|
||||||
// check for default environments
|
// check for default environments
|
||||||
expect(payload.secretImport).toEqual(
|
expect(payload.secretImport).toEqual(
|
||||||
@@ -124,28 +155,19 @@ describe("Secret Folder Router", async () => {
|
|||||||
expect(secretImportsListRes.statusCode).toBe(200);
|
expect(secretImportsListRes.statusCode).toBe(200);
|
||||||
const secretImportList = JSON.parse(secretImportsListRes.payload);
|
const secretImportList = JSON.parse(secretImportsListRes.payload);
|
||||||
expect(secretImportList).toHaveProperty("secretImports");
|
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 () => {
|
test("Delete secret import position", async () => {
|
||||||
const res = await testServer.inject({
|
const createdImport1 = await createSecretImport("/", "dev");
|
||||||
method: "DELETE",
|
const createdImport2 = await createSecretImport("/", "staging");
|
||||||
url: `/api/v1/secret-imports/${testSecretImportId}`,
|
const deletedImport = await deleteSecretImport(createdImport1.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");
|
|
||||||
// check for default environments
|
// check for default environments
|
||||||
expect(payload.secretImport).toEqual(
|
expect(deletedImport).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
importPath: expect.any(String),
|
importPath: expect.any(String),
|
||||||
@@ -175,5 +197,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
expect(secretImportList).toHaveProperty("secretImports");
|
expect(secretImportList).toHaveProperty("secretImports");
|
||||||
expect(secretImportList.secretImports.length).toEqual(1);
|
expect(secretImportList.secretImports.length).toEqual(1);
|
||||||
expect(secretImportList.secretImports[0].position).toEqual(1);
|
expect(secretImportList.secretImports[0].position).toEqual(1);
|
||||||
|
|
||||||
|
await deleteSecretImport(createdImport2.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -83,9 +83,59 @@ const deleteServiceToken = async () => {
|
|||||||
expect(deleteTokenRes.statusCode).toBe(200);
|
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 () => {
|
describe("Service token secret ops", async () => {
|
||||||
let serviceToken = "";
|
let serviceToken = "";
|
||||||
let projectKey = "";
|
let projectKey = "";
|
||||||
|
let folderId = "";
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
serviceToken = await createServiceToken(
|
serviceToken = await createServiceToken(
|
||||||
[{ secretPath: "/**", environment: seedData1.environment.slug }],
|
[{ secretPath: "/**", environment: seedData1.environment.slug }],
|
||||||
@@ -125,10 +175,26 @@ describe("Service token secret ops", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(folderCreate.statusCode).toBe(200);
|
expect(folderCreate.statusCode).toBe(200);
|
||||||
|
folderId = folderCreate.json().folder.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await deleteServiceToken();
|
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 = [
|
const testSecrets = [
|
||||||
@@ -168,25 +234,8 @@ describe("Service token secret ops", async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test.each(testSecrets)("Create secret in path $path", async ({ secret, path }) => {
|
test.each(testSecrets)("Create secret in path $path", async ({ secret, path }) => {
|
||||||
const createSecretReqBody = {
|
const createdSecret = await createSecret({ projectKey, path, ...secret, token: serviceToken });
|
||||||
workspaceId: seedData1.project.id,
|
const decryptedSecret = decryptSecret(projectKey, createdSecret);
|
||||||
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);
|
|
||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
expect(decryptedSecret.value).toEqual(secret.value);
|
expect(decryptedSecret.value).toEqual(secret.value);
|
||||||
expect(decryptedSecret.comment).toEqual(secret.comment);
|
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 }) => {
|
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({
|
const getSecByNameRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v3/secrets/${secret.key}`,
|
url: `/api/v3/secrets/${secret.key}`,
|
||||||
@@ -224,9 +276,12 @@ describe("Service token secret ops", async () => {
|
|||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
expect(decryptedSecret.value).toEqual(secret.value);
|
expect(decryptedSecret.value).toEqual(secret.value);
|
||||||
expect(decryptedSecret.comment).toEqual(secret.comment);
|
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 }) => {
|
test.each(testSecrets)("Update secret in path $path", async ({ path, secret }) => {
|
||||||
|
await createSecret({ projectKey, path, ...secret, token: serviceToken });
|
||||||
const updateSecretReqBody = {
|
const updateSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
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 }) => {
|
test.each(testSecrets)("Delete secret in path $path", async ({ secret, path }) => {
|
||||||
const deleteSecRes = await testServer.inject({
|
await createSecret({ projectKey, path, ...secret, token: serviceToken });
|
||||||
method: "DELETE",
|
const deletedSecret = await deleteSecret({ path, key: secret.key, token: serviceToken });
|
||||||
url: `/api/v3/secrets/${secret.key}`,
|
const decryptedSecret = decryptSecret(projectKey, deletedSecret);
|
||||||
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);
|
|
||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
|
|
||||||
// shared secret deletion should delete personal ones also
|
// shared secret deletion should delete personal ones also
|
||||||
@@ -305,7 +349,7 @@ describe("Service token secret ops", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
...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);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.arrayContaining(
|
expect.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.key}-${i + 1}`,
|
key: `BULK-${secret.key}-${i + 1}`,
|
||||||
type: SecretType.Shared
|
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 }) => {
|
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({
|
const createSharedSecRes = await testServer.inject({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
@@ -340,16 +392,24 @@ describe("Service token secret ops", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(createSharedSecRes.statusCode).toBe(400);
|
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 }) => {
|
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({
|
const updateSharedSecRes = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
@@ -360,7 +420,7 @@ describe("Service token secret ops", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, "update-value", secret.comment)
|
...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);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.arrayContaining(
|
expect.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.key}-${i + 1}`,
|
key: `BULK-${secret.key}-${i + 1}`,
|
||||||
value: "update-value",
|
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 }) => {
|
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",
|
method: "DELETE",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
headers: {
|
headers: {
|
||||||
@@ -396,20 +467,21 @@ describe("Service token secret ops", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`
|
secretName: `BULK-${secret.key}-${i + 1}`
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(updateSharedSecRes.statusCode).toBe(200);
|
|
||||||
const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload);
|
expect(deletedSharedSecRes.statusCode).toBe(200);
|
||||||
expect(updateSharedSecPayload).toHaveProperty("secrets");
|
const deletedSecretPayload = JSON.parse(deletedSharedSecRes.payload);
|
||||||
|
expect(deletedSecretPayload).toHaveProperty("secrets");
|
||||||
|
|
||||||
// bulk ones should exist
|
// bulk ones should exist
|
||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.not.arrayContaining(
|
expect.not.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.value}-${i + 1}`,
|
key: `BULK-${secret.value}-${i + 1}`,
|
||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
|
|||||||
@@ -2,6 +2,54 @@ import { SecretType, TSecrets } from "@app/db/schemas";
|
|||||||
import { decryptSecret, encryptSecret, getUserPrivateKey, seedData1 } from "@app/db/seed-data";
|
import { decryptSecret, encryptSecret, getUserPrivateKey, seedData1 } from "@app/db/seed-data";
|
||||||
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
|
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 () => {
|
describe("Secret V3 Router", async () => {
|
||||||
const testSecrets = [
|
const testSecrets = [
|
||||||
{
|
{
|
||||||
@@ -23,6 +71,7 @@ describe("Secret V3 Router", async () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let projectKey = "";
|
let projectKey = "";
|
||||||
|
let folderId = "";
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const projectKeyRes = await testServer.inject({
|
const projectKeyRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -64,6 +113,23 @@ describe("Secret V3 Router", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(folderCreate.statusCode).toBe(200);
|
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 = "/") => {
|
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 }) => {
|
test.each(testSecrets)("Create secret in path $path", async ({ secret, path }) => {
|
||||||
const createSecretReqBody = {
|
const createdSecret = await createSecret({ projectKey, path, ...secret });
|
||||||
workspaceId: seedData1.project.id,
|
const decryptedSecret = decryptSecret(projectKey, createdSecret);
|
||||||
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);
|
|
||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
expect(decryptedSecret.value).toEqual(secret.value);
|
expect(decryptedSecret.value).toEqual(secret.value);
|
||||||
expect(decryptedSecret.comment).toEqual(secret.comment);
|
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 }) => {
|
test.each(testSecrets)("Get secret by name in path $path", async ({ secret, path }) => {
|
||||||
|
await createSecret({ projectKey, path, ...secret });
|
||||||
|
|
||||||
const getSecByNameRes = await testServer.inject({
|
const getSecByNameRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v3/secrets/${secret.key}`,
|
url: `/api/v3/secrets/${secret.key}`,
|
||||||
@@ -140,6 +192,8 @@ describe("Secret V3 Router", async () => {
|
|||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
expect(decryptedSecret.value).toEqual(secret.value);
|
expect(decryptedSecret.value).toEqual(secret.value);
|
||||||
expect(decryptedSecret.comment).toEqual(secret.comment);
|
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 }) => {
|
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 }) => {
|
test.each(testSecrets)("Creating personal secret in path $path", async ({ secret, path }) => {
|
||||||
|
await createSecret({ projectKey, path, ...secret });
|
||||||
|
|
||||||
const createSecretReqBody = {
|
const createSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
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 }) => {
|
test.each(testSecrets)("Update secret in path $path", async ({ path, secret }) => {
|
||||||
|
await createSecret({ projectKey, path, ...secret });
|
||||||
const updateSecretReqBody = {
|
const updateSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
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 }) => {
|
test.each(testSecrets)("Delete secret in path $path", async ({ secret, path }) => {
|
||||||
const deleteSecRes = await testServer.inject({
|
await createSecret({ projectKey, path, ...secret });
|
||||||
method: "DELETE",
|
const deletedSecret = await deleteSecret({ path, key: secret.key });
|
||||||
url: `/api/v3/secrets/${secret.key}`,
|
const decryptedSecret = decryptSecret(projectKey, deletedSecret);
|
||||||
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);
|
|
||||||
expect(decryptedSecret.key).toEqual(secret.key);
|
expect(decryptedSecret.key).toEqual(secret.key);
|
||||||
|
|
||||||
// shared secret deletion should delete personal ones also
|
// shared secret deletion should delete personal ones also
|
||||||
@@ -274,37 +322,8 @@ describe("Secret V3 Router", async () => {
|
|||||||
test.each(testSecrets)(
|
test.each(testSecrets)(
|
||||||
"Deleting personal one should not delete shared secret in path $path",
|
"Deleting personal one should not delete shared secret in path $path",
|
||||||
async ({ secret, path }) => {
|
async ({ secret, path }) => {
|
||||||
const createSharedSecRes = await testServer.inject({
|
await createSecret({ projectKey, path, ...secret }); // shared one
|
||||||
method: "POST",
|
await createSecret({ projectKey, path, ...secret, type: SecretType.Personal });
|
||||||
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);
|
|
||||||
|
|
||||||
// shared secret deletion should delete personal ones also
|
// shared secret deletion should delete personal ones also
|
||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
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,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
...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);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.arrayContaining(
|
expect.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.key}-${i + 1}`,
|
key: `BULK-${secret.key}-${i + 1}`,
|
||||||
type: SecretType.Shared
|
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 }) => {
|
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({
|
const createSharedSecRes = await testServer.inject({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
@@ -369,16 +393,24 @@ describe("Secret V3 Router", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, secret.value, secret.comment)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(createSharedSecRes.statusCode).toBe(400);
|
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 }) => {
|
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({
|
const updateSharedSecRes = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
@@ -389,7 +421,7 @@ describe("Secret V3 Router", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`,
|
secretName: `BULK-${secret.key}-${i + 1}`,
|
||||||
...encryptSecret(projectKey, `BULK-${secret.key}-${i + 1}`, "update-value", secret.comment)
|
...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);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.arrayContaining(
|
expect.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.key}-${i + 1}`,
|
key: `BULK-${secret.key}-${i + 1}`,
|
||||||
value: "update-value",
|
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 }) => {
|
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",
|
method: "DELETE",
|
||||||
url: `/api/v3/secrets/batch`,
|
url: `/api/v3/secrets/batch`,
|
||||||
headers: {
|
headers: {
|
||||||
@@ -425,20 +464,21 @@ describe("Secret V3 Router", async () => {
|
|||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
secretPath: path,
|
secretPath: path,
|
||||||
secrets: Array.from(Array(10)).map((_e, i) => ({
|
secrets: Array.from(Array(5)).map((_e, i) => ({
|
||||||
secretName: `BULK-${secret.key}-${i + 1}`
|
secretName: `BULK-${secret.key}-${i + 1}`
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(updateSharedSecRes.statusCode).toBe(200);
|
|
||||||
const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload);
|
expect(deletedSharedSecRes.statusCode).toBe(200);
|
||||||
expect(updateSharedSecPayload).toHaveProperty("secrets");
|
const deletedSecretPayload = JSON.parse(deletedSharedSecRes.payload);
|
||||||
|
expect(deletedSecretPayload).toHaveProperty("secrets");
|
||||||
|
|
||||||
// bulk ones should exist
|
// bulk ones should exist
|
||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual(
|
||||||
expect.not.arrayContaining(
|
expect.not.arrayContaining(
|
||||||
Array.from(Array(10)).map((_e, i) =>
|
Array.from(Array(5)).map((_e, i) =>
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: `BULK-${secret.value}-${i + 1}`,
|
key: `BULK-${secret.value}-${i + 1}`,
|
||||||
type: SecretType.Shared
|
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
|
// raw secret endpoints
|
||||||
describe("Secret V3 Raw Router", async () => {
|
describe("Secret V3 Raw Router", async () => {
|
||||||
|
let folderId = "";
|
||||||
const testRawSecrets = [
|
const testRawSecrets = [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
@@ -543,6 +632,7 @@ describe("Secret V3 Raw Router", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(folderCreate.statusCode).toBe(200);
|
expect(folderCreate.statusCode).toBe(200);
|
||||||
|
folderId = folderCreate.json().folder.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -569,6 +659,19 @@ describe("Secret V3 Raw Router", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(setBotInActive.statusCode).toEqual(200);
|
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 = "/") => {
|
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 }) => {
|
test.each(testRawSecrets)("Get secret by name raw in path $path", async ({ secret, path }) => {
|
||||||
|
await createRawSecret({ path, ...secret });
|
||||||
|
|
||||||
const getSecByNameRes = await testServer.inject({
|
const getSecByNameRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/v3/secrets/raw/${secret.key}`,
|
url: `/api/v3/secrets/raw/${secret.key}`,
|
||||||
@@ -645,9 +752,33 @@ describe("Secret V3 Raw Router", async () => {
|
|||||||
secretValue: secret.value
|
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 }) => {
|
test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => {
|
||||||
|
await createRawSecret({ path, ...secret });
|
||||||
|
|
||||||
const updateSecretReqBody = {
|
const updateSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
@@ -655,7 +786,6 @@ describe("Secret V3 Raw Router", async () => {
|
|||||||
secretValue: "new-value",
|
secretValue: "new-value",
|
||||||
secretPath: path
|
secretPath: path
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSecRes = await testServer.inject({
|
const updateSecRes = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: `/api/v3/secrets/raw/${secret.key}`,
|
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 }) => {
|
test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => {
|
||||||
|
await createRawSecret({ path, ...secret });
|
||||||
|
|
||||||
const deletedSecretReqBody = {
|
const deletedSecretReqBody = {
|
||||||
workspaceId: seedData1.project.id,
|
workspaceId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
@@ -703,14 +837,7 @@ describe("Secret V3 Raw Router", async () => {
|
|||||||
|
|
||||||
// fetch secrets
|
// fetch secrets
|
||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual(
|
expect(secrets).toEqual([]);
|
||||||
expect.arrayContaining([
|
|
||||||
expect.not.objectContaining({
|
|
||||||
key: secret.key,
|
|
||||||
type: SecretType.Shared
|
|
||||||
})
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user