Merge pull request #3315 from akhilmhdh/feat/folder-last-secret-modified

Folder last secret commit feature
This commit is contained in:
Maidul Islam
2025-04-01 10:08:50 -04:00
committed by GitHub
7 changed files with 48 additions and 4 deletions

View File

@@ -0,0 +1,21 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasCol = await knex.schema.hasColumn(TableName.SecretFolder, "lastSecretModified");
if (!hasCol) {
await knex.schema.alterTable(TableName.SecretFolder, (t) => {
t.datetime("lastSecretModified");
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasCol = await knex.schema.hasColumn(TableName.SecretFolder, "lastSecretModified");
if (hasCol) {
await knex.schema.alterTable(TableName.SecretFolder, (t) => {
t.dropColumn("lastSecretModified");
});
}
}

View File

@@ -16,7 +16,8 @@ export const SecretFoldersSchema = z.object({
envId: z.string().uuid(),
parentId: z.string().uuid().nullable().optional(),
isReserved: z.boolean().default(false).nullable().optional(),
description: z.string().nullable().optional()
description: z.string().nullable().optional(),
lastSecretModified: z.date().nullable().optional()
});
export type TSecretFolders = z.infer<typeof SecretFoldersSchema>;

View File

@@ -632,7 +632,8 @@ export const FOLDERS = {
environment: "The slug of the environment to list folders from.",
path: "The path to list folders from.",
directory: "The directory to list folders from. (Deprecated in favor of path)",
recursive: "Whether or not to fetch all folders from the specified base path, and all of its subdirectories."
recursive: "Whether or not to fetch all folders from the specified base path, and all of its subdirectories.",
lastSecretModified: "The timestamp used to filter folders with secrets modified after the specified date. The format for this timestamp is ISO 8601 (e.g. 2025-04-01T09:41:45-04:00)"
},
GET_BY_ID: {
folderId: "The ID of the folder to get details."

View File

@@ -335,6 +335,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
querystring: z.object({
workspaceId: z.string().trim().describe(FOLDERS.LIST.workspaceId),
environment: z.string().trim().describe(FOLDERS.LIST.environment),
lastSecretModified: z.string().datetime().trim().optional().describe(FOLDERS.LIST.lastSecretModified),
path: z
.string()
.trim()

View File

@@ -402,7 +402,8 @@ export const secretFolderServiceFactory = ({
orderDirection,
limit,
offset,
recursive
recursive,
lastSecretModified
}: TGetFolderDTO) => {
// folder list is allowed to be read by anyone
// permission to check does user has access
@@ -425,7 +426,16 @@ export const secretFolderServiceFactory = ({
const recursiveFolders = await folderDAL.findByEnvsDeep({ parentIds: [parentFolder.id] });
// remove the parent folder
return recursiveFolders
.filter((folder) => folder.id !== parentFolder.id)
.filter((folder) => {
if (lastSecretModified) {
if (!folder.lastSecretModified) return false;
if (folder.lastSecretModified < new Date(lastSecretModified)) {
return false;
}
}
return folder.id !== parentFolder.id;
})
.map((folder) => ({
...folder,
relativePath: folder.path
@@ -445,6 +455,11 @@ export const secretFolderServiceFactory = ({
offset
}
);
if (lastSecretModified) {
return folders.filter((el) =>
el.lastSecretModified ? el.lastSecretModified >= new Date(lastSecretModified) : false
);
}
return folders;
};

View File

@@ -46,6 +46,7 @@ export type TGetFolderDTO = {
limit?: number;
offset?: number;
recursive?: boolean;
lastSecretModified?: string;
} & TProjectPermission;
export type TGetFolderByIdDTO = {

View File

@@ -646,6 +646,10 @@ export const secretQueueFactory = ({
}
);
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
if (!folder) return;
await folderDAL.updateById(folder.id, { lastSecretModified: new Date() });
await secretSyncQueue.queueSecretSyncsSyncSecretsByPath({ projectId, environmentSlug: environment, secretPath });
await syncIntegrations({ secretPath, projectId, environment, deDupeQueue, isManual: false });