feat: made secrets ops test to have both identity and jwt token based and test for identity

This commit is contained in:
Akhil Mohan
2024-02-20 20:58:10 +05:30
parent d428fd055b
commit 2996efe9d5
3 changed files with 373 additions and 666 deletions
+47 -387
View File
@@ -1,411 +1,71 @@
import { SecretType } from "@app/db/schemas"; import { OrgMembershipRole } from "@app/db/schemas";
import { getUserPrivateKey, seedData1 } from "@app/db/seed-data"; import { seedData1 } from "@app/db/seed-data";
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
const createRawSecret = async (dto: { export const createIdentity = async (name: string, role: string) => {
path: string; const createIdentityRes = await testServer.inject({
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", method: "POST",
url: `/api/v3/secrets/raw/${dto.key}`, url: "/api/v1/identities",
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: { body: {
workspaceId: seedData1.project.id, name,
environment: seedData1.environment.slug, role,
secretPath: dto.path organizationId: seedData1.organization.id
},
headers: {
authorization: `Bearer ${jwtAuthToken}`
} }
}); });
expect(deleteSecRes.statusCode).toBe(200); expect(createIdentityRes.statusCode).toBe(200);
const updatedSecretPayload = JSON.parse(deleteSecRes.payload); return createIdentityRes.json().identity;
expect(updatedSecretPayload).toHaveProperty("secret");
return updatedSecretPayload.secret;
}; };
describe("Secret operations with Identity token", async () => { export const deleteIdentity = async (id: string) => {
let identityToken = ""; const deleteIdentityRes = await testServer.inject({
let folderId = ""; method: "DELETE",
beforeAll(async () => { url: `/api/v1/identities/${id}`,
// enable bot headers: {
const res = await testServer.inject({ authorization: `Bearer ${jwtAuthToken}`
method: "GET",
url: `/api/v2/workspace/${seedData1.project.id}/encrypted-key`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(res.statusCode).toEqual(200);
const projectKeyEnc = JSON.parse(res.payload);
const userInfoRes = await testServer.inject({
method: "GET",
url: "/api/v2/users/me",
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(userInfoRes.statusCode).toEqual(200);
const { user: userInfo } = JSON.parse(userInfoRes.payload);
const privateKey = await getUserPrivateKey(seedData1.password, userInfo);
const projectKey = decryptAsymmetric({
ciphertext: projectKeyEnc.encryptedKey,
nonce: projectKeyEnc.nonce,
publicKey: projectKeyEnc.sender.publicKey,
privateKey
});
const projectBotRes = await testServer.inject({
method: "GET",
url: `/api/v1/bot/${seedData1.project.id}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(projectBotRes.statusCode).toEqual(200);
const projectBot = JSON.parse(projectBotRes.payload).bot;
const botKey = encryptAsymmetric(projectKey, projectBot.publicKey, privateKey);
// set bot as active
const setBotActive = await testServer.inject({
method: "PATCH",
url: `/api/v1/bot/${projectBot.id}/active`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: {
isActive: true,
workspaceId: seedData1.project.id,
botKey: {
encryptedKey: botKey.ciphertext,
nonce: botKey.nonce
}
}
});
expect(setBotActive.statusCode).toEqual(200);
// set identity token
const identityLogin = await testServer.inject({
method: "POST",
url: "/api/v1/auth/universal-auth/login",
body: {
clientSecret: seedData1.machineIdentity.clientCredentials.secret,
clientId: seedData1.machineIdentity.clientCredentials.id
}
});
expect(identityLogin.statusCode).toBe(200);
identityToken = identityLogin.json().accessToken;
// create a deep folder
const folderCreate = await testServer.inject({
method: "POST",
url: `/api/v1/folders`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
name: "folder",
path: "/nested1/nested2"
}
});
expect(folderCreate.statusCode).toBe(200);
folderId = folderCreate.json().folder.id;
});
afterAll(async () => {
const projectBotRes = await testServer.inject({
method: "GET",
url: `/api/v1/bot/${seedData1.project.id}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(projectBotRes.statusCode).toEqual(200);
const projectBot = JSON.parse(projectBotRes.payload).bot;
// set bot as inactive
const setBotInActive = await testServer.inject({
method: "PATCH",
url: `/api/v1/bot/${projectBot.id}/active`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: {
isActive: false,
workspaceId: seedData1.project.id
}
});
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 secretTestCases = [
{
path: "/",
secret: {
key: "secret-key-1",
value: "something-secret",
comment: "some comment"
}
},
{
path: "/nested1/nested2/folder",
secret: {
key: "secret-key-2",
value: `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCa6eeFk+cMVqFn
hoVQDYgn2Ptp5Azysr2UPq6P73pCL9BzUtOXKZROqDyGehzzfg3wE2KdYU1Jk5Uq
fP0ZOWDIlM2SaVCSI3FW32o5+ZiggjpqcVdLFc/PS0S/ZdSmpPd8h11iO2brtIAI
ugTW8fcKlGSNUwx9aFmE7A6JnTRliTxB1l6QaC+YAwTK39VgeVH2gDSWC407aS15
QobAkaBKKmFkzB5D7i2ZJwt+uXJV/rbLmyDmtnw0lubciGn7NX9wbYef180fisqT
aPNAz0nPKk0fFH2Wd5MZixNGbrrpDA+FCYvI5doThZyT2hpj08qWP07oXXCAqw46
IEupNSILAgMBAAECggEBAIJb5KzeaiZS3B3O8G4OBQ5rJB3WfyLYUHnoSWLsBbie
nc392/ovThLmtZAAQE6SO85Tsb93+t64Z2TKqv1H8G658UeMgfWIB78v4CcLJ2mi
TN/3opqXrzjkQOTDHzBgT7al/mpETHZ6fOdbCemK0fVALGFUioUZg4M8VXtuI4Jw
q28jAyoRKrCrzda4BeQ553NZ4G5RvwhX3O2I8B8upTbt5hLcisBKy8MPLYY5LUFj
YKAP+raf6QLliP6KYHuVxUlgzxjLTxVG41etcyqqZF+foyiKBO3PU3n8oh++tgQP
ExOxiR0JSkBG5b+oOBD0zxcvo3/SjBHn0dJOZCSU2SkCgYEAyCe676XnNyBZMRD7
6trsaoiCWBpA6M8H44+x3w4cQFtqV38RyLy60D+iMKjIaLqeBbnay61VMzo24Bz3
EuF2n4+9k/MetLJ0NCw8HmN5k0WSMD2BFsJWG8glVbzaqzehP4tIclwDTYc1jQVt
IoV2/iL7HGT+x2daUwbU5kN5hK0CgYEAxiLB+fmjxJW7VY4SHDLqPdpIW0q/kv4K
d/yZBrCX799vjmFb9vLh7PkQUfJhMJ/ttJOd7EtT3xh4mfkBeLfHwVU0d/ahbmSH
UJu/E9ZGxAW3PP0kxHZtPrLKQwBnfq8AxBauIhR3rPSorQTIOKtwz1jMlHFSUpuL
3KeK2YfDYJcCgYEAkQnJOlNcAuRb/WQzSHIvktssqK8NjiZHryy3Vc0hx7j2jES2
HGI2dSVHYD9OSiXA0KFm3OTTsnViwm/60iGzFdjRJV6tR39xGUVcoyCuPnvRfUd0
PYvBXgxgkYpyYlPDcwp5CvWGJy3tLi1acgOIwIuUr3S38sL//t4adGk8q1kCgYB8
Jbs1Tl53BvrimKpwUNbE+sjrquJu0A7vL68SqgQJoQ7dP9PH4Ff/i+/V6PFM7mib
BQOm02wyFbs7fvKVGVJoqWK+6CIucX732x7W5yRgHtS5ukQXdbzt1Ek3wkEW98Cb
HTruz7RNAt/NyXlLSODeit1lBbx3Vk9EaxZtRsv88QKBgGn7JwXgez9NOyobsNIo
QVO80rpUeenSjuFi+R0VmbLKe/wgAQbYJ0xTAsQ0btqViMzB27D6mJyC+KUIwWNX
MN8a+m46v4kqvZkKL2c4gmDibyURNe/vCtCHFuanJS/1mo2tr4XDyEeiuK52eTd9
omQDpP86RX/hIIQ+JyLSaWYa
-----END PRIVATE KEY-----`,
comment:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation"
}
},
{
path: "/nested1/nested2/folder",
secret: {
key: "secret-key-3",
value:
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uCg==",
comment: ""
}
} }
]; });
expect(deleteIdentityRes.statusCode).toBe(200);
return deleteIdentityRes.json().identity;
};
const getSecrets = async (environment: string, secretPath = "/") => { describe("Identity v1", async () => {
const res = await testServer.inject({ test("Create identity", async () => {
method: "GET", const newIdentity = await createIdentity("mac1", OrgMembershipRole.Admin);
url: `/api/v3/secrets/raw`, expect(newIdentity.name).toBe("mac1");
headers: { expect(newIdentity.authMethod).toBeNull();
authorization: `Bearer ${identityToken}`
},
query: {
secretPath,
environment,
workspaceId: seedData1.project.id
}
});
const secrets: { secretKey: string; secretValue: string; type: SecretType; version: number }[] =
JSON.parse(res.payload).secrets || [];
return secrets.map((el) => ({ key: el.secretKey, value: el.secretValue, type: el.type, version: el.version }));
};
test.each(secretTestCases)("Create raw secret", async ({ secret, path }) => { await deleteIdentity(newIdentity.id);
const createSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: secret.value,
secretComment: secret.comment,
secretPath: path
};
const createSecRes = await testServer.inject({
method: "POST",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${identityToken}`
},
body: createSecretReqBody
});
expect(createSecRes.statusCode).toBe(200);
const createdSecretPayload = JSON.parse(createSecRes.payload);
expect(createdSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: secret.key,
value: secret.value,
type: SecretType.Shared
})
])
);
await deleteRawSecret({ path, key: secret.key, token: identityToken });
}); });
test.each(secretTestCases)("Fetch raw secret by name", async ({ secret, path }) => { test("Update identity", async () => {
await createRawSecret({ path, ...secret, token: identityToken }); const newIdentity = await createIdentity("mac1", OrgMembershipRole.Admin);
expect(newIdentity.name).toBe("mac1");
expect(newIdentity.authMethod).toBeNull();
const getSecByNameRes = await testServer.inject({ const updatedIdentity = await testServer.inject({
method: "GET",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${identityToken}`
},
query: {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
secretPath: path
}
});
expect(getSecByNameRes.statusCode).toBe(200);
const secretPayload = JSON.parse(getSecByNameRes.payload);
expect(secretPayload).toHaveProperty("secret");
expect(secretPayload.secret).toEqual(
expect.objectContaining({
secretKey: secret.key,
secretValue: secret.value
})
);
await deleteRawSecret({ path, key: secret.key, token: identityToken });
});
test.each(secretTestCases)("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(secretTestCases)("Update raw secret", async ({ secret, path }) => {
await createRawSecret({ path, ...secret, token: identityToken });
const updateSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: "new-value",
secretPath: path
};
const updateSecRes = await testServer.inject({
method: "PATCH", method: "PATCH",
url: `/api/v3/secrets/raw/${secret.key}`, url: `/api/v1/identities/${newIdentity.id}`,
headers: { headers: {
authorization: `Bearer ${identityToken}` authorization: `Bearer ${jwtAuthToken}`
}, },
body: updateSecretReqBody body: {
name: "updated-mac-1",
role: OrgMembershipRole.Member
}
}); });
expect(updateSecRes.statusCode).toBe(200);
const updatedSecretPayload = JSON.parse(updateSecRes.payload);
expect(updatedSecretPayload).toHaveProperty("secret");
// fetch secrets expect(updatedIdentity.statusCode).toBe(200);
const secrets = await getSecrets(seedData1.environment.slug, path); expect(updatedIdentity.json().identity.name).toBe("updated-mac-1");
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: secret.key,
value: "new-value",
version: 2,
type: SecretType.Shared
})
])
);
await deleteRawSecret({ path, key: secret.key, token: identityToken }); await deleteIdentity(newIdentity.id);
}); });
test.each(secretTestCases)("Delete raw secret", async ({ path, secret }) => { test("Delete Identity", async () => {
await createRawSecret({ path, ...secret, token: identityToken }); const newIdentity = await createIdentity("mac1", OrgMembershipRole.Admin);
const deletedSecretReqBody = { const deletedIdentity = await deleteIdentity(newIdentity.id);
workspaceId: seedData1.project.id, expect(deletedIdentity.name).toBe("mac1");
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretPath: path
};
const deletedSecRes = await testServer.inject({
method: "DELETE",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${identityToken}`
},
body: deletedSecretReqBody
});
expect(deletedSecRes.statusCode).toBe(200);
const deletedSecretPayload = JSON.parse(deletedSecRes.payload);
expect(deletedSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual([]);
}); });
}); });
+299 -279
View File
@@ -1,6 +1,7 @@
import { SecretType, TSecrets } from "@app/db/schemas"; 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";
import { AuthMode } from "@app/services/auth/auth-type";
const createSecret = async (dto: { const createSecret = async (dto: {
projectKey: string; projectKey: string;
@@ -538,308 +539,327 @@ const deleteRawSecret = async (dto: { path: string; key: string }) => {
}; };
// raw secret endpoints // raw secret endpoints
describe("Secret V3 Raw Router", async () => { describe.each([{ auth: AuthMode.JWT }, { auth: AuthMode.IDENTITY_ACCESS_TOKEN }])(
let folderId = ""; "Secret V3 Raw Router - $auth mode",
const testRawSecrets = [ async ({ auth }) => {
{ let folderId = "";
path: "/", let authToken = "";
secret: { const testRawSecrets = [
key: "RAW-SEC1", {
value: "something-secret", path: "/",
comment: "some comment" secret: {
} key: "RAW-SEC1",
}, value: "something-secret",
{ comment: "some comment"
path: "/nested1/nested2/folder", }
secret: {
key: "NESTED-RAW-SEC1",
value: "something-secret",
comment: "some comment"
}
}
];
beforeAll(async () => {
const res = await testServer.inject({
method: "GET",
url: `/api/v2/workspace/${seedData1.project.id}/encrypted-key`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(res.statusCode).toEqual(200);
const projectKeyEnc = JSON.parse(res.payload);
const userInfoRes = await testServer.inject({
method: "GET",
url: "/api/v2/users/me",
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(userInfoRes.statusCode).toEqual(200);
const { user: userInfo } = JSON.parse(userInfoRes.payload);
const privateKey = await getUserPrivateKey(seedData1.password, userInfo);
const projectKey = decryptAsymmetric({
ciphertext: projectKeyEnc.encryptedKey,
nonce: projectKeyEnc.nonce,
publicKey: projectKeyEnc.sender.publicKey,
privateKey
});
const projectBotRes = await testServer.inject({
method: "GET",
url: `/api/v1/bot/${seedData1.project.id}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(projectBotRes.statusCode).toEqual(200);
const projectBot = JSON.parse(projectBotRes.payload).bot;
const botKey = encryptAsymmetric(projectKey, projectBot.publicKey, privateKey);
// set bot as active
const setBotActive = await testServer.inject({
method: "PATCH",
url: `/api/v1/bot/${projectBot.id}/active`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}, },
body: { {
isActive: true, path: "/nested1/nested2/folder",
workspaceId: seedData1.project.id, secret: {
botKey: { key: "NESTED-RAW-SEC1",
encryptedKey: botKey.ciphertext, value: "something-secret",
nonce: botKey.nonce comment: "some comment"
} }
} }
}); ];
expect(setBotActive.statusCode).toEqual(200);
// create a deep folder beforeAll(async () => {
const folderCreate = await testServer.inject({ const res = await testServer.inject({
method: "POST", method: "GET",
url: `/api/v1/folders`, url: `/api/v2/workspace/${seedData1.project.id}/encrypted-key`,
headers: { headers: {
authorization: `Bearer ${jwtAuthToken}` authorization: `Bearer ${jwtAuthToken}`
}, }
body: { });
workspaceId: seedData1.project.id, expect(res.statusCode).toEqual(200);
environment: seedData1.environment.slug, const projectKeyEnc = JSON.parse(res.payload);
name: "folder",
path: "/nested1/nested2" const userInfoRes = await testServer.inject({
method: "GET",
url: "/api/v2/users/me",
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(userInfoRes.statusCode).toEqual(200);
const { user: userInfo } = JSON.parse(userInfoRes.payload);
const privateKey = await getUserPrivateKey(seedData1.password, userInfo);
const projectKey = decryptAsymmetric({
ciphertext: projectKeyEnc.encryptedKey,
nonce: projectKeyEnc.nonce,
publicKey: projectKeyEnc.sender.publicKey,
privateKey
});
const projectBotRes = await testServer.inject({
method: "GET",
url: `/api/v1/bot/${seedData1.project.id}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
}
});
expect(projectBotRes.statusCode).toEqual(200);
const projectBot = JSON.parse(projectBotRes.payload).bot;
const botKey = encryptAsymmetric(projectKey, projectBot.publicKey, privateKey);
// set bot as active
const setBotActive = await testServer.inject({
method: "PATCH",
url: `/api/v1/bot/${projectBot.id}/active`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: {
isActive: true,
workspaceId: seedData1.project.id,
botKey: {
encryptedKey: botKey.ciphertext,
nonce: botKey.nonce
}
}
});
expect(setBotActive.statusCode).toEqual(200);
// create a deep folder
const folderCreate = await testServer.inject({
method: "POST",
url: `/api/v1/folders`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
name: "folder",
path: "/nested1/nested2"
}
});
expect(folderCreate.statusCode).toBe(200);
folderId = folderCreate.json().folder.id;
if (auth === AuthMode.JWT) {
authToken = jwtAuthToken;
} else if (auth === AuthMode.IDENTITY_ACCESS_TOKEN) {
const identityLogin = await testServer.inject({
method: "POST",
url: "/api/v1/auth/universal-auth/login",
body: {
clientSecret: seedData1.machineIdentity.clientCredentials.secret,
clientId: seedData1.machineIdentity.clientCredentials.id
}
});
expect(identityLogin.statusCode).toBe(200);
authToken = identityLogin.json().accessToken;
} }
}); });
expect(folderCreate.statusCode).toBe(200);
folderId = folderCreate.json().folder.id;
});
afterAll(async () => { afterAll(async () => {
const projectBotRes = await testServer.inject({ const projectBotRes = await testServer.inject({
method: "GET", method: "GET",
url: `/api/v1/bot/${seedData1.project.id}`, url: `/api/v1/bot/${seedData1.project.id}`,
headers: { headers: {
authorization: `Bearer ${jwtAuthToken}` authorization: `Bearer ${jwtAuthToken}`
} }
}); });
expect(projectBotRes.statusCode).toEqual(200); expect(projectBotRes.statusCode).toEqual(200);
const projectBot = JSON.parse(projectBotRes.payload).bot; const projectBot = JSON.parse(projectBotRes.payload).bot;
// set bot as inactive // set bot as inactive
const setBotInActive = await testServer.inject({ const setBotInActive = await testServer.inject({
method: "PATCH", method: "PATCH",
url: `/api/v1/bot/${projectBot.id}/active`, url: `/api/v1/bot/${projectBot.id}/active`,
headers: { headers: {
authorization: `Bearer ${jwtAuthToken}` authorization: `Bearer ${jwtAuthToken}`
}, },
body: { body: {
isActive: false, isActive: false,
workspaceId: seedData1.project.id workspaceId: seedData1.project.id
} }
});
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);
}); });
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 = "/") => {
const res = await testServer.inject({ const res = await testServer.inject({
method: "GET", method: "GET",
url: `/api/v3/secrets/raw`, url: `/api/v3/secrets/raw`,
headers: { headers: {
authorization: `Bearer ${jwtAuthToken}` authorization: `Bearer ${authToken}`
}, },
query: { query: {
secretPath, secretPath,
environment, environment,
workspaceId: seedData1.project.id workspaceId: seedData1.project.id
} }
}); });
const secrets: { secretKey: string; secretValue: string; type: SecretType; version: number }[] = const secrets: { secretKey: string; secretValue: string; type: SecretType; version: number }[] =
JSON.parse(res.payload).secrets || []; JSON.parse(res.payload).secrets || [];
return secrets.map((el) => ({ key: el.secretKey, value: el.secretValue, type: el.type, version: el.version })); return secrets.map((el) => ({ key: el.secretKey, value: el.secretValue, type: el.type, version: el.version }));
};
test.each(testRawSecrets)("Create secret raw in path $path", async ({ secret, path }) => {
const createSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: secret.value,
secretComment: secret.comment,
secretPath: path
}; };
const createSecRes = await testServer.inject({
method: "POST",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: createSecretReqBody
});
expect(createSecRes.statusCode).toBe(200);
const createdSecretPayload = JSON.parse(createSecRes.payload);
expect(createdSecretPayload).toHaveProperty("secret");
// fetch secrets test.each(testRawSecrets)("Create secret raw in path $path", async ({ secret, path }) => {
const secrets = await getSecrets(seedData1.environment.slug, path); const createSecretReqBody = {
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: secret.key,
value: secret.value,
type: SecretType.Shared
})
])
);
await deleteRawSecret({ path, key: secret.key });
});
test.each(testRawSecrets)("Get secret by name raw in path $path", async ({ secret, path }) => {
await createRawSecret({ path, ...secret });
const getSecByNameRes = await testServer.inject({
method: "GET",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
query: {
workspaceId: seedData1.project.id, workspaceId: seedData1.project.id,
environment: seedData1.environment.slug, environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: secret.value,
secretComment: secret.comment,
secretPath: path secretPath: path
} };
const createSecRes = await testServer.inject({
method: "POST",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${authToken}`
},
body: createSecretReqBody
});
expect(createSecRes.statusCode).toBe(200);
const createdSecretPayload = JSON.parse(createSecRes.payload);
expect(createdSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: secret.key,
value: secret.value,
type: SecretType.Shared
})
])
);
await deleteRawSecret({ path, key: secret.key });
}); });
expect(getSecByNameRes.statusCode).toBe(200);
const secretPayload = JSON.parse(getSecByNameRes.payload);
expect(secretPayload).toHaveProperty("secret");
expect(secretPayload.secret).toEqual(
expect.objectContaining({
secretKey: secret.key,
secretValue: secret.value
})
);
await deleteRawSecret({ path, key: secret.key }); test.each(testRawSecrets)("Get secret by name raw in path $path", async ({ secret, path }) => {
}); await createRawSecret({ path, ...secret });
test.each(testRawSecrets)("List secret raw in path $path", async ({ secret, path }) => { const getSecByNameRes = await testServer.inject({
await Promise.all( method: "GET",
Array.from(Array(5)).map((_e, i) => createRawSecret({ path, ...secret, key: `BULK-${secret.key}-${i + 1}` })) url: `/api/v3/secrets/raw/${secret.key}`,
); headers: {
authorization: `Bearer ${authToken}`
const secrets = await getSecrets(seedData1.environment.slug, path); },
expect(secrets.length).toEqual(5); query: {
expect(secrets).toEqual( workspaceId: seedData1.project.id,
expect.arrayContaining( environment: seedData1.environment.slug,
Array.from(Array(5)).map((_e, i) => secretPath: path
expect.objectContaining({ value: expect.any(String), key: `BULK-${secret.key}-${i + 1}` }) }
) });
) expect(getSecByNameRes.statusCode).toBe(200);
); const secretPayload = JSON.parse(getSecByNameRes.payload);
expect(secretPayload).toHaveProperty("secret");
await Promise.all( expect(secretPayload.secret).toEqual(
Array.from(Array(5)).map((_e, i) => deleteRawSecret({ path, key: `BULK-${secret.key}-${i + 1}` }))
);
});
test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => {
await createRawSecret({ path, ...secret });
const updateSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: "new-value",
secretPath: path
};
const updateSecRes = await testServer.inject({
method: "PATCH",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: updateSecretReqBody
});
expect(updateSecRes.statusCode).toBe(200);
const updatedSecretPayload = JSON.parse(updateSecRes.payload);
expect(updatedSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
key: secret.key, secretKey: secret.key,
value: "new-value", secretValue: secret.value
version: 2,
type: SecretType.Shared
}) })
]) );
);
await deleteRawSecret({ path, key: secret.key }); await deleteRawSecret({ path, key: secret.key });
});
test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => {
await createRawSecret({ path, ...secret });
const deletedSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretPath: path
};
const deletedSecRes = await testServer.inject({
method: "DELETE",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${jwtAuthToken}`
},
body: deletedSecretReqBody
}); });
expect(deletedSecRes.statusCode).toBe(200);
const deletedSecretPayload = JSON.parse(deletedSecRes.payload);
expect(deletedSecretPayload).toHaveProperty("secret");
// fetch secrets test.each(testRawSecrets)("List secret raw in path $path", async ({ secret, path }) => {
const secrets = await getSecrets(seedData1.environment.slug, path); await Promise.all(
expect(secrets).toEqual([]); Array.from(Array(5)).map((_e, i) => createRawSecret({ path, ...secret, key: `BULK-${secret.key}-${i + 1}` }))
}); );
});
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets.length).toEqual(5);
expect(secrets).toEqual(
expect.arrayContaining(
Array.from(Array(5)).map((_e, i) =>
expect.objectContaining({ value: expect.any(String), key: `BULK-${secret.key}-${i + 1}` })
)
)
);
await Promise.all(
Array.from(Array(5)).map((_e, i) => deleteRawSecret({ path, key: `BULK-${secret.key}-${i + 1}` }))
);
});
test.each(testRawSecrets)("Update secret raw in path $path", async ({ secret, path }) => {
await createRawSecret({ path, ...secret });
const updateSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretValue: "new-value",
secretPath: path
};
const updateSecRes = await testServer.inject({
method: "PATCH",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${authToken}`
},
body: updateSecretReqBody
});
expect(updateSecRes.statusCode).toBe(200);
const updatedSecretPayload = JSON.parse(updateSecRes.payload);
expect(updatedSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: secret.key,
value: "new-value",
version: 2,
type: SecretType.Shared
})
])
);
await deleteRawSecret({ path, key: secret.key });
});
test.each(testRawSecrets)("Delete secret raw in path $path", async ({ path, secret }) => {
await createRawSecret({ path, ...secret });
const deletedSecretReqBody = {
workspaceId: seedData1.project.id,
environment: seedData1.environment.slug,
type: SecretType.Shared,
secretPath: path
};
const deletedSecRes = await testServer.inject({
method: "DELETE",
url: `/api/v3/secrets/raw/${secret.key}`,
headers: {
authorization: `Bearer ${authToken}`
},
body: deletedSecretReqBody
});
expect(deletedSecRes.statusCode).toBe(200);
const deletedSecretPayload = JSON.parse(deletedSecRes.payload);
expect(deletedSecretPayload).toHaveProperty("secret");
// fetch secrets
const secrets = await getSecrets(seedData1.environment.slug, path);
expect(secrets).toEqual([]);
});
}
);
describe("Secret V3 Raw Router Without E2EE enabled", async () => { describe("Secret V3 Raw Router Without E2EE enabled", async () => {
const secret = { const secret = {
@@ -0,0 +1,27 @@
export const getDefaultOnPremFeatures = () => {
return {
_id: null,
slug: null,
tier: -1,
workspaceLimit: null,
workspacesUsed: 0,
memberLimit: null,
membersUsed: 0,
environmentLimit: null,
environmentsUsed: 0,
secretVersioning: true,
pitRecovery: false,
ipAllowlisting: true,
rbac: false,
customRateLimits: false,
customAlerts: false,
auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: false,
status: null,
trial_end: null,
has_used_trial: true,
secretApproval: false,
secretRotation: true
};
};