Revert "feat(api/secrets): view secret value permission"

This commit is contained in:
Maidul Islam
2025-03-05 14:15:02 -05:00
committed by GitHub
parent 8e82813894
commit bf6cfbac7a
70 changed files with 806 additions and 2202 deletions
@@ -7,7 +7,6 @@ import {
ProjectRolesSchema,
ProjectsSchema,
SecretApprovalPoliciesSchema,
SecretTagsSchema,
UsersSchema
} from "@app/db/schemas";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@@ -233,11 +232,3 @@ export const SanitizedProjectSchema = ProjectsSchema.pick({
kmsCertificateKeyId: true,
auditLogsRetentionDays: true
});
export const SanitizedTagSchema = SecretTagsSchema.pick({
id: true,
slug: true,
color: true
}).extend({
name: z.string()
});
@@ -1,11 +1,10 @@
import { ForbiddenError, subject } from "@casl/ability";
import { z } from "zod";
import { ActionProjectType, SecretFoldersSchema, SecretImportsSchema } from "@app/db/schemas";
import { ActionProjectType, SecretFoldersSchema, SecretImportsSchema, SecretTagsSchema } from "@app/db/schemas";
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import {
ProjectPermissionDynamicSecretActions,
ProjectPermissionSecretActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { DASHBOARD } from "@app/lib/api-docs";
@@ -16,7 +15,7 @@ import { secretsLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { getUserAgentType } from "@app/server/plugins/audit-log";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { SanitizedDynamicSecretSchema, SanitizedTagSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas";
import { SanitizedDynamicSecretSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas";
import { AuthMode } from "@app/services/auth/auth-type";
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
import { SecretsOrderBy } from "@app/services/secret/secret-types";
@@ -117,10 +116,16 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
dynamicSecrets: SanitizedDynamicSecretSchema.extend({ environment: z.string() }).array().optional(),
secrets: secretRawSchema
.extend({
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional()
})
.array()
.optional(),
@@ -289,7 +294,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
if (remainingLimit > 0 && totalSecretCount > adjustedOffset) {
secrets = await server.services.secret.getSecretsRawMultiEnv({
viewSecretValue: true,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
@@ -389,7 +393,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
.optional(),
search: z.string().trim().describe(DASHBOARD.SECRET_DETAILS_LIST.search).optional(),
tags: z.string().trim().transform(decodeURIComponent).describe(DASHBOARD.SECRET_DETAILS_LIST.tags).optional(),
viewSecretValue: booleanSchema.default(true),
includeSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeSecrets),
includeFolders: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeFolders),
includeDynamicSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeDynamicSecrets),
@@ -407,10 +410,16 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
dynamicSecrets: SanitizedDynamicSecretSchema.array().optional(),
secrets: secretRawSchema
.extend({
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional()
})
.array()
.optional(),
@@ -592,25 +601,23 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
});
if (remainingLimit > 0 && totalSecretCount > adjustedOffset) {
secrets = (
await server.services.secret.getSecretsRaw({
actorId: req.permission.id,
actor: req.permission.type,
viewSecretValue: req.query.viewSecretValue,
throwOnMissingReadValuePermission: false,
actorOrgId: req.permission.orgId,
environment,
actorAuthMethod: req.permission.authMethod,
projectId,
path: secretPath,
orderBy,
orderDirection,
search,
limit: remainingLimit,
offset: adjustedOffset,
tagSlugs: tags
})
).secrets;
const secretsRaw = await server.services.secret.getSecretsRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment,
actorAuthMethod: req.permission.authMethod,
projectId,
path: secretPath,
orderBy,
orderDirection,
search,
limit: remainingLimit,
offset: adjustedOffset,
tagSlugs: tags
});
secrets = secretsRaw.secrets;
await server.services.auditLog.createAuditLog({
projectId,
@@ -689,10 +696,16 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
.optional(),
secrets: secretRawSchema
.extend({
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional()
})
.array()
.optional()
@@ -736,7 +749,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.getSecretsRawByFolderMappings(
{
filterByAction: ProjectPermissionSecretActions.DescribeSecret,
projectId,
folderMappings,
filters: {
@@ -850,17 +862,22 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
projectId: z.string().trim(),
environment: z.string().trim(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
keys: z.string().trim().transform(decodeURIComponent),
viewSecretValue: booleanSchema.default(false)
keys: z.string().trim().transform(decodeURIComponent)
}),
response: {
200: z.object({
secrets: secretRawSchema
.extend({
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional()
})
.array()
.optional()
@@ -869,7 +886,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { secretPath, projectId, environment, viewSecretValue } = req.query;
const { secretPath, projectId, environment } = req.query;
const keys = req.query.keys?.split(",").filter((key) => Boolean(key.trim())) ?? [];
if (!keys.length) throw new BadRequestError({ message: "One or more keys required" });
@@ -878,7 +895,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
viewSecretValue,
environment,
actorAuthMethod: req.permission.authMethod,
projectId,
@@ -94,7 +94,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
iv: z.string().trim(),
tag: z.string().trim(),
expiresIn: z.number().nullable(),
permissions: z.enum(["read", "write", "readValue"]).array()
permissions: z.enum(["read", "write"]).array()
}),
response: {
200: z.object({
+91 -57
View File
@@ -1,7 +1,13 @@
import picomatch from "picomatch";
import { z } from "zod";
import { SecretApprovalRequestsSchema, SecretsSchema, SecretType, ServiceTokenScopes } from "@app/db/schemas";
import {
SecretApprovalRequestsSchema,
SecretsSchema,
SecretTagsSchema,
SecretType,
ServiceTokenScopes
} from "@app/db/schemas";
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import { RAW_SECRETS, SECRETS } from "@app/lib/api-docs";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
@@ -17,7 +23,7 @@ import { SecretOperations, SecretProtectionType } from "@app/services/secret/sec
import { SecretUpdateMode } from "@app/services/secret-v2-bridge/secret-v2-bridge-types";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { SanitizedTagSchema, secretRawSchema } from "../sanitizedSchemas";
import { secretRawSchema } from "../sanitizedSchemas";
const SecretReferenceNode = z.object({
key: z.string(),
@@ -25,14 +31,6 @@ const SecretReferenceNode = z.object({
environment: z.string(),
secretPath: z.string()
});
const convertStringBoolean = (defaultValue: boolean = false) => {
return z
.enum(["true", "false"])
.default(defaultValue ? "true" : "false")
.transform((value) => value === "true");
};
type TSecretReferenceNode = z.infer<typeof SecretReferenceNode> & { children: TSecretReferenceNode[] };
const SecretReferenceNodeTree: z.ZodType<TSecretReferenceNode> = SecretReferenceNode.extend({
@@ -77,9 +75,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).extend({
tags: SanitizedTagSchema.array()
})
secret: SecretsSchema.omit({ secretBlindIndex: true }).merge(
z.object({
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
})
)
})
}
},
@@ -133,7 +139,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).extend({
tags: SanitizedTagSchema.array()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
})
})
}
@@ -235,10 +247,21 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceSlug: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceSlug),
environment: z.string().trim().optional().describe(RAW_SECRETS.LIST.environment),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.LIST.secretPath),
viewSecretValue: convertStringBoolean(true).describe(RAW_SECRETS.LIST.viewSecretValue),
expandSecretReferences: convertStringBoolean().describe(RAW_SECRETS.LIST.expand),
recursive: convertStringBoolean().describe(RAW_SECRETS.LIST.recursive),
include_imports: convertStringBoolean().describe(RAW_SECRETS.LIST.includeImports),
expandSecretReferences: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.LIST.expand),
recursive: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.LIST.recursive),
include_imports: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.LIST.includeImports),
tagSlugs: z
.string()
.describe(RAW_SECRETS.LIST.tagSlugs)
@@ -251,9 +274,15 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secrets: secretRawSchema
.extend({
secretPath: z.string().optional(),
secretValueHidden: z.boolean(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional()
})
.array(),
imports: z
@@ -264,7 +293,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secrets: secretRawSchema
.omit({ createdAt: true, updatedAt: true })
.extend({
secretValueHidden: z.boolean(),
secretMetadata: ResourceMetadataSchema.optional()
})
.array()
@@ -314,7 +342,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
expandSecretReferences: req.query.expandSecretReferences,
actorAuthMethod: req.permission.authMethod,
projectId: workspaceId,
viewSecretValue: req.query.viewSecretValue,
path: secretPath,
metadataFilter: req.query.metadataFilter,
includeImports: req.query.include_imports,
@@ -349,7 +376,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
}
});
}
return { secrets, imports };
}
});
@@ -377,15 +403,28 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath),
version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.GET.type),
viewSecretValue: convertStringBoolean(true).describe(RAW_SECRETS.GET.viewSecretValue),
expandSecretReferences: convertStringBoolean().describe(RAW_SECRETS.GET.expand),
include_imports: convertStringBoolean().describe(RAW_SECRETS.GET.includeImports)
expandSecretReferences: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.GET.expand),
include_imports: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.GET.includeImports)
}),
response: {
200: z.object({
secret: secretRawSchema.extend({
secretValueHidden: z.boolean(),
tags: SanitizedTagSchema.array().optional(),
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
.optional(),
secretMetadata: ResourceMetadataSchema.optional()
})
})
@@ -417,7 +456,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
expandSecretReferences: req.query.expandSecretReferences,
environment,
projectId: workspaceId,
viewSecretValue: req.query.viewSecretValue,
projectSlug: workspaceSlug,
path: secretPath,
secretName: req.params.secretName,
@@ -624,9 +662,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secret: secretRawSchema.extend({
secretValueHidden: z.boolean()
})
secret: secretRawSchema
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -722,9 +758,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secret: secretRawSchema.extend({
secretValueHidden: z.boolean()
})
secret: secretRawSchema
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -746,7 +780,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
if (secretOperation.type === SecretProtectionType.Approval) {
return { approval: secretOperation.approval };
}
const { secret } = secretOperation;
await server.services.auditLog.createAuditLog({
@@ -809,7 +842,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspace: z.string(),
environment: z.string(),
secretPath: z.string().optional(),
tags: SanitizedTagSchema.array()
tags: SecretTagsSchema.pick({
id: true,
slug: true,
color: true
})
.extend({ name: z.string() })
.array()
})
.array(),
imports: z
@@ -905,7 +944,10 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
type: z.nativeEnum(SecretType).default(SecretType.Shared),
version: z.coerce.number().optional(),
include_imports: convertStringBoolean()
include_imports: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
}),
response: {
200: z.object({
@@ -1176,7 +1218,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).merge(
z.object({
secretValueHidden: z.boolean(),
_id: z.string(),
workspace: z.string(),
environment: z.string()
@@ -1346,12 +1387,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).extend({
_id: z.string(),
secretValueHidden: z.boolean(),
workspace: z.string(),
environment: z.string()
})
secret: SecretsSchema.omit({ secretBlindIndex: true }).merge(
z.object({
_id: z.string(),
workspace: z.string(),
environment: z.string()
})
)
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -1663,7 +1705,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).extend({ secretValueHidden: z.boolean() }).array()
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -1778,11 +1820,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true })
.extend({
secretValueHidden: z.boolean()
})
.array()
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -2044,7 +2082,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secrets: secretRawSchema.extend({ secretValueHidden: z.boolean() }).array()
secrets: secretRawSchema.array()
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])
@@ -2166,11 +2204,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.union([
z.object({
secrets: secretRawSchema
.extend({
secretValueHidden: z.boolean()
})
.array()
secrets: secretRawSchema.array()
}),
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
])