feat: changed the whole api from projectid to slug

This commit is contained in:
Akhil Mohan
2024-03-22 14:18:12 +05:30
parent 70fe80414d
commit e3e62430ba
28 changed files with 357 additions and 165 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ declare module "fastify" {
authMethod: ActorAuthMethod; authMethod: ActorAuthMethod;
type: ActorType; type: ActorType;
id: string; id: string;
orgId?: string; orgId: string;
}; };
// passport data // passport data
passportUser: { passportUser: {
+1 -1
View File
@@ -13,7 +13,7 @@ export type TProjectPermission = {
actorId: string; actorId: string;
projectId: string; projectId: string;
actorAuthMethod: ActorAuthMethod; actorAuthMethod: ActorAuthMethod;
actorOrgId: string | undefined; actorOrgId: string;
}; };
export type RequiredKeys<T> = { export type RequiredKeys<T> = {
@@ -16,7 +16,7 @@ export type TAuthMode =
userId: string; userId: string;
tokenVersionId: string; // the session id of token used tokenVersionId: string; // the session id of token used
user: TUsers; user: TUsers;
orgId?: string; orgId: string;
authMethod: AuthMethod; authMethod: AuthMethod;
} }
| { | {
@@ -119,7 +119,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
userId: user.id, userId: user.id,
tokenVersionId, tokenVersionId,
actor, actor,
orgId, orgId: orgId as string,
authMethod: token.authMethod authMethod: token.authMethod
}; };
break; break;
+2
View File
@@ -566,6 +566,7 @@ export const registerRoutes = async (
dynamicSecretDAL dynamicSecretDAL
}); });
const dynamicSecretService = dynamicSecretServiceFactory({ const dynamicSecretService = dynamicSecretServiceFactory({
projectDAL,
dynamicSecretQueueService, dynamicSecretQueueService,
dynamicSecretDAL, dynamicSecretDAL,
dynamicSecretLeaseDAL, dynamicSecretLeaseDAL,
@@ -574,6 +575,7 @@ export const registerRoutes = async (
permissionService permissionService
}); });
const dynamicSecretLeaseService = dynamicSecretLeaseServiceFactory({ const dynamicSecretLeaseService = dynamicSecretLeaseServiceFactory({
projectDAL,
permissionService, permissionService,
dynamicSecretQueueService, dynamicSecretQueueService,
dynamicSecretDAL, dynamicSecretDAL,
@@ -7,14 +7,16 @@ import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
import { SanitizedDynamicSecretSchema } from "../sanitizedSchemas";
export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvider) => { export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/", url: "/",
method: "POST", method: "POST",
schema: { schema: {
body: z.object({ body: z.object({
slug: z.string(), slug: z.string().min(1),
projectId: z.string(), projectSlug: z.string().min(1),
ttl: z ttl: z
.string() .string()
.optional() .optional()
@@ -27,7 +29,7 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}), }),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -57,9 +59,9 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
leaseId: z.string() leaseId: z.string()
}), }),
body: z.object({ body: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().min(1).trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -100,9 +102,9 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
if (valMs > daysToMillisecond(1)) if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}), }),
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().min(1).trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -125,34 +127,36 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
}); });
server.route({ server.route({
url: "/:slug", url: "/:leaseId",
method: "GET", method: "GET",
schema: { schema: {
params: z.object({ params: z.object({
slug: z.string() leaseId: z.string()
}), }),
querystring: z.object({ querystring: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
leases: DynamicSecretLeasesSchema.array() lease: DynamicSecretLeasesSchema.extend({
dynamicSecret: SanitizedDynamicSecretSchema
})
}) })
} }
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => { handler: async (req) => {
const leases = await server.services.dynamicSecretLease.listLeases({ const lease = await server.services.dynamicSecretLease.getLeaseDetails({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
slug: req.params.slug, leaseId: req.params.leaseId,
...req.query ...req.query
}); });
return { leases }; return { lease };
} }
}); });
}; };
@@ -1,6 +1,7 @@
import ms from "ms"; import ms from "ms";
import { z } from "zod"; import { z } from "zod";
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
import { daysToMillisecond } from "@app/lib/dates"; import { daysToMillisecond } from "@app/lib/dates";
import { removeTrailingSlash } from "@app/lib/fn"; import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -15,7 +16,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
method: "POST", method: "POST",
schema: { schema: {
body: z.object({ body: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
provider: DynamicSecretProviderSchema, provider: DynamicSecretProviderSchema,
defaultTTL: z.string().superRefine((val, ctx) => { defaultTTL: z.string().superRefine((val, ctx) => {
const valMs = ms(val); const valMs = ms(val);
@@ -37,8 +38,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}) })
.nullable(), .nullable(),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string(), environment: z.string().min(1),
slug: z.string().toLowerCase() slug: z.string().min(1).toLowerCase()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -67,9 +68,9 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
slug: z.string() slug: z.string()
}), }),
body: z.object({ body: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string(), environment: z.string().min(1),
data: z.object({ data: z.object({
inputs: z.any().optional(), inputs: z.any().optional(),
defaultTTL: z defaultTTL: z
@@ -113,7 +114,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
slug: req.params.slug, slug: req.params.slug,
path: req.body.path, path: req.body.path,
projectId: req.body.projectId, projectSlug: req.body.projectSlug,
environment: req.body.environment, environment: req.body.environment,
...req.body.data ...req.body.data
}); });
@@ -129,9 +130,9 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
slug: z.string() slug: z.string()
}), }),
body: z.object({ body: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -161,9 +162,9 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
slug: z.string() slug: z.string()
}), }),
querystring: z.object({ querystring: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -192,9 +193,9 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
method: "GET", method: "GET",
schema: { schema: {
querystring: z.object({ querystring: z.object({
projectId: z.string(), projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash), path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string() environment: z.string().min(1)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -214,4 +215,36 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
return { dynamicSecrets: dynamicSecretCfgs }; return { dynamicSecrets: dynamicSecretCfgs };
} }
}); });
server.route({
url: "/:slug/leases",
method: "GET",
schema: {
params: z.object({
slug: z.string()
}),
querystring: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
}),
response: {
200: z.object({
leases: DynamicSecretLeasesSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const leases = await server.services.dynamicSecretLease.listLeases({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
...req.query
});
return { leases };
}
});
}; };
@@ -1,10 +1,71 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas"; import { DynamicSecretLeasesSchema, TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex"; import { DatabaseError } from "@app/lib/errors";
import { ormify, selectAllTableCols } from "@app/lib/knex";
export type TDynamicSecretLeaseDALFactory = ReturnType<typeof dynamicSecretLeaseDALFactory>; export type TDynamicSecretLeaseDALFactory = ReturnType<typeof dynamicSecretLeaseDALFactory>;
export const dynamicSecretLeaseDALFactory = (db: TDbClient) => { export const dynamicSecretLeaseDALFactory = (db: TDbClient) => {
const orm = ormify(db, TableName.DynamicSecretLease); const orm = ormify(db, TableName.DynamicSecretLease);
return orm;
const findById = async (id: string, tx?: Knex) => {
try {
const doc = await (tx || db)(TableName.DynamicSecretLease)
.where({ id })
.first()
.join(
TableName.DynamicSecret,
`${TableName.DynamicSecretLease}.dynamicSecretId`,
`${TableName.DynamicSecret}.id`
)
.select(selectAllTableCols(TableName.DynamicSecretLease))
.select(
db.ref("id").withSchema(TableName.DynamicSecret).as("dynId"),
db.ref("slug").withSchema(TableName.DynamicSecret).as("dynSlug"),
db.ref("version").withSchema(TableName.DynamicSecret).as("dynVersion"),
db.ref("type").withSchema(TableName.DynamicSecret).as("dynType"),
db.ref("defaultTTL").withSchema(TableName.DynamicSecret).as("dynDefaultTTL"),
db.ref("maxTTL").withSchema(TableName.DynamicSecret).as("dynMaxTTL"),
db.ref("inputIV").withSchema(TableName.DynamicSecret).as("dynInputIV"),
db.ref("inputTag").withSchema(TableName.DynamicSecret).as("dynInputTag"),
db.ref("inputCiphertext").withSchema(TableName.DynamicSecret).as("dynInputCiphertext"),
db.ref("algorithm").withSchema(TableName.DynamicSecret).as("dynAlgorithm"),
db.ref("keyEncoding").withSchema(TableName.DynamicSecret).as("dynKeyEncoding"),
db.ref("folderId").withSchema(TableName.DynamicSecret).as("dynFolderId"),
db.ref("status").withSchema(TableName.DynamicSecret).as("dynStatus"),
db.ref("statusDetails").withSchema(TableName.DynamicSecret).as("dynStatusDetails"),
db.ref("createdAt").withSchema(TableName.DynamicSecret).as("dynCreatedAt"),
db.ref("updatedAt").withSchema(TableName.DynamicSecret).as("dynUpdatedAt")
);
if (!doc) return;
return {
...DynamicSecretLeasesSchema.parse(doc),
dynamicSecret: {
id: doc.dynId,
slug: doc.dynSlug,
version: doc.dynVersion,
type: doc.dynType,
defaultTTL: doc.dynDefaultTTL,
maxTTL: doc.dynMaxTTL,
inputIV: doc.dynInputIV,
inputTag: doc.dynInputTag,
inputCiphertext: doc.dynInputCiphertext,
algorithm: doc.dynAlgorithm,
keyEncoding: doc.dynKeyEncoding,
folderId: doc.dynFolderId,
status: doc.dynStatus,
statusDetails: doc.dynStatusDetails,
createdAt: doc.dynCreatedAt,
updatedAt: doc.dynUpdatedAt
}
};
} catch (error) {
throw new DatabaseError({ error, name: "DynamicSecretLeaseFindById" });
}
};
return { ...orm, findById };
}; };
@@ -9,12 +9,14 @@ import { BadRequestError } from "@app/lib/errors";
import { TDynamicSecretDALFactory } from "../dynamic-secret/dynamic-secret-dal"; import { TDynamicSecretDALFactory } from "../dynamic-secret/dynamic-secret-dal";
import { DynamicSecretProviders, TDynamicProviderFns } from "../dynamic-secret/providers/models"; import { DynamicSecretProviders, TDynamicProviderFns } from "../dynamic-secret/providers/models";
import { TProjectDALFactory } from "../project/project-dal";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TDynamicSecretLeaseDALFactory } from "./dynamic-secret-lease-dal"; import { TDynamicSecretLeaseDALFactory } from "./dynamic-secret-lease-dal";
import { TDynamicSecretLeaseQueueServiceFactory } from "./dynamic-secret-lease-queue"; import { TDynamicSecretLeaseQueueServiceFactory } from "./dynamic-secret-lease-queue";
import { import {
TCreateDynamicSecretLeaseDTO, TCreateDynamicSecretLeaseDTO,
TDeleteDynamicSecretLeaseDTO, TDeleteDynamicSecretLeaseDTO,
TDetailsDynamicSecretLeaseDTO,
TListDynamicSecretLeasesDTO, TListDynamicSecretLeasesDTO,
TRenewDynamicSecretLeaseDTO TRenewDynamicSecretLeaseDTO
} from "./dynamic-secret-lease-types"; } from "./dynamic-secret-lease-types";
@@ -26,6 +28,7 @@ type TDynamicSecretLeaseServiceFactoryDep = {
dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory; dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory;
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">; folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
}; };
export type TDynamicSecretLeaseServiceFactory = ReturnType<typeof dynamicSecretLeaseServiceFactory>; export type TDynamicSecretLeaseServiceFactory = ReturnType<typeof dynamicSecretLeaseServiceFactory>;
@@ -36,19 +39,24 @@ export const dynamicSecretLeaseServiceFactory = ({
dynamicSecretDAL, dynamicSecretDAL,
folderDAL, folderDAL,
permissionService, permissionService,
dynamicSecretQueueService dynamicSecretQueueService,
projectDAL
}: TDynamicSecretLeaseServiceFactoryDep) => { }: TDynamicSecretLeaseServiceFactoryDep) => {
const create = async ({ const create = async ({
environment, environment,
path, path,
slug, slug,
projectId, projectSlug,
actor, actor,
actorId, actorId,
actorOrgId, actorOrgId,
actorAuthMethod, actorAuthMethod,
ttl ttl
}: TCreateDynamicSecretLeaseDTO) => { }: TCreateDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -57,7 +65,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit, ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
); );
@@ -102,11 +110,15 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId, actorOrgId,
actorId, actorId,
actor, actor,
projectId, projectSlug,
path, path,
environment, environment,
leaseId leaseId
}: TRenewDynamicSecretLeaseDTO) => { }: TRenewDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -125,12 +137,7 @@ export const dynamicSecretLeaseServiceFactory = ({
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId); const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" }); if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
id: dynamicSecretLease.dynamicSecretId,
folderId: folder.id
});
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders]; const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
const decryptedStoredInput = JSON.parse( const decryptedStoredInput = JSON.parse(
infisicalSymmetricDecrypt({ infisicalSymmetricDecrypt({
@@ -168,12 +175,16 @@ export const dynamicSecretLeaseServiceFactory = ({
leaseId, leaseId,
environment, environment,
path, path,
projectId, projectSlug,
actor, actor,
actorId, actorId,
actorOrgId, actorOrgId,
actorAuthMethod actorAuthMethod
}: TDeleteDynamicSecretLeaseDTO) => { }: TDeleteDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -182,7 +193,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit, ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
); );
@@ -192,12 +203,7 @@ export const dynamicSecretLeaseServiceFactory = ({
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId); const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" }); if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
id: dynamicSecretLease.dynamicSecretId,
folderId: folder.id
});
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders]; const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
const decryptedStoredInput = JSON.parse( const decryptedStoredInput = JSON.parse(
infisicalSymmetricDecrypt({ infisicalSymmetricDecrypt({
@@ -220,11 +226,15 @@ export const dynamicSecretLeaseServiceFactory = ({
slug, slug,
actor, actor,
actorId, actorId,
projectId, projectSlug,
actorOrgId, actorOrgId,
environment, environment,
actorAuthMethod actorAuthMethod
}: TListDynamicSecretLeasesDTO) => { }: TListDynamicSecretLeasesDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -233,7 +243,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
); );
@@ -247,10 +257,46 @@ export const dynamicSecretLeaseServiceFactory = ({
return dynamicSecretLeases; return dynamicSecretLeases;
}; };
const getLeaseDetails = async ({
projectSlug,
actorOrgId,
path,
environment,
actor,
actorId,
leaseId,
actorAuthMethod
}: TDetailsDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
return dynamicSecretLease;
};
return { return {
create, create,
listLeases, listLeases,
revokeLease, revokeLease,
renewLease renewLease,
getLeaseDetails
}; };
}; };
@@ -9,23 +9,34 @@ export type TCreateDynamicSecretLeaseDTO = {
path: string; path: string;
environment: string; environment: string;
ttl?: string; ttl?: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDetailsDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretLeasesDTO = { export type TListDynamicSecretLeasesDTO = {
slug: string; slug: string;
path: string; path: string;
environment: string; environment: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretLeaseDTO = { export type TDeleteDynamicSecretLeaseDTO = {
leaseId: string; leaseId: string;
path: string; path: string;
environment: string; environment: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TRenewDynamicSecretLeaseDTO = { export type TRenewDynamicSecretLeaseDTO = {
leaseId: string; leaseId: string;
path: string; path: string;
environment: string; environment: string;
ttl?: string; ttl?: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
@@ -8,6 +8,7 @@ import { BadRequestError } from "@app/lib/errors";
import { TDynamicSecretLeaseDALFactory } from "../dynamic-secret-lease/dynamic-secret-lease-dal"; import { TDynamicSecretLeaseDALFactory } from "../dynamic-secret-lease/dynamic-secret-lease-dal";
import { TDynamicSecretLeaseQueueServiceFactory } from "../dynamic-secret-lease/dynamic-secret-lease-queue"; import { TDynamicSecretLeaseQueueServiceFactory } from "../dynamic-secret-lease/dynamic-secret-lease-queue";
import { TProjectDALFactory } from "../project/project-dal";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TDynamicSecretDALFactory } from "./dynamic-secret-dal"; import { TDynamicSecretDALFactory } from "./dynamic-secret-dal";
import { import {
@@ -26,6 +27,7 @@ type TDynamicSecretServiceFactoryDep = {
dynamicSecretProviders: Record<DynamicSecretProviders, TDynamicProviderFns>; dynamicSecretProviders: Record<DynamicSecretProviders, TDynamicProviderFns>;
dynamicSecretQueueService: Pick<TDynamicSecretLeaseQueueServiceFactory, "pruneDynamicSecret">; dynamicSecretQueueService: Pick<TDynamicSecretLeaseQueueServiceFactory, "pruneDynamicSecret">;
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">; folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
}; };
@@ -37,7 +39,8 @@ export const dynamicSecretServiceFactory = ({
folderDAL, folderDAL,
dynamicSecretProviders, dynamicSecretProviders,
permissionService, permissionService,
dynamicSecretQueueService dynamicSecretQueueService,
projectDAL
}: TDynamicSecretServiceFactoryDep) => { }: TDynamicSecretServiceFactoryDep) => {
const create = async ({ const create = async ({
path, path,
@@ -47,11 +50,15 @@ export const dynamicSecretServiceFactory = ({
maxTTL, maxTTL,
provider, provider,
environment, environment,
projectId, projectSlug,
actorOrgId, actorOrgId,
defaultTTL, defaultTTL,
actorAuthMethod actorAuthMethod
}: TCreateDynamicSecretDTO) => { }: TCreateDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -96,7 +103,7 @@ export const dynamicSecretServiceFactory = ({
defaultTTL, defaultTTL,
inputs, inputs,
environment, environment,
projectId, projectSlug,
path, path,
actor, actor,
actorId, actorId,
@@ -104,6 +111,11 @@ export const dynamicSecretServiceFactory = ({
actorOrgId, actorOrgId,
actorAuthMethod actorAuthMethod
}: TUpdateDynamicSecretDTO) => { }: TUpdateDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -161,11 +173,16 @@ export const dynamicSecretServiceFactory = ({
actorOrgId, actorOrgId,
actorId, actorId,
actor, actor,
projectId, projectSlug,
slug, slug,
path, path,
environment environment
}: TDeleteDynamicSecretDTO) => { }: TDeleteDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -201,7 +218,7 @@ export const dynamicSecretServiceFactory = ({
const getDetails = async ({ const getDetails = async ({
slug, slug,
projectId, projectSlug,
path, path,
environment, environment,
actorAuthMethod, actorAuthMethod,
@@ -209,6 +226,10 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
actor actor
}: TDetailsDynamicSecretDTO) => { }: TDetailsDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -244,10 +265,14 @@ export const dynamicSecretServiceFactory = ({
actorOrgId, actorOrgId,
actorId, actorId,
actor, actor,
projectId, projectSlug,
path, path,
environment environment
}: TListDynamicSecretsDTO) => { }: TListDynamicSecretsDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
@@ -18,7 +18,8 @@ export type TCreateDynamicSecretDTO = {
path: string; path: string;
environment: string; environment: string;
slug: string; slug: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateDynamicSecretDTO = { export type TUpdateDynamicSecretDTO = {
slug: string; slug: string;
@@ -28,21 +29,25 @@ export type TUpdateDynamicSecretDTO = {
path: string; path: string;
environment: string; environment: string;
inputs?: TProvider["inputs"]; inputs?: TProvider["inputs"];
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretDTO = { export type TDeleteDynamicSecretDTO = {
slug: string; slug: string;
path: string; path: string;
environment: string; environment: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDetailsDynamicSecretDTO = { export type TDetailsDynamicSecretDTO = {
slug: string; slug: string;
path: string; path: string;
environment: string; environment: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretsDTO = { export type TListDynamicSecretsDTO = {
path: string; path: string;
environment: string; environment: string;
} & TProjectPermission; projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
@@ -13,7 +13,7 @@ import { DynamicSecretSqlDBSchema, TDynamicProviderFns } from "./models";
const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000; const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000;
const generatePassword = (size?: number) => { const generatePassword = (size?: number) => {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%^&*()_+-=[]{}|;,./<>"; const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*'$#";
return customAlphabet(charset, 20)(size); return customAlphabet(charset, 20)(size);
}; };
@@ -62,7 +62,7 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
await db.raw(creationStatement.toString()); await db.raw(creationStatement.toString());
await db.destroy(); await db.destroy();
return { entityId: username, data: { username, password } }; return { entityId: username, data: { DB_USERNAME: username, DB_PASSWORD: password } };
}; };
const revoke = async (inputs: unknown, entityId: string) => { const revoke = async (inputs: unknown, entityId: string) => {
@@ -21,8 +21,8 @@ export const useCreateDynamicSecret = () => {
); );
return data.dynamicSecret; return data.dynamicSecret;
}, },
onSuccess: (_, { path, environment, projectId }) => { onSuccess: (_, { path, environment, projectSlug }) => {
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectId, environment })); queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environment }));
} }
}); });
}; };
@@ -38,8 +38,8 @@ export const useUpdateDynamicSecret = () => {
); );
return data.dynamicSecret; return data.dynamicSecret;
}, },
onSuccess: (_, { path, environment, projectId }) => { onSuccess: (_, { path, environment, projectSlug }) => {
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectId, environment })); queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environment }));
} }
}); });
}; };
@@ -55,8 +55,8 @@ export const useDeleteDynamicSecret = () => {
); );
return data.dynamicSecret; return data.dynamicSecret;
}, },
onSuccess: (_, { path, environment, projectId }) => { onSuccess: (_, { path, environment, projectSlug }) => {
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectId, environment })); queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environment }));
} }
}); });
}; };
+13 -13
View File
@@ -6,25 +6,25 @@ import { TDetailsDynamicSecretDTO, TDynamicSecret, TListDynamicSecretDTO } from
export const dynamicSecretKeys = { export const dynamicSecretKeys = {
list: ({ list: ({
projectId, projectSlug,
environment, environment,
path path
}: Pick<TListDynamicSecretDTO, "path" | "environment" | "projectId">) => }: Pick<TListDynamicSecretDTO, "path" | "environment" | "projectSlug">) =>
[{ projectId, environment, path }, "dynamic-secrets"] as const, [{ projectSlug, environment, path }, "dynamic-secrets"] as const,
details: ({ path, environment, projectId, slug }: TDetailsDynamicSecretDTO) => details: ({ path, environment, projectSlug, slug }: TDetailsDynamicSecretDTO) =>
[{ projectId, path, environment, slug }, "dynamic-secret-details"] as const [{ projectSlug, path, environment, slug }, "dynamic-secret-details"] as const
}; };
export const useGetDynamicSecrets = ({ projectId, environment, path }: TListDynamicSecretDTO) => { export const useGetDynamicSecrets = ({ projectSlug, environment, path }: TListDynamicSecretDTO) => {
return useQuery({ return useQuery({
queryKey: dynamicSecretKeys.list({ path, environment, projectId }), queryKey: dynamicSecretKeys.list({ path, environment, projectSlug }),
enabled: Boolean(projectId && environment && path), enabled: Boolean(projectSlug && environment && path),
queryFn: async () => { queryFn: async () => {
const { data } = await apiRequest.get<{ dynamicSecrets: TDynamicSecret[] }>( const { data } = await apiRequest.get<{ dynamicSecrets: TDynamicSecret[] }>(
"/api/v1/dynamic-secrets", "/api/v1/dynamic-secrets",
{ {
params: { params: {
projectId, projectSlug,
environment, environment,
path path
} }
@@ -37,20 +37,20 @@ export const useGetDynamicSecrets = ({ projectId, environment, path }: TListDyna
}; };
export const useGetDynamicSecretDetails = ({ export const useGetDynamicSecretDetails = ({
projectId, projectSlug,
environment, environment,
path, path,
slug slug
}: TDetailsDynamicSecretDTO) => { }: TDetailsDynamicSecretDTO) => {
return useQuery({ return useQuery({
queryKey: dynamicSecretKeys.details({ path, environment, projectId, slug }), queryKey: dynamicSecretKeys.details({ path, environment, projectSlug, slug }),
enabled: Boolean(projectId && environment && path && slug), enabled: Boolean(projectSlug && environment && path && slug),
queryFn: async () => { queryFn: async () => {
const { data } = await apiRequest.get<{ const { data } = await apiRequest.get<{
dynamicSecret: TDynamicSecret & { inputs: unknown }; dynamicSecret: TDynamicSecret & { inputs: unknown };
}>(`/api/v1/dynamic-secrets/${slug}`, { }>(`/api/v1/dynamic-secrets/${slug}`, {
params: { params: {
projectId, projectSlug,
environment, environment,
path path
} }
@@ -40,7 +40,7 @@ export type TDynamicSecretProvider = {
}; };
export type TCreateDynamicSecretDTO = { export type TCreateDynamicSecretDTO = {
projectId: string; projectSlug: string;
provider: TDynamicSecretProvider; provider: TDynamicSecretProvider;
defaultTTL: string; defaultTTL: string;
maxTTL?: string; maxTTL?: string;
@@ -51,7 +51,7 @@ export type TCreateDynamicSecretDTO = {
export type TUpdateDynamicSecretDTO = { export type TUpdateDynamicSecretDTO = {
slug: string; slug: string;
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
data: { data: {
@@ -63,20 +63,20 @@ export type TUpdateDynamicSecretDTO = {
}; };
export type TListDynamicSecretDTO = { export type TListDynamicSecretDTO = {
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
}; };
export type TDeleteDynamicSecretDTO = { export type TDeleteDynamicSecretDTO = {
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
slug: string; slug: string;
}; };
export type TDetailsDynamicSecretDTO = { export type TDetailsDynamicSecretDTO = {
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
slug: string; slug: string;
@@ -25,9 +25,9 @@ export const useCreateDynamicSecretLease = () => {
); );
return data; return data;
}, },
onSuccess: (_, { path, environment, projectId, slug }) => { onSuccess: (_, { path, environment, projectSlug, slug }) => {
queryClient.invalidateQueries( queryClient.invalidateQueries(
dynamicSecretLeaseKeys.list({ path, projectId, environment, slug }) dynamicSecretLeaseKeys.list({ path, projectSlug, environment, slug })
); );
} }
}); });
@@ -44,9 +44,9 @@ export const useRenewDynamicSecretLease = () => {
); );
return data.lease; return data.lease;
}, },
onSuccess: (_, { path, environment, projectId, slug }) => { onSuccess: (_, { path, environment, projectSlug, slug }) => {
queryClient.invalidateQueries( queryClient.invalidateQueries(
dynamicSecretLeaseKeys.list({ path, projectId, environment, slug }) dynamicSecretLeaseKeys.list({ path, projectSlug, environment, slug })
); );
} }
}); });
@@ -63,9 +63,9 @@ export const useRevokeDynamicSecretLease = () => {
); );
return data.lease; return data.lease;
}, },
onSuccess: (_, { path, environment, projectId, slug }) => { onSuccess: (_, { path, environment, projectSlug, slug }) => {
queryClient.invalidateQueries( queryClient.invalidateQueries(
dynamicSecretLeaseKeys.list({ path, projectId, environment, slug }) dynamicSecretLeaseKeys.list({ path, projectSlug, environment, slug })
); );
} }
}); });
@@ -5,26 +5,26 @@ import { apiRequest } from "@app/config/request";
import { TDynamicSecretLease, TListDynamicSecretLeaseDTO } from "./types"; import { TDynamicSecretLease, TListDynamicSecretLeaseDTO } from "./types";
export const dynamicSecretLeaseKeys = { export const dynamicSecretLeaseKeys = {
list: ({ projectId, environment, path, slug }: TListDynamicSecretLeaseDTO) => list: ({ projectSlug, environment, path, slug }: TListDynamicSecretLeaseDTO) =>
[{ projectId, environment, path, slug }, "dynamic-secret-leases"] as const [{ projectSlug, environment, path, slug }, "dynamic-secret-leases"] as const
}; };
export const useGetDynamicSecretLeases = ({ export const useGetDynamicSecretLeases = ({
projectId, projectSlug,
environment, environment,
path, path,
slug, slug,
enabled = true enabled = true
}: TListDynamicSecretLeaseDTO) => { }: TListDynamicSecretLeaseDTO) => {
return useQuery({ return useQuery({
queryKey: dynamicSecretLeaseKeys.list({ path, environment, projectId, slug }), queryKey: dynamicSecretLeaseKeys.list({ path, environment, projectSlug, slug }),
enabled: Boolean(projectId && environment && path && slug && enabled), enabled: Boolean(projectSlug && environment && path && slug && enabled),
queryFn: async () => { queryFn: async () => {
const { data } = await apiRequest.get<{ leases: TDynamicSecretLease[] }>( const { data } = await apiRequest.get<{ leases: TDynamicSecretLease[] }>(
`/api/v1/dynamic-secrets/leases/${slug}`, `/api/v1/dynamic-secrets/${slug}/leases`,
{ {
params: { params: {
projectId, projectSlug,
environment, environment,
path path
} }
@@ -15,7 +15,7 @@ export type TDynamicSecretLease = {
export type TCreateDynamicSecretLeaseDTO = { export type TCreateDynamicSecretLeaseDTO = {
slug: string; slug: string;
projectId: string; projectSlug: string;
ttl?: string; ttl?: string;
path: string; path: string;
environment: string; environment: string;
@@ -25,14 +25,14 @@ export type TRenewDynamicSecretLeaseDTO = {
leaseId: string; leaseId: string;
slug: string; slug: string;
ttl?: string; ttl?: string;
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
}; };
export type TListDynamicSecretLeaseDTO = { export type TListDynamicSecretLeaseDTO = {
slug: string; slug: string;
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
enabled?: boolean; enabled?: boolean;
@@ -41,7 +41,7 @@ export type TListDynamicSecretLeaseDTO = {
export type TRevokeDynamicSecretLeaseDTO = { export type TRevokeDynamicSecretLeaseDTO = {
leaseId: string; leaseId: string;
slug: string; slug: string;
projectId: string; projectSlug: string;
path: string; path: string;
environment: string; environment: string;
}; };
@@ -69,6 +69,7 @@ export const SecretMainPage = () => {
// env slug // env slug
const environment = router.query.env as string; const environment = router.query.env as string;
const workspaceId = currentWorkspace?.id || ""; const workspaceId = currentWorkspace?.id || "";
const projectSlug = currentWorkspace?.slug || "";
const secretPath = (router.query.secretPath as string) || "/"; const secretPath = (router.query.secretPath as string) || "/";
const canReadSecret = permission.can( const canReadSecret = permission.can(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
@@ -139,7 +140,7 @@ export const SecretMainPage = () => {
}); });
const { data: dynamicSecrets, isLoading: isDynamicSecretLoading } = useGetDynamicSecrets({ const { data: dynamicSecrets, isLoading: isDynamicSecretLoading } = useGetDynamicSecrets({
projectId: workspaceId, projectSlug,
environment, environment,
path: secretPath path: secretPath
}); });
@@ -258,6 +259,7 @@ export const SecretMainPage = () => {
importedSecrets={importedSecrets} importedSecrets={importedSecrets}
environment={environment} environment={environment}
workspaceId={workspaceId} workspaceId={workspaceId}
projectSlug={projectSlug}
secretPath={secretPath} secretPath={secretPath}
isVisible={isVisible} isVisible={isVisible}
filter={filter} filter={filter}
@@ -316,7 +318,7 @@ export const SecretMainPage = () => {
<DynamicSecretListView <DynamicSecretListView
sortDir={sortDir} sortDir={sortDir}
environment={environment} environment={environment}
workspaceId={workspaceId} projectSlug={projectSlug}
secretPath={secretPath} secretPath={secretPath}
dynamicSecrets={dynamicSecrets || []} dynamicSecrets={dynamicSecrets || []}
/> />
@@ -62,7 +62,9 @@ type Props = {
// swtich the secrets type as it gets decrypted after api call // swtich the secrets type as it gets decrypted after api call
importedSecrets?: Array<Omit<TImportedSecrets, "secrets"> & { secrets: DecryptedSecret[] }>; importedSecrets?: Array<Omit<TImportedSecrets, "secrets"> & { secrets: DecryptedSecret[] }>;
environment: string; environment: string;
// @depreciated will be moving all these details to zustand
workspaceId: string; workspaceId: string;
projectSlug: string;
secretPath?: string; secretPath?: string;
filter: Filter; filter: Filter;
tags?: WsTag[]; tags?: WsTag[];
@@ -81,6 +83,7 @@ export const ActionBar = ({
importedSecrets = [], importedSecrets = [],
environment, environment,
workspaceId, workspaceId,
projectSlug,
secretPath = "/", secretPath = "/",
filter, filter,
tags = [], tags = [],
@@ -443,7 +446,7 @@ export const ActionBar = ({
<CreateDynamicSecretForm <CreateDynamicSecretForm
isOpen={popUp.addDynamicSecret.isOpen} isOpen={popUp.addDynamicSecret.isOpen}
onToggle={(isOpen) => handlePopUpToggle("addDynamicSecret", isOpen)} onToggle={(isOpen) => handlePopUpToggle("addDynamicSecret", isOpen)}
workspaceId={workspaceId} projectSlug={projectSlug}
environment={environment} environment={environment}
secretPath={secretPath} secretPath={secretPath}
/> />
@@ -11,7 +11,7 @@ import { SqlDatabaseInputForm } from "./SqlDatabaseInputForm";
type Props = { type Props = {
isOpen?: boolean; isOpen?: boolean;
onToggle: (isOpen: boolean) => void; onToggle: (isOpen: boolean) => void;
workspaceId: string; projectSlug:string;
environment: string; environment: string;
secretPath: string; secretPath: string;
}; };
@@ -24,7 +24,7 @@ enum WizardSteps {
export const CreateDynamicSecretForm = ({ export const CreateDynamicSecretForm = ({
isOpen, isOpen,
onToggle, onToggle,
workspaceId, projectSlug,
environment, environment,
secretPath secretPath
}: Props) => { }: Props) => {
@@ -92,7 +92,7 @@ export const CreateDynamicSecretForm = ({
<SqlDatabaseInputForm <SqlDatabaseInputForm
onCompleted={handleFormReset} onCompleted={handleFormReset}
onCancel={handleFormReset} onCancel={handleFormReset}
projectId={workspaceId} projectSlug={projectSlug}
secretPath={secretPath} secretPath={secretPath}
environment={environment} environment={environment}
/> />
@@ -58,7 +58,7 @@ type Props = {
onCompleted: () => void; onCompleted: () => void;
onCancel: () => void; onCancel: () => void;
secretPath: string; secretPath: string;
projectId: string; projectSlug: string;
environment: string; environment: string;
}; };
@@ -67,7 +67,7 @@ export const SqlDatabaseInputForm = ({
onCancel, onCancel,
environment, environment,
secretPath, secretPath,
projectId projectSlug
}: Props) => { }: Props) => {
const { const {
control, control,
@@ -89,7 +89,7 @@ export const SqlDatabaseInputForm = ({
slug, slug,
path: secretPath, path: secretPath,
defaultTTL, defaultTTL,
projectId, projectSlug,
environment environment
}); });
onCompleted(); onCompleted();
@@ -13,20 +13,6 @@ import { useTimedReset } from "@app/hooks";
import { useCreateDynamicSecretLease } from "@app/hooks/api"; import { useCreateDynamicSecretLease } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
const formSchema = z.object({
ttl: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number")
});
type TForm = z.infer<typeof formSchema>;
type Props = {
onClose: () => void;
slug: string;
provider: DynamicSecretProviders;
projectId: string;
environment: string;
secretPath: string;
};
const OutputDisplay = ({ const OutputDisplay = ({
value, value,
label, label,
@@ -68,14 +54,14 @@ const OutputDisplay = ({
}; };
const renderOutputForm = (provider: DynamicSecretProviders, data: unknown) => { const renderOutputForm = (provider: DynamicSecretProviders, data: unknown) => {
const { username, password } = data as { username: string; password: string }; const { DB_PASSWORD, DB_USERNAME } = data as { DB_USERNAME: string; DB_PASSWORD: string };
if (provider === DynamicSecretProviders.SqlDatabase) { if (provider === DynamicSecretProviders.SqlDatabase) {
return ( return (
<div> <div>
<OutputDisplay label="Database User" value={username} /> <OutputDisplay label="Database User" value={DB_USERNAME} />
<OutputDisplay <OutputDisplay
label="Database Password" label="Database Password"
value={password} value={DB_PASSWORD}
helperText="Important: Copy this information now. It will disappear after this.opy this values as you won't be able to see it again." helperText="Important: Copy this information now. It will disappear after this.opy this values as you won't be able to see it again."
/> />
</div> </div>
@@ -84,9 +70,23 @@ const renderOutputForm = (provider: DynamicSecretProviders, data: unknown) => {
return null; return null;
}; };
const formSchema = z.object({
ttl: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number")
});
type TForm = z.infer<typeof formSchema>;
type Props = {
onClose: () => void;
slug: string;
provider: DynamicSecretProviders;
projectSlug: string;
environment: string;
secretPath: string;
};
export const CreateDynamicSecretLease = ({ export const CreateDynamicSecretLease = ({
onClose, onClose,
projectId, projectSlug,
slug, slug,
provider, provider,
secretPath, secretPath,
@@ -107,11 +107,11 @@ export const CreateDynamicSecretLease = ({
const createDynamicSecretLease = useCreateDynamicSecretLease(); const createDynamicSecretLease = useCreateDynamicSecretLease();
const handleDynamicSecretLeaseCreate = async ({ ttl }: TForm) => { const handleDynamicSecretLeaseCreate = async ({ ttl }: TForm) => {
if(createDynamicSecretLease.isLoading) return; if (createDynamicSecretLease.isLoading) return;
try { try {
await createDynamicSecretLease.mutateAsync({ await createDynamicSecretLease.mutateAsync({
environment, environment,
projectId, projectSlug,
path: secretPath, path: secretPath,
ttl, ttl,
slug slug
@@ -28,7 +28,7 @@ import { RenewDynamicSecretLease } from "./RenewDynamicSecretLease";
type Props = { type Props = {
slug: string; slug: string;
projectId: string; projectSlug: string;
environment: string; environment: string;
secretPath: string; secretPath: string;
onClickNewLease: () => void; onClickNewLease: () => void;
@@ -36,7 +36,7 @@ type Props = {
}; };
export const DynamicSecretLease = ({ export const DynamicSecretLease = ({
projectId, projectSlug,
slug, slug,
environment, environment,
secretPath, secretPath,
@@ -48,7 +48,7 @@ export const DynamicSecretLease = ({
"renewSecret" "renewSecret"
] as const); ] as const);
const { data: leases, isLoading: isLeaseLoading } = useGetDynamicSecretLeases({ const { data: leases, isLoading: isLeaseLoading } = useGetDynamicSecretLeases({
projectId, projectSlug,
environment, environment,
path: secretPath, path: secretPath,
slug slug
@@ -62,7 +62,7 @@ export const DynamicSecretLease = ({
const { leaseId } = popUp.deleteSecret.data as { leaseId: string }; const { leaseId } = popUp.deleteSecret.data as { leaseId: string };
await deleteDynamicSecretLease.mutateAsync({ await deleteDynamicSecretLease.mutateAsync({
environment, environment,
projectId, projectSlug,
path: secretPath, path: secretPath,
slug, slug,
leaseId leaseId
@@ -193,7 +193,7 @@ export const DynamicSecretLease = ({
<ModalContent title="Renew Lease"> <ModalContent title="Renew Lease">
<RenewDynamicSecretLease <RenewDynamicSecretLease
onClose={() => handlePopUpClose("renewSecret")} onClose={() => handlePopUpClose("renewSecret")}
projectId={projectId} projectSlug={projectSlug}
leaseId={(popUp.renewSecret?.data as { leaseId: string })?.leaseId} leaseId={(popUp.renewSecret?.data as { leaseId: string })?.leaseId}
slug={slug} slug={slug}
secretPath={secretPath} secretPath={secretPath}
@@ -40,7 +40,7 @@ const formatProviderName = (type: DynamicSecretProviders) => {
type Props = { type Props = {
dynamicSecrets: TDynamicSecret[]; dynamicSecrets: TDynamicSecret[];
environment: string; environment: string;
workspaceId: string; projectSlug: string;
secretPath?: string; secretPath?: string;
sortDir: SortDir; sortDir: SortDir;
}; };
@@ -48,7 +48,7 @@ type Props = {
export const DynamicSecretListView = ({ export const DynamicSecretListView = ({
dynamicSecrets = [], dynamicSecrets = [],
environment, environment,
workspaceId, projectSlug,
secretPath = "/", secretPath = "/",
sortDir = SortDir.ASC sortDir = SortDir.ASC
}: Props) => { }: Props) => {
@@ -67,7 +67,7 @@ export const DynamicSecretListView = ({
const { slug } = popUp.deleteDynamicSecret.data as TDynamicSecret; const { slug } = popUp.deleteDynamicSecret.data as TDynamicSecret;
await deleteDynamicSecret.mutateAsync({ await deleteDynamicSecret.mutateAsync({
environment, environment,
projectId: workspaceId, projectSlug,
path: secretPath, path: secretPath,
slug slug
}); });
@@ -206,7 +206,7 @@ export const DynamicSecretListView = ({
<DynamicSecretLease <DynamicSecretLease
onClickNewLease={() => handlePopUpOpen("createDynamicSecretLease", secret)} onClickNewLease={() => handlePopUpOpen("createDynamicSecretLease", secret)}
onClose={() => handlePopUpClose("dynamicSecretLeases")} onClose={() => handlePopUpClose("dynamicSecretLeases")}
projectId={workspaceId} projectSlug={projectSlug}
key={secret.id} key={secret.id}
slug={secret.slug} slug={secret.slug}
secretPath={secretPath} secretPath={secretPath}
@@ -226,7 +226,7 @@ export const DynamicSecretListView = ({
(popUp.createDynamicSecretLease?.data as { type: DynamicSecretProviders })?.type (popUp.createDynamicSecretLease?.data as { type: DynamicSecretProviders })?.type
} }
onClose={() => handlePopUpClose("createDynamicSecretLease")} onClose={() => handlePopUpClose("createDynamicSecretLease")}
projectId={workspaceId} projectSlug={projectSlug}
slug={(popUp.createDynamicSecretLease?.data as { slug: string })?.slug} slug={(popUp.createDynamicSecretLease?.data as { slug: string })?.slug}
secretPath={secretPath} secretPath={secretPath}
environment={environment} environment={environment}
@@ -240,7 +240,7 @@ export const DynamicSecretListView = ({
<ModalContent title="Edit dynamic secret" className="max-w-3xl"> <ModalContent title="Edit dynamic secret" className="max-w-3xl">
<EditDynamicSecretForm <EditDynamicSecretForm
onClose={() => handlePopUpClose("updateDynamicSecret")} onClose={() => handlePopUpClose("updateDynamicSecret")}
projectId={workspaceId} projectSlug={projectSlug}
slug={(popUp.updateDynamicSecret?.data as TDynamicSecret)?.slug} slug={(popUp.updateDynamicSecret?.data as TDynamicSecret)?.slug}
secretPath={secretPath} secretPath={secretPath}
environment={environment} environment={environment}
@@ -9,7 +9,7 @@ import { EditDynamicSecretSqlProviderForm } from "./EditDynamicSecretSqlProvider
type Props = { type Props = {
onClose: () => void; onClose: () => void;
slug: string; slug: string;
projectId: string; projectSlug: string;
environment: string; environment: string;
secretPath: string; secretPath: string;
}; };
@@ -17,13 +17,13 @@ type Props = {
export const EditDynamicSecretForm = ({ export const EditDynamicSecretForm = ({
slug, slug,
environment, environment,
projectId, projectSlug,
onClose, onClose,
secretPath secretPath
}: Props) => { }: Props) => {
const { data: dynamicSecretDetails, isLoading: isDynamicSecretLoading } = const { data: dynamicSecretDetails, isLoading: isDynamicSecretLoading } =
useGetDynamicSecretDetails({ useGetDynamicSecretDetails({
projectId, projectSlug,
environment, environment,
slug, slug,
path: secretPath path: secretPath
@@ -49,7 +49,7 @@ export const EditDynamicSecretForm = ({
> >
<EditDynamicSecretSqlProviderForm <EditDynamicSecretSqlProviderForm
onClose={onClose} onClose={onClose}
projectId={projectId} projectSlug={projectSlug}
secretPath={secretPath} secretPath={secretPath}
dynamicSecret={dynamicSecretDetails} dynamicSecret={dynamicSecretDetails}
environment={environment} environment={environment}
@@ -61,8 +61,8 @@ type Props = {
onClose: () => void; onClose: () => void;
dynamicSecret: TDynamicSecret & { inputs: unknown }; dynamicSecret: TDynamicSecret & { inputs: unknown };
secretPath: string; secretPath: string;
projectId: string;
environment: string; environment: string;
projectSlug: string;
}; };
export const EditDynamicSecretSqlProviderForm = ({ export const EditDynamicSecretSqlProviderForm = ({
@@ -70,7 +70,7 @@ export const EditDynamicSecretSqlProviderForm = ({
dynamicSecret, dynamicSecret,
environment, environment,
secretPath, secretPath,
projectId projectSlug
}: Props) => { }: Props) => {
const { const {
control, control,
@@ -97,7 +97,7 @@ export const EditDynamicSecretSqlProviderForm = ({
await updateDynamicSecret.mutateAsync({ await updateDynamicSecret.mutateAsync({
slug: dynamicSecret.slug, slug: dynamicSecret.slug,
path: secretPath, path: secretPath,
projectId, projectSlug,
environment, environment,
data: { data: {
maxTTL: maxTTL || undefined, maxTTL: maxTTL || undefined,
@@ -25,14 +25,14 @@ type Props = {
onClose: () => void; onClose: () => void;
leaseId: string; leaseId: string;
slug: string; slug: string;
projectId: string; projectSlug: string;
environment: string; environment: string;
secretPath: string; secretPath: string;
}; };
export const RenewDynamicSecretLease = ({ export const RenewDynamicSecretLease = ({
onClose, onClose,
projectId, projectSlug,
slug, slug,
leaseId, leaseId,
secretPath, secretPath,
@@ -57,7 +57,7 @@ export const RenewDynamicSecretLease = ({
try { try {
await renewDynamicSecretLease.mutateAsync({ await renewDynamicSecretLease.mutateAsync({
environment, environment,
projectId, projectSlug,
path: secretPath, path: secretPath,
ttl, ttl,
slug, slug,