mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 04:26:11 +00:00
feat: added test for checkings secrets from import via replication and non replicaiton
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
|
|
||||||
|
const createPolicy = async (dto: { name: string; secretPath: string; approvers: string[]; approvals: number }) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v1/secret-approvals`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
name: dto.name,
|
||||||
|
secretPath: dto.secretPath,
|
||||||
|
approvers: dto.approvers,
|
||||||
|
approvals: dto.approvals
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
return res.json().approval;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("Secret approval policy router", async () => {
|
||||||
|
test("Create policy", async () => {
|
||||||
|
const policy = await createPolicy({
|
||||||
|
secretPath: "/",
|
||||||
|
approvals: 1,
|
||||||
|
approvers: [seedData1.id],
|
||||||
|
name: "test-policy"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(policy.name).toBe("test-policy");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,56 +1,23 @@
|
|||||||
|
import { createFolder, deleteFolder } from "e2e-test/testUtils/folders";
|
||||||
|
import { createSecretImport, deleteSecretImport } from "e2e-test/testUtils/secret-imports";
|
||||||
|
import { createSecretV2, deleteSecretV2, getSecretByNameV2, getSecretsV2 } from "e2e-test/testUtils/secrets";
|
||||||
|
|
||||||
import { seedData1 } from "@app/db/seed-data";
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
|
|
||||||
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 () => {
|
describe("Secret Import Router", async () => {
|
||||||
test.each([
|
test.each([
|
||||||
{ importEnv: "prod", importPath: "/" }, // one in root
|
{ importEnv: "prod", 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 }) => {
|
||||||
// check for default environments
|
// check for default environments
|
||||||
const payload = await createSecretImport(importPath, importEnv);
|
const payload = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath,
|
||||||
|
importEnv
|
||||||
|
});
|
||||||
expect(payload).toEqual(
|
expect(payload).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
@@ -62,12 +29,32 @@ describe("Secret Import Router", async () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await deleteSecretImport(payload.id);
|
await deleteSecretImport({
|
||||||
|
id: payload.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Get secret imports", async () => {
|
test("Get secret imports", async () => {
|
||||||
const createdImport1 = await createSecretImport("/", "prod");
|
const createdImport1 = await createSecretImport({
|
||||||
const createdImport2 = await createSecretImport("/", "staging");
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: "/",
|
||||||
|
importEnv: "prod"
|
||||||
|
});
|
||||||
|
const createdImport2 = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: "/",
|
||||||
|
importEnv: "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`,
|
||||||
@@ -98,16 +85,42 @@ describe("Secret Import Router", async () => {
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
await deleteSecretImport(createdImport1.id);
|
await deleteSecretImport({
|
||||||
await deleteSecretImport(createdImport2.id);
|
id: createdImport1.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: createdImport2.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Update secret import position", async () => {
|
test("Update secret import position", async () => {
|
||||||
const prodImportDetails = { path: "/", envSlug: "prod" };
|
const prodImportDetails = { path: "/", envSlug: "prod" };
|
||||||
const stagingImportDetails = { path: "/", envSlug: "staging" };
|
const stagingImportDetails = { path: "/", envSlug: "staging" };
|
||||||
|
|
||||||
const createdImport1 = await createSecretImport(prodImportDetails.path, prodImportDetails.envSlug);
|
const createdImport1 = await createSecretImport({
|
||||||
const createdImport2 = await createSecretImport(stagingImportDetails.path, stagingImportDetails.envSlug);
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: prodImportDetails.path,
|
||||||
|
importEnv: prodImportDetails.envSlug
|
||||||
|
});
|
||||||
|
const createdImport2 = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: stagingImportDetails.path,
|
||||||
|
importEnv: stagingImportDetails.envSlug
|
||||||
|
});
|
||||||
|
|
||||||
const updateImportRes = await testServer.inject({
|
const updateImportRes = await testServer.inject({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
@@ -161,14 +174,47 @@ describe("Secret Import Router", async () => {
|
|||||||
expect(secretImportList.secretImports[1].id).toEqual(createdImport1.id);
|
expect(secretImportList.secretImports[1].id).toEqual(createdImport1.id);
|
||||||
expect(secretImportList.secretImports[0].id).toEqual(createdImport2.id);
|
expect(secretImportList.secretImports[0].id).toEqual(createdImport2.id);
|
||||||
|
|
||||||
await deleteSecretImport(createdImport1.id);
|
await deleteSecretImport({
|
||||||
await deleteSecretImport(createdImport2.id);
|
id: createdImport1.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: createdImport2.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete secret import position", async () => {
|
test("Delete secret import position", async () => {
|
||||||
const createdImport1 = await createSecretImport("/", "prod");
|
const createdImport1 = await createSecretImport({
|
||||||
const createdImport2 = await createSecretImport("/", "staging");
|
authToken: jwtAuthToken,
|
||||||
const deletedImport = await deleteSecretImport(createdImport1.id);
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: "/",
|
||||||
|
importEnv: "prod"
|
||||||
|
});
|
||||||
|
const createdImport2 = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
importPath: "/",
|
||||||
|
importEnv: "staging"
|
||||||
|
});
|
||||||
|
const deletedImport = await deleteSecretImport({
|
||||||
|
id: createdImport1.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
// check for default environments
|
// check for default environments
|
||||||
expect(deletedImport).toEqual(
|
expect(deletedImport).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -201,6 +247,391 @@ describe("Secret Import Router", async () => {
|
|||||||
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);
|
await deleteSecretImport({
|
||||||
|
id: createdImport2.id,
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// dev <- stage <- prod
|
||||||
|
describe.each([{ path: "/" }, { path: "/deep" }])(
|
||||||
|
"Secret import waterfall pattern testing - %path",
|
||||||
|
({ path: testSuitePath }) => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
let prodFolder: { id: string };
|
||||||
|
let stagingFolder: { id: string };
|
||||||
|
let devFolder: { id: string };
|
||||||
|
|
||||||
|
if (testSuitePath !== "/") {
|
||||||
|
prodFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
stagingFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
devFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const devImportFromStage = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "staging"
|
||||||
|
});
|
||||||
|
|
||||||
|
const stageImportFromProd = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "prod"
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: stageImportFromProd.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromStage.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prodFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: prodFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "prod"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stagingFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: stagingFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: devFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check one level imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY",
|
||||||
|
value: "stage-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("STAGING_KEY");
|
||||||
|
expect(secret.secretValue).toBe("stage-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "STAGING_KEY",
|
||||||
|
secretValue: "stage-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check two level imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY",
|
||||||
|
value: "prod-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("PROD_KEY");
|
||||||
|
expect(secret.secretValue).toBe("prod-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "PROD_KEY",
|
||||||
|
secretValue: "prod-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// dev <- stage, dev <- prod
|
||||||
|
describe.each([{ path: "/" }, { path: "/deep" }])(
|
||||||
|
"Secret import 1-N pattern testing - %path",
|
||||||
|
({ path: testSuitePath }) => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
let prodFolder: { id: string };
|
||||||
|
let stagingFolder: { id: string };
|
||||||
|
let devFolder: { id: string };
|
||||||
|
|
||||||
|
if (testSuitePath !== "/") {
|
||||||
|
prodFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
stagingFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
devFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const devImportFromStage = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "staging"
|
||||||
|
});
|
||||||
|
|
||||||
|
const devImportFromProd = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "prod"
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromProd.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromStage.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prodFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: prodFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "prod"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stagingFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: stagingFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: devFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY",
|
||||||
|
value: "stage-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY",
|
||||||
|
value: "prod-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("STAGING_KEY");
|
||||||
|
expect(secret.secretValue).toBe("stage-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "STAGING_KEY",
|
||||||
|
secretValue: "stage-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "PROD_KEY",
|
||||||
|
secretValue: "prod-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|||||||
@@ -0,0 +1,405 @@
|
|||||||
|
import { createFolder, deleteFolder } from "e2e-test/testUtils/folders";
|
||||||
|
import { createSecretImport, deleteSecretImport } from "e2e-test/testUtils/secret-imports";
|
||||||
|
import { createSecretV2, deleteSecretV2, getSecretByNameV2, getSecretsV2 } from "e2e-test/testUtils/secrets";
|
||||||
|
|
||||||
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
|
|
||||||
|
// dev <- stage <- prod
|
||||||
|
describe.each([{ path: "/" }, { path: "/deep" }])(
|
||||||
|
"Secret replication waterfall pattern testing - %path",
|
||||||
|
({ path: testSuitePath }) => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
let prodFolder: { id: string };
|
||||||
|
let stagingFolder: { id: string };
|
||||||
|
let devFolder: { id: string };
|
||||||
|
|
||||||
|
if (testSuitePath !== "/") {
|
||||||
|
prodFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
stagingFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
devFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const devImportFromStage = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "staging",
|
||||||
|
isReplication: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const stageImportFromProd = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "prod",
|
||||||
|
isReplication: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: stageImportFromProd.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromStage.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prodFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: prodFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "prod"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stagingFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: stagingFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: devFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check one level imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY",
|
||||||
|
value: "stage-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for 5 second for replication to finish
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 5000); // time to breathe for db
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("STAGING_KEY");
|
||||||
|
expect(secret.secretValue).toBe("stage-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "STAGING_KEY",
|
||||||
|
secretValue: "stage-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check two level imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY",
|
||||||
|
value: "prod-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for 5 second for replication to finish
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 5000); // time to breathe for db
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("PROD_KEY");
|
||||||
|
expect(secret.secretValue).toBe("prod-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "PROD_KEY",
|
||||||
|
secretValue: "prod-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ timeout: 30000 }
|
||||||
|
);
|
||||||
|
|
||||||
|
// dev <- stage, dev <- prod
|
||||||
|
describe.each([{ path: "/" }, { path: "/deep" }])(
|
||||||
|
"Secret replication 1-N pattern testing - %path",
|
||||||
|
({ path: testSuitePath }) => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
let prodFolder: { id: string };
|
||||||
|
let stagingFolder: { id: string };
|
||||||
|
let devFolder: { id: string };
|
||||||
|
|
||||||
|
if (testSuitePath !== "/") {
|
||||||
|
prodFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
stagingFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
devFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const devImportFromStage = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "staging",
|
||||||
|
isReplication: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const devImportFromProd = await createSecretImport({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
importPath: testSuitePath,
|
||||||
|
importEnv: "prod",
|
||||||
|
isReplication: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromProd.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteSecretImport({
|
||||||
|
id: devImportFromStage.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prodFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: prodFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "prod"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stagingFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: stagingFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: "staging"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devFolder) {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: devFolder.id,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
environmentSlug: seedData1.environment.slug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Check imported secret exist", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY",
|
||||||
|
value: "stage-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY",
|
||||||
|
value: "prod-value"
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for 5 second for replication to finish
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 5000); // time to breathe for db
|
||||||
|
});
|
||||||
|
|
||||||
|
const secret = await getSecretByNameV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(secret.secretKey).toBe("STAGING_KEY");
|
||||||
|
expect(secret.secretValue).toBe("stage-value");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.imports).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "STAGING_KEY",
|
||||||
|
secretValue: "stage-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
secrets: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "PROD_KEY",
|
||||||
|
secretValue: "prod-value"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "staging",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "STAGING_KEY"
|
||||||
|
});
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
secretPath: testSuitePath,
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "PROD_KEY"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ timeout: 30000 }
|
||||||
|
);
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { createFolder, deleteFolder } from "e2e-test/testUtils/folders";
|
||||||
|
import { createSecretV2, deleteSecretV2, getSecretsV2 } from "e2e-test/testUtils/secrets";
|
||||||
|
|
||||||
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
|
|
||||||
|
describe("Secret expansion", () => {
|
||||||
|
const projectId = seedData1.projectV3.id;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const prodRootFolder = await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
name: "deep"
|
||||||
|
});
|
||||||
|
|
||||||
|
await createFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
environmentSlug: "prod",
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/deep",
|
||||||
|
name: "nested"
|
||||||
|
});
|
||||||
|
|
||||||
|
return async () => {
|
||||||
|
await deleteFolder({
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
secretPath: "/",
|
||||||
|
id: prodRootFolder.id,
|
||||||
|
workspaceId: projectId,
|
||||||
|
environmentSlug: "prod"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Local secret reference", async () => {
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "HELLO",
|
||||||
|
value: "world"
|
||||||
|
});
|
||||||
|
|
||||||
|
await createSecretV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "TEST",
|
||||||
|
// eslint-disable-next-line
|
||||||
|
value: "hello ${HELLO}"
|
||||||
|
});
|
||||||
|
//
|
||||||
|
// const expandedSecret = await getSecretByNameV2({
|
||||||
|
// environmentSlug: seedData1.environment.slug,
|
||||||
|
// workspaceId: projectId,
|
||||||
|
// secretPath: "/",
|
||||||
|
// authToken: jwtAuthToken,
|
||||||
|
// key: "TEST"
|
||||||
|
// });
|
||||||
|
// expect(expandedSecret.secretValue).toBe("hello world");
|
||||||
|
|
||||||
|
const listSecrets = await getSecretsV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken
|
||||||
|
});
|
||||||
|
expect(listSecrets.secrets).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
secretKey: "TEST",
|
||||||
|
secretValue: "hello world"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "TEST"
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteSecretV2({
|
||||||
|
environmentSlug: seedData1.environment.slug,
|
||||||
|
workspaceId: projectId,
|
||||||
|
secretPath: "/",
|
||||||
|
authToken: jwtAuthToken,
|
||||||
|
key: "HELLO"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -8,6 +8,7 @@ type TRawSecret = {
|
|||||||
secretComment?: string;
|
secretComment?: string;
|
||||||
version: number;
|
version: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSecret = async (dto: { path: string; key: string; value: string; comment: string; type?: SecretType }) => {
|
const createSecret = async (dto: { path: string; key: string; value: string; comment: string; type?: SecretType }) => {
|
||||||
const createSecretReqBody = {
|
const createSecretReqBody = {
|
||||||
workspaceId: seedData1.projectV3.id,
|
workspaceId: seedData1.projectV3.id,
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
type TFolder = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createFolder = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
name: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v1/folders`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
name: dto.name,
|
||||||
|
path: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
return res.json().folder as TFolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteFolder = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
id: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/api/v1/folders/${dto.id}`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
path: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
return res.json().folder as TFolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listFolders = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: `/api/v1/folders`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
path: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
return res.json().folders as TFolder[];
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
type TSecretImport = {
|
||||||
|
id: string;
|
||||||
|
importEnv: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
importPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createSecretImport = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
isReplication?: boolean;
|
||||||
|
secretPath: string;
|
||||||
|
importPath: string;
|
||||||
|
importEnv: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v1/secret-imports`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
isReplication: dto.isReplication,
|
||||||
|
path: dto.secretPath,
|
||||||
|
import: {
|
||||||
|
environment: dto.importEnv,
|
||||||
|
path: dto.importPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
const payload = JSON.parse(res.payload);
|
||||||
|
expect(payload).toHaveProperty("secretImport");
|
||||||
|
return payload.secretImport as TSecretImport;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteSecretImport = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
authToken: string;
|
||||||
|
id: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/api/v1/secret-imports/${dto.id}`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
path: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
const payload = JSON.parse(res.payload);
|
||||||
|
expect(payload).toHaveProperty("secretImport");
|
||||||
|
return payload.secretImport as TSecretImport;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listSecretImport = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: `/api/v1/secret-imports`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
path: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
const payload = JSON.parse(res.payload);
|
||||||
|
expect(payload).toHaveProperty("secretImports");
|
||||||
|
return payload.secretImports as TSecretImport[];
|
||||||
|
};
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import { SecretType } from "@app/db/schemas";
|
||||||
|
|
||||||
|
type TRawSecret = {
|
||||||
|
secretKey: string;
|
||||||
|
secretValue: string;
|
||||||
|
secretComment?: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createSecretV2 = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
comment?: string;
|
||||||
|
authToken: string;
|
||||||
|
type?: SecretType;
|
||||||
|
}) => {
|
||||||
|
const createSecretReqBody = {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
type: dto.type || SecretType.Shared,
|
||||||
|
secretPath: dto.secretPath,
|
||||||
|
secretKey: dto.key,
|
||||||
|
secretValue: dto.value,
|
||||||
|
secretComment: dto.comment
|
||||||
|
};
|
||||||
|
const createSecRes = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v3/secrets/raw/${dto.key}`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: createSecretReqBody
|
||||||
|
});
|
||||||
|
expect(createSecRes.statusCode).toBe(200);
|
||||||
|
const createdSecretPayload = JSON.parse(createSecRes.payload);
|
||||||
|
expect(createdSecretPayload).toHaveProperty("secret");
|
||||||
|
return createdSecretPayload.secret as TRawSecret;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteSecretV2 = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
key: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const deleteSecRes = await testServer.inject({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/api/v3/secrets/raw/${dto.key}`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
secretPath: dto.secretPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(deleteSecRes.statusCode).toBe(200);
|
||||||
|
const updatedSecretPayload = JSON.parse(deleteSecRes.payload);
|
||||||
|
expect(updatedSecretPayload).toHaveProperty("secret");
|
||||||
|
return updatedSecretPayload.secret as TRawSecret;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSecretByNameV2 = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
key: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const response = await testServer.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: `/api/v3/secrets/raw/${dto.key}`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
secretPath: dto.secretPath,
|
||||||
|
expandSecretReferences: "true",
|
||||||
|
include_imports: "true"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
const payload = JSON.parse(response.payload);
|
||||||
|
expect(payload).toHaveProperty("secret");
|
||||||
|
return payload.secret as TRawSecret;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSecretsV2 = async (dto: {
|
||||||
|
workspaceId: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
secretPath: string;
|
||||||
|
authToken: string;
|
||||||
|
}) => {
|
||||||
|
const getSecretsResponse = await testServer.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: `/api/v3/secrets/raw`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${dto.authToken}`
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
workspaceId: dto.workspaceId,
|
||||||
|
environment: dto.environmentSlug,
|
||||||
|
secretPath: dto.secretPath,
|
||||||
|
expandSecretReferences: "true",
|
||||||
|
include_imports: "true"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(getSecretsResponse.statusCode).toBe(200);
|
||||||
|
const getSecretsPayload = JSON.parse(getSecretsResponse.payload);
|
||||||
|
expect(getSecretsPayload).toHaveProperty("secrets");
|
||||||
|
expect(getSecretsPayload).toHaveProperty("imports");
|
||||||
|
return getSecretsPayload as {
|
||||||
|
secrets: TRawSecret[];
|
||||||
|
imports: {
|
||||||
|
secretPath: string;
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
secrets: TRawSecret[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -11,10 +11,11 @@ import { initLogger } from "@app/lib/logger";
|
|||||||
import { main } from "@app/server/app";
|
import { main } from "@app/server/app";
|
||||||
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { mockQueue } from "./mocks/queue";
|
|
||||||
import { mockSmtpServer } from "./mocks/smtp";
|
import { mockSmtpServer } from "./mocks/smtp";
|
||||||
import { mockKeyStore } from "./mocks/keystore";
|
|
||||||
import { initDbConnection } from "@app/db";
|
import { initDbConnection } from "@app/db";
|
||||||
|
import { queueServiceFactory } from "@app/queue";
|
||||||
|
import { keyStoreFactory } from "@app/keystore/keystore";
|
||||||
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
||||||
export default {
|
export default {
|
||||||
@@ -28,6 +29,9 @@ export default {
|
|||||||
dbRootCert: cfg.DB_ROOT_CERT
|
dbRootCert: cfg.DB_ROOT_CERT
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const redis = new Redis(cfg.REDIS_URL);
|
||||||
|
await redis.flushdb("ASYNC");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.migrate.rollback(
|
await db.migrate.rollback(
|
||||||
{
|
{
|
||||||
@@ -48,8 +52,8 @@ export default {
|
|||||||
extension: "ts"
|
extension: "ts"
|
||||||
});
|
});
|
||||||
const smtp = mockSmtpServer();
|
const smtp = mockSmtpServer();
|
||||||
const queue = mockQueue();
|
const queue = queueServiceFactory(cfg.REDIS_URL);
|
||||||
const keyStore = mockKeyStore();
|
const keyStore = keyStoreFactory(cfg.REDIS_URL);
|
||||||
const server = await main({ db, smtp, logger, queue, keyStore });
|
const server = await main({ db, smtp, logger, queue, keyStore });
|
||||||
// @ts-expect-error type
|
// @ts-expect-error type
|
||||||
globalThis.testServer = server;
|
globalThis.testServer = server;
|
||||||
@@ -91,6 +95,9 @@ export default {
|
|||||||
},
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await redis.flushdb("ASYNC");
|
||||||
|
redis.disconnect();
|
||||||
await db.destroy();
|
await db.destroy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user