Merge remote-tracking branch 'origin' into revise-quickstart

This commit is contained in:
Tuan Dang
2023-04-29 20:39:30 +03:00
12 changed files with 429 additions and 389 deletions
-3
View File
@@ -15,9 +15,6 @@ jobs:
- name: 🧪 Run tests - name: 🧪 Run tests
run: npm run test:ci run: npm run test:ci
working-directory: backend working-directory: backend
- name: Check if Jest tests failed
if: ${{ always() }} && ${{ steps.backend-test.outcome }} != 'success'
run: exit 1
- name: Save commit hashes for tag - name: Save commit hashes for tag
id: commit id: commit
uses: pr-mpt/actions-commit-hash@v2 uses: pr-mpt/actions-commit-hash@v2
@@ -1,3 +1,4 @@
import { Types } from 'mongoose';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { MembershipOrg, Organization, User } from '../../models'; import { MembershipOrg, Organization, User } from '../../models';
@@ -139,7 +140,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
inviteEmail: inviteeEmail, inviteEmail: inviteeEmail,
organization: organizationId, organization: organizationId,
role: MEMBER, role: MEMBER,
status: invitee?.publicKey ? ACCEPTED : INVITED status: INVITED
}).save(); }).save();
} }
} else { } else {
@@ -164,6 +165,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
const organization = await Organization.findOne({ _id: organizationId }); const organization = await Organization.findOne({ _id: organizationId });
if (organization) { if (organization) {
const token = await TokenService.createToken({ const token = await TokenService.createToken({
type: TOKEN_EMAIL_ORG_INVITATION, type: TOKEN_EMAIL_ORG_INVITATION,
email: inviteeEmail, email: inviteeEmail,
@@ -179,6 +181,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
inviterEmail: req.user.email, inviterEmail: req.user.email,
organizationName: organization.name, organizationName: organization.name,
email: inviteeEmail, email: inviteeEmail,
organizationId: organization._id.toString(),
token, token,
callback_url: (await getSiteURL()) + '/signupinvite' callback_url: (await getSiteURL()) + '/signupinvite'
} }
@@ -214,13 +217,18 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
export const verifyUserToOrganization = async (req: Request, res: Response) => { export const verifyUserToOrganization = async (req: Request, res: Response) => {
let user, token; let user, token;
try { try {
const { email, code } = req.body; const {
email,
organizationId,
code
} = req.body;
user = await User.findOne({ email }).select('+publicKey'); user = await User.findOne({ email }).select('+publicKey');
const membershipOrg = await MembershipOrg.findOne({ const membershipOrg = await MembershipOrg.findOne({
inviteEmail: email, inviteEmail: email,
status: INVITED status: INVITED,
organization: new Types.ObjectId(organizationId)
}); });
if (!membershipOrg) if (!membershipOrg)
@@ -85,7 +85,7 @@ export const createOrganization = async (req: Request, res: Response) => {
export const getOrganization = async (req: Request, res: Response) => { export const getOrganization = async (req: Request, res: Response) => {
let organization; let organization;
try { try {
organization = req.membershipOrg.organization; organization = req.organization
} catch (err) { } catch (err) {
Sentry.setUser({ email: req.user.email }); Sentry.setUser({ email: req.user.email });
Sentry.captureException(err); Sentry.captureException(err);
@@ -323,14 +323,14 @@ export const createOrganizationPortalSession = async (
// check if there is a payment method on file // check if there is a payment method on file
const paymentMethods = await stripe.paymentMethods.list({ const paymentMethods = await stripe.paymentMethods.list({
customer: req.membershipOrg.organization.customerId, customer: req.organization.customerId,
type: 'card' type: 'card'
}); });
if (paymentMethods.data.length < 1) { if (paymentMethods.data.length < 1) {
// case: no payment method on file // case: no payment method on file
session = await stripe.checkout.sessions.create({ session = await stripe.checkout.sessions.create({
customer: req.membershipOrg.organization.customerId, customer: req.organization.customerId,
mode: 'setup', mode: 'setup',
payment_method_types: ['card'], payment_method_types: ['card'],
success_url: (await getSiteURL()) + '/dashboard', success_url: (await getSiteURL()) + '/dashboard',
@@ -338,7 +338,7 @@ export const createOrganizationPortalSession = async (
}); });
} else { } else {
session = await stripe.billingPortal.sessions.create({ session = await stripe.billingPortal.sessions.create({
customer: req.membershipOrg.organization.customerId, customer: req.organization.customerId,
return_url: (await getSiteURL()) + '/dashboard' return_url: (await getSiteURL()) + '/dashboard'
}); });
} }
@@ -370,7 +370,7 @@ export const getOrganizationSubscriptions = async (
}); });
subscriptions = await stripe.subscriptions.list({ subscriptions = await stripe.subscriptions.list({
customer: req.membershipOrg.organization.customerId customer: req.organization.customerId
}); });
} catch (err) { } catch (err) {
Sentry.setUser({ email: req.user.email }); Sentry.setUser({ email: req.user.email });
+42 -11
View File
@@ -270,28 +270,59 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => {
const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { const getAppsGithub = async ({ accessToken }: { accessToken: string }) => {
let apps; let apps;
try { try {
interface GitHubApp {
id: string;
name: string;
permissions: {
admin: boolean;
};
owner: {
login: string;
}
}
const octokit = new Octokit({ const octokit = new Octokit({
auth: accessToken, auth: accessToken,
}); });
const repos = ( const getAllRepos = async () => {
await octokit.request( let repos: GitHubApp[] = [];
"GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}", let page = 1;
{ const per_page = 100;
per_page: 100, let hasMore = true;
while (hasMore) {
const response = await octokit.request(
"GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}",
{
per_page,
page,
}
);
if (response.data.length > 0) {
repos = repos.concat(response.data);
page++;
} else {
hasMore = false;
} }
) }
).data;
return repos;
};
const repos = await getAllRepos();
apps = repos apps = repos
.filter((a: any) => a.permissions.admin === true) .filter((a: GitHubApp) => a.permissions.admin === true)
.map((a: any) => { .map((a: GitHubApp) => {
return ({ return {
appId: a.id, appId: a.id,
name: a.name, name: a.name,
owner: a.owner.login, owner: a.owner.login,
}); };
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException(err); Sentry.captureException(err);
+1
View File
@@ -19,6 +19,7 @@ router.post(
router.post( router.post(
'/verify', '/verify',
body('email').exists().trim().notEmpty(), body('email').exists().trim().notEmpty(),
body('organizationId').exists().trim().notEmpty(),
body('code').exists().trim().notEmpty(), body('code').exists().trim().notEmpty(),
validateRequest, validateRequest,
membershipOrgController.verifyUserToOrganization membershipOrgController.verifyUserToOrganization
@@ -9,7 +9,7 @@
<body> <body>
<h2>Join your organization on Infisical</h2> <h2>Join your organization on Infisical</h2>
<p>{{inviterFirstName}} ({{inviterEmail}}) has invited you to their Infisical organization — {{organizationName}}</p> <p>{{inviterFirstName}} ({{inviterEmail}}) has invited you to their Infisical organization — {{organizationName}}</p>
<a href="{{callback_url}}?token={{token}}&to={{email}}">Join now</a> <a href="{{callback_url}}?token={{token}}&to={{email}}&organization_id={{organizationId}}">Join now</a>
<h3>What is Infisical?</h3> <h3>What is Infisical?</h3>
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.</p> <p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.</p>
</body> </body>
@@ -1,408 +1,408 @@
import request from 'supertest' // import request from 'supertest'
import main from '../../../../src/index' // import main from '../../../../src/index'
import { testWorkspaceId } from '../../../../src/utils/addDevelopmentUser'; // import { testWorkspaceId } from '../../../../src/utils/addDevelopmentUser';
import { deleteAllSecrets, getAllSecrets, getJWTFromTestUser, getServiceTokenFromTestUser } from '../../../helper/helper'; // import { deleteAllSecrets, getAllSecrets, getJWTFromTestUser, getServiceTokenFromTestUser } from '../../../helper/helper';
// eslint-disable-next-line @typescript-eslint/no-var-requires // // eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithNoOverride = require('../../../data/batch-secrets-no-override.json'); // const batchSecretRequestWithNoOverride = require('../../../data/batch-secrets-no-override.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires // // eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithOverrides = require('../../../data/batch-secrets-with-overrides.json'); // const batchSecretRequestWithOverrides = require('../../../data/batch-secrets-with-overrides.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires // // eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithBadRequest = require('../../../data/batch-create-secrets-with-some-missing-params.json'); // const batchSecretRequestWithBadRequest = require('../../../data/batch-create-secrets-with-some-missing-params.json');
let server: any; // let server: any;
beforeAll(async () => { // beforeAll(async () => {
server = await main; // server = await main;
}); // });
afterAll(async () => { // afterAll(async () => {
server.close(); // server.close();
}); // });
describe("GET /api/v2/secrets", () => { // describe("GET /api/v2/secrets", () => {
describe("Get secrets via JTW", () => { // describe("Get secrets via JTW", () => {
test("should create secrets and read secrets via jwt", async () => { // test("should create secrets and read secrets via jwt", async () => {
try { // try {
// get login details // // get login details
const loginResponse = await getJWTFromTestUser() // const loginResponse = await getJWTFromTestUser()
// create creates // // create creates
const createSecretsResponse = await request(server) // const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch") // .post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.send({ // .send({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev", // environment: "dev",
requests: batchSecretRequestWithNoOverride // requests: batchSecretRequestWithNoOverride
}) // })
expect(createSecretsResponse.statusCode).toBe(200) // expect(createSecretsResponse.statusCode).toBe(200)
const getSecrets = await request(server) // const getSecrets = await request(server)
.get("/api/v2/secrets") // .get("/api/v2/secrets")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.query({ // .query({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev" // environment: "dev"
}) // })
expect(getSecrets.statusCode).toBe(200) // expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets") // expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3) // expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array); // expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => { // getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id'); // expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy(); // expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version'); // expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy(); // expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace'); // expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy(); // expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type'); // expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy(); // expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags'); // expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0); // expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment'); // expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev"); // expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext'); // expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy(); // expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV'); // expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy(); // expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag'); // expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy(); // expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext'); // expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy(); // expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV'); // expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy(); // expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag'); // expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy(); // expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext'); // expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy(); // expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV'); // expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy(); // expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag'); // expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy(); // expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt'); // expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy(); // expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt'); // expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy(); // expect(secret.updatedAt).toBeTruthy();
}); // });
} finally { // } finally {
// clean up // // clean up
await deleteAllSecrets() // await deleteAllSecrets()
} // }
}) // })
test("Get secrets via jwt when personal overrides exist", async () => { // test("Get secrets via jwt when personal overrides exist", async () => {
try { // try {
// get login details // // get login details
const loginResponse = await getJWTFromTestUser() // const loginResponse = await getJWTFromTestUser()
// create creates // // create creates
const createSecretsResponse = await request(server) // const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch") // .post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.send({ // .send({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev", // environment: "dev",
requests: batchSecretRequestWithOverrides // requests: batchSecretRequestWithOverrides
}) // })
expect(createSecretsResponse.statusCode).toBe(200) // expect(createSecretsResponse.statusCode).toBe(200)
const getSecrets = await request(server) // const getSecrets = await request(server)
.get("/api/v2/secrets") // .get("/api/v2/secrets")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.query({ // .query({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev" // environment: "dev"
}) // })
expect(getSecrets.statusCode).toBe(200) // expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets") // expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(2) // expect(getSecrets.body.secrets).toHaveLength(2)
expect(getSecrets.body.secrets).toBeInstanceOf(Array); // expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => { // getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id'); // expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy(); // expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version'); // expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy(); // expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace'); // expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy(); // expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type'); // expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy(); // expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags'); // expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0); // expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment'); // expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev"); // expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext'); // expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy(); // expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV'); // expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy(); // expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag'); // expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy(); // expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext'); // expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy(); // expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV'); // expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy(); // expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag'); // expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy(); // expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext'); // expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy(); // expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV'); // expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy(); // expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag'); // expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy(); // expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt'); // expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy(); // expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt'); // expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy(); // expect(secret.updatedAt).toBeTruthy();
}); // });
} finally { // } finally {
// clean up // // clean up
await deleteAllSecrets() // await deleteAllSecrets()
} // }
}) // })
}) // })
describe("fetch secrets via service token", () => { // describe("fetch secrets via service token", () => {
test("Get secrets via jwt when personal overrides exist", async () => { // test("Get secrets via jwt when personal overrides exist", async () => {
try { // try {
// get login details // // get login details
const loginResponse = await getJWTFromTestUser() // const loginResponse = await getJWTFromTestUser()
// create creates // // create creates
const createSecretsResponse = await request(server) // const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch") // .post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.send({ // .send({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev", // environment: "dev",
requests: batchSecretRequestWithOverrides // requests: batchSecretRequestWithOverrides
}) // })
expect(createSecretsResponse.statusCode).toBe(200) // expect(createSecretsResponse.statusCode).toBe(200)
// now use the service token to fetch secrets // // now use the service token to fetch secrets
const serviceToken = await getServiceTokenFromTestUser() // const serviceToken = await getServiceTokenFromTestUser()
const getSecrets = await request(server) // const getSecrets = await request(server)
.get("/api/v2/secrets") // .get("/api/v2/secrets")
.set('Authorization', `Bearer ${serviceToken}`) // .set('Authorization', `Bearer ${serviceToken}`)
.query({ // .query({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev" // environment: "dev"
}) // })
expect(getSecrets.statusCode).toBe(200) // expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets") // expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(2) // expect(getSecrets.body.secrets).toHaveLength(2)
expect(getSecrets.body.secrets).toBeInstanceOf(Array); // expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => { // getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id'); // expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy(); // expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version'); // expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy(); // expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace'); // expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy(); // expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type'); // expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy(); // expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags'); // expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0); // expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment'); // expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev"); // expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext'); // expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy(); // expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV'); // expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy(); // expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag'); // expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy(); // expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext'); // expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy(); // expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV'); // expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy(); // expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag'); // expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy(); // expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext'); // expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy(); // expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV'); // expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy(); // expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag'); // expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy(); // expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt'); // expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy(); // expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt'); // expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy(); // expect(secret.updatedAt).toBeTruthy();
}); // });
} finally { // } finally {
// clean up // // clean up
await deleteAllSecrets() // await deleteAllSecrets()
} // }
}) // })
test("should create secrets and read secrets via service token when no overrides", async () => { // test("should create secrets and read secrets via service token when no overrides", async () => {
try { // try {
// get login details // // get login details
const loginResponse = await getJWTFromTestUser() // const loginResponse = await getJWTFromTestUser()
// create secrets // // create secrets
const createSecretsResponse = await request(server) // const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch") // .post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.send({ // .send({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev", // environment: "dev",
requests: batchSecretRequestWithNoOverride // requests: batchSecretRequestWithNoOverride
}) // })
expect(createSecretsResponse.statusCode).toBe(200) // expect(createSecretsResponse.statusCode).toBe(200)
// now use the service token to fetch secrets // // now use the service token to fetch secrets
const serviceToken = await getServiceTokenFromTestUser() // const serviceToken = await getServiceTokenFromTestUser()
const getSecrets = await request(server) // const getSecrets = await request(server)
.get("/api/v2/secrets") // .get("/api/v2/secrets")
.set('Authorization', `Bearer ${serviceToken}`) // .set('Authorization', `Bearer ${serviceToken}`)
.query({ // .query({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev" // environment: "dev"
}) // })
expect(getSecrets.statusCode).toBe(200) // expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets") // expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3) // expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array); // expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => { // getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id'); // expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy(); // expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version'); // expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy(); // expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace'); // expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy(); // expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type'); // expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy(); // expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags'); // expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0); // expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment'); // expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev"); // expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext'); // expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy(); // expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV'); // expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy(); // expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag'); // expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy(); // expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext'); // expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy(); // expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV'); // expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy(); // expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag'); // expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy(); // expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext'); // expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy(); // expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV'); // expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy(); // expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag'); // expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy(); // expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt'); // expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy(); // expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt'); // expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy(); // expect(secret.updatedAt).toBeTruthy();
}); // });
} finally { // } finally {
// clean up // // clean up
await deleteAllSecrets() // await deleteAllSecrets()
} // }
}) // })
}) // })
describe("create secrets via JWT", () => { // describe("create secrets via JWT", () => {
test("Create secrets via jwt when some requests have missing required parameters", async () => { // test("Create secrets via jwt when some requests have missing required parameters", async () => {
// get login details // // get login details
const loginResponse = await getJWTFromTestUser() // const loginResponse = await getJWTFromTestUser()
// create creates // // create creates
const createSecretsResponse = await request(server) // const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch") // .post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`) // .set('Authorization', `Bearer ${loginResponse.token}`)
.send({ // .send({
workspaceId: testWorkspaceId, // workspaceId: testWorkspaceId,
environment: "dev", // environment: "dev",
requests: batchSecretRequestWithBadRequest // requests: batchSecretRequestWithBadRequest
}) // })
const allSecretsInDB = await getAllSecrets() // const allSecretsInDB = await getAllSecrets()
expect(createSecretsResponse.statusCode).toBe(500) // TODO should be set to 400 // expect(createSecretsResponse.statusCode).toBe(500) // TODO should be set to 400
expect(allSecretsInDB).toHaveLength(0) // expect(allSecretsInDB).toHaveLength(0)
}) // })
}) // })
}) // })
@@ -1,7 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import { faKey, faUser } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { Menu, MenuGroup, MenuItem } from './Menu'; import { Menu, MenuGroup, MenuItem } from './Menu';
@@ -74,14 +71,14 @@ export const WithIcons: Story = {
render: (args) => ( render: (args) => (
<Menu {...args}> <Menu {...args}>
<MenuGroup title="Group 1"> <MenuGroup title="Group 1">
<MenuItem isDisabled icon={<FontAwesomeIcon icon={faKey} />}> <MenuItem isDisabled icon="system-outline-90-lock-closed">
Secrets Secrets
</MenuItem> </MenuItem>
<MenuItem icon={<FontAwesomeIcon icon={faUser} />}>Members</MenuItem> <MenuItem icon="system-outline-96-groups">Members</MenuItem>
</MenuGroup> </MenuGroup>
<MenuGroup title="Group 2"> <MenuGroup title="Group 2">
<MenuItem icon={<FontAwesomeIcon icon={faKey} />}>Secrets</MenuItem> <MenuItem icon="system-outline-90-lock-closed">Secrets</MenuItem>
<MenuItem icon={<FontAwesomeIcon icon={faKey} />}>Members</MenuItem> <MenuItem icon="system-outline-96-groups">Members</MenuItem>
</MenuGroup> </MenuGroup>
</Menu> </Menu>
), ),
@@ -93,12 +90,12 @@ export const WithDescription: Story = {
<Menu {...args}> <Menu {...args}>
<MenuItem <MenuItem
isDisabled isDisabled
icon={<FontAwesomeIcon icon={faKey} />} icon="system-outline-90-lock-closed"
description="Some random description" description="Some random description"
> >
Secrets Secrets
</MenuItem> </MenuItem>
<MenuItem icon={<FontAwesomeIcon icon={faUser} />} description="Some random description"> <MenuItem icon="system-outline-96-groups" description="Some random description">
Members Members
</MenuItem> </MenuItem>
</Menu> </Menu>
+1
View File
@@ -1,3 +1,4 @@
// @ts-nocheck
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable global-require */ /* eslint-disable global-require */
import { ComponentPropsWithRef, ElementType, ReactNode, Ref, useRef } from 'react'; import { ComponentPropsWithRef, ElementType, ReactNode, Ref, useRef } from 'react';
@@ -1,22 +1,25 @@
interface Props { interface Props {
email: string; email: string;
code: string; code: string;
organizationId: string;
} }
/** /**
* This route verifies the signup invite link * This route verifies the signup invite link
* @param {object} obj * @param {object} obj
* @param {string} obj.email - email that a user is trying to verify * @param {string} obj.email - email that a user is trying to verify
* @param {string} obj.organizationId - id of organization that a user is trying to verify for
* @param {string} obj.code - code that a user received to the abovementioned email * @param {string} obj.code - code that a user received to the abovementioned email
* @returns * @returns
*/ */
const verifySignupInvite = ({ email, code }: Props) => fetch('/api/v1/invite-org/verify', { const verifySignupInvite = ({ email, organizationId, code }: Props) => fetch('/api/v1/invite-org/verify', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
email, email,
organizationId,
code code
}) })
}); });
+3 -1
View File
@@ -51,6 +51,7 @@ export default function SignupInvite() {
const router = useRouter(); const router = useRouter();
const parsedUrl = queryString.parse(router.asPath.split('?')[1]); const parsedUrl = queryString.parse(router.asPath.split('?')[1]);
const token = parsedUrl.token as string; const token = parsedUrl.token as string;
const organizationId = parsedUrl.organization_id as string;
const email = (parsedUrl.to as string)?.replace(' ', '+').trim(); const email = (parsedUrl.to as string)?.replace(' ', '+').trim();
// Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria. // Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria.
@@ -190,7 +191,8 @@ export default function SignupInvite() {
onButtonPressed={async () => { onButtonPressed={async () => {
const response = await verifySignupInvite({ const response = await verifySignupInvite({
email, email,
code: token code: token,
organizationId
}); });
if (response.status === 200) { if (response.status === 200) {
const res = await response.json(); const res = await response.json();
+4 -4
View File
@@ -60,13 +60,13 @@
$ kubectl get all -n {{ .Release.Namespace }} $ kubectl get all -n {{ .Release.Namespace }}
→ Get your release status → Get your release status
$ helm status {{ .Release.Namespace }} {{ .Release.Name }} $ helm status -n {{ .Release.Namespace }} {{ .Release.Name }}
→ Get your release resources → Get your release resources
$ helm get all {{ .Release.Namespace }} {{ .Release.Name }} $ helm get all -n {{ .Release.Namespace }} {{ .Release.Name }}
→ Uninstall your release → Uninstall your release
$ helm uninstall {{ .Release.Namespace }} {{ .Release.Name }} $ helm uninstall -n {{ .Release.Namespace }} {{ .Release.Name }}
→ Get MongoDB root password → Get MongoDB root password
$ kubectl get secret -n {{ .Release.Namespace }} mongodb $ kubectl get secret -n {{ .Release.Namespace }} mongodb
@@ -82,4 +82,4 @@ $ kubectl get secrets/<your-secret-name> -n {{ .Release.Namespace }} \
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――┤ ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――┤
## ##