mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 06:28:11 +00:00
Merge pull request #3293 from Infisical/feat/addRecursiveSearchToFoldersGetEndpoint
Add recursive flag to folders get endpoint to retrieve all nested folders
This commit is contained in:
@@ -631,7 +631,8 @@ export const FOLDERS = {
|
|||||||
workspaceId: "The ID of the project to list folders from.",
|
workspaceId: "The ID of the project to list folders from.",
|
||||||
environment: "The slug of the environment to list folders from.",
|
environment: "The slug of the environment to list folders from.",
|
||||||
path: "The path to list folders from.",
|
path: "The path to list folders from.",
|
||||||
directory: "The directory to list folders from. (Deprecated in favor of path)"
|
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."
|
||||||
},
|
},
|
||||||
GET_BY_ID: {
|
GET_BY_ID: {
|
||||||
folderId: "The ID of the folder to get details."
|
folderId: "The ID of the folder to get details."
|
||||||
|
|||||||
@@ -70,6 +70,19 @@ export const DefaultResponseErrorsSchema = {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const booleanSchema = z
|
||||||
|
.union([z.boolean(), z.string().trim()])
|
||||||
|
.transform((value) => {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
// ie if not empty, 0 or false, return true
|
||||||
|
return Boolean(value) && Number(value) !== 0 && value.toLowerCase() !== "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.default(true);
|
||||||
|
|
||||||
export const sapPubSchema = SecretApprovalPoliciesSchema.merge(
|
export const sapPubSchema = SecretApprovalPoliciesSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
environment: z.object({
|
environment: z.object({
|
||||||
|
|||||||
@@ -16,7 +16,12 @@ import { secretsLimit } from "@app/server/config/rateLimiter";
|
|||||||
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||||
import { getUserAgentType } from "@app/server/plugins/audit-log";
|
import { getUserAgentType } from "@app/server/plugins/audit-log";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedDynamicSecretSchema, SanitizedTagSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas";
|
import {
|
||||||
|
booleanSchema,
|
||||||
|
SanitizedDynamicSecretSchema,
|
||||||
|
SanitizedTagSchema,
|
||||||
|
secretRawSchema
|
||||||
|
} from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
|
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
||||||
@@ -24,20 +29,6 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
|||||||
|
|
||||||
const MAX_DEEP_SEARCH_LIMIT = 500; // arbitrary limit to prevent excessive results
|
const MAX_DEEP_SEARCH_LIMIT = 500; // arbitrary limit to prevent excessive results
|
||||||
|
|
||||||
// handle querystring boolean values
|
|
||||||
const booleanSchema = z
|
|
||||||
.union([z.boolean(), z.string().trim()])
|
|
||||||
.transform((value) => {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
// ie if not empty, 0 or false, return true
|
|
||||||
return Boolean(value) && Number(value) !== 0 && value.toLowerCase() !== "false";
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
.default(true);
|
|
||||||
|
|
||||||
const parseSecretPathSearch = (search?: string) => {
|
const parseSecretPathSearch = (search?: string) => {
|
||||||
if (!search)
|
if (!search)
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { readLimit, secretsLimit } from "@app/server/config/rateLimiter";
|
|||||||
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 { booleanSchema } from "../sanitizedSchemas";
|
||||||
|
|
||||||
export const registerSecretFolderRouter = async (server: FastifyZodProvider) => {
|
export const registerSecretFolderRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
url: "/",
|
url: "/",
|
||||||
@@ -347,11 +349,14 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
.default("/")
|
.default("/")
|
||||||
.transform(prefixWithSlash)
|
.transform(prefixWithSlash)
|
||||||
.transform(removeTrailingSlash)
|
.transform(removeTrailingSlash)
|
||||||
.describe(FOLDERS.LIST.directory)
|
.describe(FOLDERS.LIST.directory),
|
||||||
|
recursive: booleanSchema.default(false).describe(FOLDERS.LIST.recursive)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
folders: SecretFoldersSchema.array()
|
folders: SecretFoldersSchema.extend({
|
||||||
|
relativePath: z.string().optional()
|
||||||
|
}).array()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -401,7 +401,8 @@ export const secretFolderServiceFactory = ({
|
|||||||
orderBy,
|
orderBy,
|
||||||
orderDirection,
|
orderDirection,
|
||||||
limit,
|
limit,
|
||||||
offset
|
offset,
|
||||||
|
recursive
|
||||||
}: TGetFolderDTO) => {
|
}: TGetFolderDTO) => {
|
||||||
// folder list is allowed to be read by anyone
|
// folder list is allowed to be read by anyone
|
||||||
// permission to check does user has access
|
// permission to check does user has access
|
||||||
@@ -420,6 +421,17 @@ export const secretFolderServiceFactory = ({
|
|||||||
const parentFolder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
const parentFolder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||||
if (!parentFolder) return [];
|
if (!parentFolder) return [];
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
const recursiveFolders = await folderDAL.findByEnvsDeep({ parentIds: [parentFolder.id] });
|
||||||
|
// remove the parent folder
|
||||||
|
return recursiveFolders
|
||||||
|
.filter((folder) => folder.id !== parentFolder.id)
|
||||||
|
.map((folder) => ({
|
||||||
|
...folder,
|
||||||
|
relativePath: folder.path
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
const folders = await folderDAL.find(
|
const folders = await folderDAL.find(
|
||||||
{
|
{
|
||||||
envId: env.id,
|
envId: env.id,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export type TGetFolderDTO = {
|
|||||||
orderDirection?: OrderByDirection;
|
orderDirection?: OrderByDirection;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
recursive?: boolean;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TGetFolderByIdDTO = {
|
export type TGetFolderByIdDTO = {
|
||||||
|
|||||||
Reference in New Issue
Block a user