From 22402772439667f10fa2dc7624711bb55618ac97 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:40:45 +0100 Subject: [PATCH 1/9] Feat: Standalone tags documentation --- backend/src/lib/api-docs/constants.ts | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 2e42f3388..2ecd9d81e 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -194,6 +194,25 @@ export const FOLDERS = { } } as const; +export const SECRETS = { + ATTACH_TAGS: { + secretName: "The name of the secret to attach tags to.", + secretPath: "The path of the secret to attach tags to.", + type: "The type of the secret to attach tags to. (shared/personal)", + environment: "The slug of the environment where the secret is located", + projectSlug: "The slug of the project where the secret is located", + tagSlugs: "An array of tag slugs to attach to the secret." + }, + DETACH_TAGS: { + secretName: "The name of the secret to detach tags from.", + secretPath: "The path of the secret to detach tags from.", + type: "The type of the secret to attach tags to. (shared/personal)", + environment: "The slug of the environment where the secret is located", + projectSlug: "The slug of the project where the secret is located", + tagSlugs: "An array of tag slugs to detach from the secret." + } +} as const; + export const RAW_SECRETS = { LIST: { workspaceId: "The ID of the project to list secrets from.", @@ -222,6 +241,7 @@ export const RAW_SECRETS = { includeImports: "Weather to include imported secrets or not." }, UPDATE: { + tags: "An array of tag IDs to attach to the secret.", secretName: "The name of the secret to update.", environment: "The slug of the environment where the secret is located.", secretPath: "The path of the secret to update", @@ -285,3 +305,19 @@ export const AUDIT_LOGS = { actor: "The actor to filter the audit logs by." } } as const; + +export const SECRET_TAGS = { + LIST: { + projectId: "The ID of the project to list tags from." + }, + CREATE: { + projectId: "The ID of the project to create the tag in.", + name: "The name of the tag to create.", + slug: "The slug of the tag to create.", + color: "The color of the tag to create." + }, + DELETE: { + tagId: "The ID of the tag to delete.", + projectId: "The ID of the project to delete the tag from." + } +} as const; From b606990dfb6401118ffc2d0c8153ae5f65130b01 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:41:12 +0100 Subject: [PATCH 2/9] Update secret-tag-router.ts --- backend/src/server/routes/v1/secret-tag-router.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/src/server/routes/v1/secret-tag-router.ts b/backend/src/server/routes/v1/secret-tag-router.ts index c60f2b9ba..519b257ae 100644 --- a/backend/src/server/routes/v1/secret-tag-router.ts +++ b/backend/src/server/routes/v1/secret-tag-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { SecretTagsSchema } from "@app/db/schemas"; +import { SECRET_TAGS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -10,7 +11,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { method: "GET", schema: { params: z.object({ - projectId: z.string().trim() + projectId: z.string().trim().describe(SECRET_TAGS.LIST.projectId) }), response: { 200: z.object({ @@ -36,12 +37,12 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { method: "POST", schema: { params: z.object({ - projectId: z.string().trim() + projectId: z.string().trim().describe(SECRET_TAGS.CREATE.projectId) }), body: z.object({ - name: z.string().trim(), - slug: z.string().trim(), - color: z.string() + name: z.string().trim().describe(SECRET_TAGS.CREATE.name), + slug: z.string().trim().describe(SECRET_TAGS.CREATE.slug), + color: z.string().trim().describe(SECRET_TAGS.CREATE.color) }), response: { 200: z.object({ @@ -68,8 +69,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { method: "DELETE", schema: { params: z.object({ - projectId: z.string().trim(), - tagId: z.string().trim() + projectId: z.string().trim().describe(SECRET_TAGS.DELETE.projectId), + tagId: z.string().trim().describe(SECRET_TAGS.DELETE.tagId) }), response: { 200: z.object({ From b23deca8e457df1f036e9b29fd2207c233a2e969 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:42:32 +0100 Subject: [PATCH 3/9] Feat: Attach/Detach tags to secret --- backend/src/server/routes/v3/secret-router.ts | 120 +++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index 1e224aa3b..f69466328 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -10,7 +10,7 @@ import { } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; -import { RAW_SECRETS } from "@app/lib/api-docs"; +import { RAW_SECRETS, SECRETS } from "@app/lib/api-docs"; import { BadRequestError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -23,6 +23,124 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; import { secretRawSchema } from "../sanitizedSchemas"; export const registerSecretRouter = async (server: FastifyZodProvider) => { + server.route({ + url: "/tags/:secretName", + method: "POST", + schema: { + description: "Attach tags to a secret", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: z.string().trim().describe(SECRETS.ATTACH_TAGS.secretName) + }), + body: z.object({ + projectSlug: z.string().trim().describe(SECRETS.ATTACH_TAGS.projectSlug), + environment: z.string().trim().describe(SECRETS.ATTACH_TAGS.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(SECRETS.ATTACH_TAGS.secretPath), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(SECRETS.ATTACH_TAGS.type), + tagSlugs: z.string().array().min(1).describe(SECRETS.ATTACH_TAGS.tagSlugs) + }), + response: { + 200: z.object({ + secret: SecretsSchema.omit({ secretBlindIndex: true }).merge( + z.object({ + tags: SecretTagsSchema.pick({ + id: true, + slug: true, + name: true, + color: true + }).array() + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secret = await server.services.secret.attachTags({ + secretName: req.params.secretName, + tagSlugs: req.body.tagSlugs, + path: req.body.secretPath, + environment: req.body.environment, + type: req.body.type, + projectSlug: req.body.projectSlug, + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId + }); + + return { secret }; + } + }); + + server.route({ + url: "/tags/:secretName", + method: "DELETE", + schema: { + description: "Detach tags from a secret", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: z.string().trim().describe(SECRETS.DETACH_TAGS.secretName) + }), + body: z.object({ + projectSlug: z.string().trim().describe(SECRETS.DETACH_TAGS.projectSlug), + environment: z.string().trim().describe(SECRETS.DETACH_TAGS.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(SECRETS.DETACH_TAGS.secretPath), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(SECRETS.DETACH_TAGS.type), + tagSlugs: z.string().array().min(1).describe(SECRETS.DETACH_TAGS.tagSlugs) + }), + response: { + 200: z.object({ + secret: SecretsSchema.omit({ secretBlindIndex: true }).merge( + z.object({ + tags: SecretTagsSchema.pick({ + id: true, + slug: true, + name: true, + color: true + }).array() + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secret = await server.services.secret.detachTags({ + secretName: req.params.secretName, + tagSlugs: req.body.tagSlugs, + path: req.body.secretPath, + environment: req.body.environment, + type: req.body.type, + projectSlug: req.body.projectSlug, + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId + }); + + return { secret }; + } + }); + server.route({ url: "/raw", method: "GET", From f7122c21fd62b3d50e046a01eca3b38596d5000b Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:43:08 +0100 Subject: [PATCH 4/9] Fix: Allow query function to be called with undefined orgId, and handle it as an error --- backend/src/services/project/project-dal.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/services/project/project-dal.ts b/backend/src/services/project/project-dal.ts index 369e005ac..4f4225344 100644 --- a/backend/src/services/project/project-dal.ts +++ b/backend/src/services/project/project-dal.ts @@ -168,8 +168,12 @@ export const projectDALFactory = (db: TDbClient) => { } }; - const findProjectBySlug = async (slug: string, orgId: string) => { + const findProjectBySlug = async (slug: string, orgId: string | undefined) => { try { + if (!orgId) { + throw new BadRequestError({ message: "Organization ID is required when querying with slugs" }); + } + const projects = await db(TableName.ProjectMembership) .where(`${TableName.Project}.slug`, slug) .where(`${TableName.Project}.orgId`, orgId) From cfb497dd5801df6b8697637a217d6a7966ebd58a Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:47:23 +0100 Subject: [PATCH 5/9] Feat: Get secret tags by secret ID --- backend/src/services/secret/secret-dal.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/backend/src/services/secret/secret-dal.ts b/backend/src/services/secret/secret-dal.ts index 11cd522ca..504174765 100644 --- a/backend/src/services/secret/secret-dal.ts +++ b/backend/src/services/secret/secret-dal.ts @@ -150,6 +150,27 @@ export const secretDALFactory = (db: TDbClient) => { } }; + const getSecretTags = async (secretId: string, tx?: Knex) => { + try { + const tags = await (tx || db)(TableName.JnSecretTag) + .join(TableName.SecretTag, `${TableName.JnSecretTag}.${TableName.SecretTag}Id`, `${TableName.SecretTag}.id`) + .where({ [`${TableName.Secret}Id` as const]: secretId }) + .select(db.ref("id").withSchema(TableName.SecretTag).as("tagId")) + .select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor")) + .select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug")) + .select(db.ref("name").withSchema(TableName.SecretTag).as("tagName")); + + return tags.map((el) => ({ + id: el.tagId, + color: el.tagColor, + slug: el.tagSlug, + name: el.tagName + })); + } catch (error) { + throw new DatabaseError({ error, name: "get secret tags" }); + } + }; + const findByBlindIndexes = async ( folderId: string, blindIndexes: Array<{ blindIndex: string; type: SecretType }>, @@ -184,6 +205,7 @@ export const secretDALFactory = (db: TDbClient) => { bulkUpdate, deleteMany, bulkUpdateNoVersionIncrement, + getSecretTags, findByFolderId, findByBlindIndexes }; From f7c2d38aefb6946c69820ce6e4a8ff3633caeb9c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:48:14 +0100 Subject: [PATCH 6/9] Feat: (Standalone) Attach / Detach tags from secrets --- backend/src/services/secret/secret-service.ts | 207 +++++++++++++++++- backend/src/services/secret/secret-types.ts | 9 + 2 files changed, 215 insertions(+), 1 deletion(-) diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index f47428fc7..e3b57802f 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -22,6 +22,7 @@ import { TSecretDALFactory } from "./secret-dal"; import { decryptSecretRaw, fnSecretBlindIndexCheck, fnSecretBulkInsert, fnSecretBulkUpdate } from "./secret-fns"; import { TSecretQueueFactory } from "./secret-queue"; import { + TAttachSecretTagsDTO, TCreateBulkSecretDTO, TCreateSecretDTO, TCreateSecretRawDTO, @@ -47,7 +48,7 @@ type TSecretServiceFactoryDep = { secretTagDAL: TSecretTagDALFactory; secretVersionDAL: TSecretVersionDALFactory; folderDAL: Pick; - projectDAL: Pick; + projectDAL: Pick; secretBlindIndexDAL: TSecretBlindIndexDALFactory; permissionService: Pick; snapshotService: Pick; @@ -307,6 +308,7 @@ export const secretServiceFactory = ({ if ((inputSecret.tags || []).length !== tags.length) throw new BadRequestError({ message: "Tag not found" }); const { secretName, ...el } = inputSecret; + const updatedSecret = await secretDAL.transaction(async (tx) => fnSecretBulkUpdate({ folderId, @@ -442,6 +444,7 @@ export const secretServiceFactory = ({ const folderId = folder.id; const secrets = await secretDAL.findByFolderId(folderId, actorId); + if (includeImports) { const secretImports = await secretImportDAL.find({ folderId }); const allowedImports = secretImports.filter(({ importEnv, importPath }) => @@ -994,7 +997,209 @@ export const secretServiceFactory = ({ return secretVersions; }; + const attachTags = async ({ + secretName, + tagSlugs, + path: secretPath, + environment, + type, + projectSlug, + actor, + actorAuthMethod, + actorOrgId, + actorId + }: TAttachSecretTagsDTO) => { + const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); + + const { permission } = await permissionService.getProjectPermission( + actor, + actorId, + project.id, + actorAuthMethod, + actorOrgId + ); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Edit, + subject(ProjectPermissionSub.Secrets, { environment, secretPath }) + ); + + await projectDAL.checkProjectUpgradeStatus(project.id); + + const secret = await getSecretByName({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + projectId: project.id, + environment, + path: secretPath, + secretName, + type + }); + + if (!secret) { + throw new BadRequestError({ message: "Secret not found" }); + } + const folder = await folderDAL.findBySecretPath(project.id, environment, secretPath); + + if (!folder) { + throw new BadRequestError({ message: "Folder not found" }); + } + + const tags = await secretTagDAL.find({ + projectId: project.id, + $in: { + slug: tagSlugs + } + }); + + if (tags.length !== tagSlugs.length) { + throw new BadRequestError({ message: "One or more tags not found." }); + } + + const secretTags = await secretDAL.getSecretTags(secret.id); + + if (secretTags.some((tag) => tagSlugs.includes(tag.slug))) { + throw new BadRequestError({ message: "One or more tags already exist on the secret" }); + } + + const combinedTags = new Set([...secretTags.map((tag) => tag.id), ...tags.map((el) => el.id)]); + + const updatedSecret = await secretDAL.transaction(async (tx) => + fnSecretBulkUpdate({ + folderId: folder.id, + projectId: project.id, + inputSecrets: [ + { + filter: { id: secret.id }, + data: { + tags: Array.from(combinedTags) + } + } + ], + secretDAL, + secretVersionDAL, + secretTagDAL, + secretVersionTagDAL, + tx + }) + ); + + await snapshotService.performSnapshot(folder.id); + await secretQueueService.syncSecrets({ secretPath, projectId: project.id, environment }); + + return { + ...updatedSecret[0], + tags: [...secretTags, ...tags].map((t) => ({ id: t.id, slug: t.slug, name: t.name, color: t.color })) + }; + }; + + const detachTags = async ({ + secretName, + tagSlugs, + path: secretPath, + environment, + type, + projectSlug, + actor, + actorAuthMethod, + actorOrgId, + actorId + }: TAttachSecretTagsDTO) => { + const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); + + const { permission } = await permissionService.getProjectPermission( + actor, + actorId, + project.id, + actorAuthMethod, + actorOrgId + ); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Edit, + subject(ProjectPermissionSub.Secrets, { environment, secretPath }) + ); + + await projectDAL.checkProjectUpgradeStatus(project.id); + + const secret = await getSecretByName({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + projectId: project.id, + environment, + path: secretPath, + secretName, + type + }); + + if (!secret) { + throw new BadRequestError({ message: "Secret not found" }); + } + const folder = await folderDAL.findBySecretPath(project.id, environment, secretPath); + + if (!folder) { + throw new BadRequestError({ message: "Folder not found" }); + } + + const tags = await secretTagDAL.find({ + projectId: project.id, + $in: { + slug: tagSlugs + } + }); + + if (tags.length !== tagSlugs.length) { + throw new BadRequestError({ message: "One or more tags not found." }); + } + + const secretTags = await secretDAL.getSecretTags(secret.id); + + // Make sure all the tags exist on the secret + const tagIdsToRemove = tags.map((tag) => tag.id); + const secretTagIds = secretTags.map((tag) => tag.id); + + if (!tagIdsToRemove.every((el) => secretTagIds.includes(el))) { + throw new BadRequestError({ message: "One or more tags not found on the secret" }); + } + + const newTags = secretTags.filter((tag) => !tagIdsToRemove.includes(tag.id)); + + const updatedSecret = await secretDAL.transaction(async (tx) => + fnSecretBulkUpdate({ + folderId: folder.id, + projectId: project.id, + inputSecrets: [ + { + filter: { id: secret.id }, + data: { + tags: newTags.map((tag) => tag.id) + } + } + ], + secretDAL, + secretVersionDAL, + secretTagDAL, + secretVersionTagDAL, + tx + }) + ); + + await snapshotService.performSnapshot(folder.id); + await secretQueueService.syncSecrets({ secretPath, projectId: project.id, environment }); + + return { + ...updatedSecret[0], + tags: newTags + }; + }; + return { + attachTags, + detachTags, createSecret, deleteSecret, updateSecret, diff --git a/backend/src/services/secret/secret-types.ts b/backend/src/services/secret/secret-types.ts index 7ad4d65d7..efd4f0f8b 100644 --- a/backend/src/services/secret/secret-types.ts +++ b/backend/src/services/secret/secret-types.ts @@ -206,6 +206,15 @@ export type TFnSecretBulkUpdate = { tx?: Knex; }; +export type TAttachSecretTagsDTO = { + projectSlug: string; + secretName: string; + tagSlugs: string[]; + environment: string; + path: string; + type: SecretType; +} & Omit; + export type TFnSecretBulkDelete = { folderId: string; projectId: string; From e7c2f6f88c435c4925fa91e0a90281b14ee67847 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:48:54 +0100 Subject: [PATCH 7/9] Docs: Expose tags endpoints --- docs/api-reference/endpoints/secret-tags/create.mdx | 4 ++++ docs/api-reference/endpoints/secret-tags/delete.mdx | 4 ++++ docs/api-reference/endpoints/secret-tags/list.mdx | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 docs/api-reference/endpoints/secret-tags/create.mdx create mode 100644 docs/api-reference/endpoints/secret-tags/delete.mdx create mode 100644 docs/api-reference/endpoints/secret-tags/list.mdx diff --git a/docs/api-reference/endpoints/secret-tags/create.mdx b/docs/api-reference/endpoints/secret-tags/create.mdx new file mode 100644 index 000000000..82d0eed17 --- /dev/null +++ b/docs/api-reference/endpoints/secret-tags/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create" +openapi: "POST /api/v1/workspace/{projectId}/tags" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/secret-tags/delete.mdx b/docs/api-reference/endpoints/secret-tags/delete.mdx new file mode 100644 index 000000000..cc98f03c2 --- /dev/null +++ b/docs/api-reference/endpoints/secret-tags/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v1/workspace/{projectId}/tags/{tagId}" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/secret-tags/list.mdx b/docs/api-reference/endpoints/secret-tags/list.mdx new file mode 100644 index 000000000..c4a940f77 --- /dev/null +++ b/docs/api-reference/endpoints/secret-tags/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v1/workspace/{projectId}/tags" +--- \ No newline at end of file From f91c77baa3714fa5041a257b76414fa6ca3fa299 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:53:39 +0100 Subject: [PATCH 8/9] Docs: Attach / Detach tags --- docs/api-reference/endpoints/secrets/attach-tags.mdx | 4 ++++ docs/api-reference/endpoints/secrets/detach-tags.mdx | 4 ++++ docs/mint.json | 12 +++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 docs/api-reference/endpoints/secrets/attach-tags.mdx create mode 100644 docs/api-reference/endpoints/secrets/detach-tags.mdx diff --git a/docs/api-reference/endpoints/secrets/attach-tags.mdx b/docs/api-reference/endpoints/secrets/attach-tags.mdx new file mode 100644 index 000000000..8dd0e6081 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/attach-tags.mdx @@ -0,0 +1,4 @@ +--- +title: "Attach tags" +openapi: "POST /api/v3/secrets/tags/{secretName}" +--- diff --git a/docs/api-reference/endpoints/secrets/detach-tags.mdx b/docs/api-reference/endpoints/secrets/detach-tags.mdx new file mode 100644 index 000000000..a74b1174e --- /dev/null +++ b/docs/api-reference/endpoints/secrets/detach-tags.mdx @@ -0,0 +1,4 @@ +--- +title: "Detach tags" +openapi: "DELETE /api/v3/secrets/tags/{secretName}" +--- \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index 732c0f036..625974241 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -467,6 +467,14 @@ "api-reference/endpoints/folders/delete" ] }, + { + "group": "Secret tags", + "pages": [ + "api-reference/endpoints/secret-tags/list", + "api-reference/endpoints/secret-tags/create", + "api-reference/endpoints/secret-tags/delete" + ] + }, { "group": "Secrets", "pages": [ @@ -474,7 +482,9 @@ "api-reference/endpoints/secrets/create", "api-reference/endpoints/secrets/read", "api-reference/endpoints/secrets/update", - "api-reference/endpoints/secrets/delete" + "api-reference/endpoints/secrets/delete", + "api-reference/endpoints/secrets/attach-tags", + "api-reference/endpoints/secrets/detach-tags" ] }, { From c52a16cc4792a3ea4d07d760170199b456f7a275 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:56:53 +0100 Subject: [PATCH 9/9] Update constants.ts --- backend/src/lib/api-docs/constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 2ecd9d81e..cd4ee6ff7 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -241,7 +241,6 @@ export const RAW_SECRETS = { includeImports: "Weather to include imported secrets or not." }, UPDATE: { - tags: "An array of tag IDs to attach to the secret.", secretName: "The name of the secret to update.", environment: "The slug of the environment where the secret is located.", secretPath: "The path of the secret to update",