fix(view-secret-value): requested changes

This commit is contained in:
Daniel Hougaard
2025-03-11 00:31:21 +04:00
parent 09df440613
commit 78c349c09a
18 changed files with 273 additions and 205 deletions
@@ -14,7 +14,7 @@ import {
SecretSubjectFields SecretSubjectFields
} from "./project-permission"; } from "./project-permission";
export function CheckForbiddenErrorSecretsSubject( export function throwIfMissingSecretReadValueOrDescribePermission(
permission: MongoAbility<ProjectPermissionSet> | PureAbility, permission: MongoAbility<ProjectPermissionSet> | PureAbility,
action: Extract< action: Extract<
ProjectPermissionSecretActions, ProjectPermissionSecretActions,
@@ -43,7 +43,7 @@ export function CheckForbiddenErrorSecretsSubject(
} }
} }
export function CheckCanSecretsSubject( export function hasSecretReadValueOrDescribePermission(
permission: MongoAbility<ProjectPermissionSet>, permission: MongoAbility<ProjectPermissionSet>,
action: Extract< action: Extract<
ProjectPermissionSecretActions, ProjectPermissionSecretActions,
@@ -83,12 +83,10 @@ export function checkForInvalidPermissionCombination(permissions: z.infer<typeof
if (!hasReadValue && !hasDescribeSecret) return; if (!hasReadValue && !hasDescribeSecret) return;
const hasBothDescribeAndReadValue = const hasBothDescribeAndReadValue = hasReadValue && hasDescribeSecret;
permission.action.includes(ProjectPermissionSecretActions.DescribeSecret) &&
permission.action.includes(ProjectPermissionSecretActions.ReadValue);
throw new BadRequestError({ throw new BadRequestError({
message: `You have selected Full Read Access, and ${ message: `You have selected Read, and ${
hasBothDescribeAndReadValue hasBothDescribeAndReadValue
? "both Read Value and Describe Secret" ? "both Read Value and Describe Secret"
: hasReadValue : hasReadValue
@@ -96,7 +94,7 @@ export function checkForInvalidPermissionCombination(permissions: z.infer<typeof
: hasDescribeSecret : hasDescribeSecret
? "Describe Secret" ? "Describe Secret"
: "" : ""
}. You cannot select Read Value or Describe Secret if you have selected Full Read Access.` }. You cannot select Read Value or Describe Secret if you have selected Read. The Read permission is a legacy action which has been replaced by Describe Secret and Read Value.`
}); });
} }
} }
@@ -565,7 +565,7 @@ const buildAdminPermissionRules = () => {
can( can(
[ [
// not adding DescribeAndReadValue, because it's already covered by DescribeSecret and ReadValue ProjectPermissionSecretActions.DescribeAndReadValue,
ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSecretActions.DescribeSecret,
ProjectPermissionSecretActions.ReadValue, ProjectPermissionSecretActions.ReadValue,
ProjectPermissionSecretActions.Create, ProjectPermissionSecretActions.Create,
@@ -634,7 +634,7 @@ const buildMemberPermissionRules = () => {
can( can(
[ [
// not adding DescribeAndReadValue, because it's already covered by DescribeSecret and ReadValue ProjectPermissionSecretActions.DescribeAndReadValue,
ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSecretActions.DescribeSecret,
ProjectPermissionSecretActions.ReadValue, ProjectPermissionSecretActions.ReadValue,
ProjectPermissionSecretActions.Edit, ProjectPermissionSecretActions.Edit,
@@ -811,7 +811,7 @@ export const projectMemberPermissions = buildMemberPermissionRules();
const buildViewerPermissionRules = () => { const buildViewerPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility); const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
// not adding DescribeAndReadValue, because it's already covered by DescribeSecret and ReadValue can(ProjectPermissionSecretActions.DescribeAndReadValue, ProjectPermissionSub.Secrets);
can(ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSub.Secrets); can(ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSub.Secrets);
can(ProjectPermissionSecretActions.ReadValue, ProjectPermissionSub.Secrets); can(ProjectPermissionSecretActions.ReadValue, ProjectPermissionSub.Secrets);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders); can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders);
@@ -77,7 +77,7 @@ import {
TSecretApprovalDetailsDTO, TSecretApprovalDetailsDTO,
TStatusChangeDTO TStatusChangeDTO
} from "./secret-approval-request-types"; } from "./secret-approval-request-types";
import { CheckForbiddenErrorSecretsSubject } from "../permission/permission-fns"; import { throwIfMissingSecretReadValueOrDescribePermission } from "../permission/permission-fns";
type TSecretApprovalRequestServiceFactoryDep = { type TSecretApprovalRequestServiceFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
@@ -919,7 +919,7 @@ export const secretApprovalRequestServiceFactory = ({
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath secretPath
}); });
@@ -23,7 +23,10 @@ import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secre
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal"; import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
import { TLicenseServiceFactory } from "../license/license-service"; import { TLicenseServiceFactory } from "../license/license-service";
import { CheckCanSecretsSubject, CheckForbiddenErrorSecretsSubject } from "../permission/permission-fns"; import {
hasSecretReadValueOrDescribePermission,
throwIfMissingSecretReadValueOrDescribePermission
} from "../permission/permission-fns";
import { TPermissionServiceFactory } from "../permission/permission-service"; import { TPermissionServiceFactory } from "../permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -103,7 +106,7 @@ export const secretSnapshotServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder. // We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath: path secretPath: path
}); });
@@ -140,7 +143,7 @@ export const secretSnapshotServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder. // We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath: path secretPath: path
}); });
@@ -187,12 +190,16 @@ export const secretSnapshotServiceFactory = ({
snapshotDetails = { snapshotDetails = {
...encryptedSnapshotDetails, ...encryptedSnapshotDetails,
secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => { secretVersions: encryptedSnapshotDetails.secretVersions.map((el) => {
const canReadValue = CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const canReadValue = hasSecretReadValueOrDescribePermission(
environment: encryptedSnapshotDetails.environment.slug, permission,
secretPath: fullFolderPath, ProjectPermissionSecretActions.ReadValue,
secretName: el.key, {
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined environment: encryptedSnapshotDetails.environment.slug,
}); secretPath: fullFolderPath,
secretName: el.key,
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined
}
);
let secretValue = ""; let secretValue = "";
if (canReadValue) { if (canReadValue) {
@@ -236,12 +243,16 @@ export const secretSnapshotServiceFactory = ({
key: botKey key: botKey
}); });
const canReadValue = CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const canReadValue = hasSecretReadValueOrDescribePermission(
environment: encryptedSnapshotDetails.environment.slug, permission,
secretPath: fullFolderPath, ProjectPermissionSecretActions.ReadValue,
secretName: secretKey, {
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined environment: encryptedSnapshotDetails.environment.slug,
}); secretPath: fullFolderPath,
secretName: secretKey,
secretTags: el.tags.length ? el.tags.map((tag) => tag.slug) : undefined
}
);
let secretValue = ""; let secretValue = "";
@@ -1,7 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas"; import { ActionProjectType } from "@app/db/schemas";
import { CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -96,7 +96,7 @@ export const integrationServiceFactory = ({
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: sourceEnvironment, environment: sourceEnvironment,
secretPath secretPath
}); });
@@ -176,7 +176,7 @@ export const integrationServiceFactory = ({
const newSecretPath = secretPath || integration.secretPath; const newSecretPath = secretPath || integration.secretPath;
if (environment || secretPath) { if (environment || secretPath) {
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: newEnvironment, environment: newEnvironment,
secretPath: newSecretPath secretPath: newSecretPath
}); });
@@ -10,7 +10,7 @@ import {
} from "@app/db/schemas"; } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -765,7 +765,7 @@ export const projectServiceFactory = ({
actorOrgId, actorOrgId,
actionProjectType: ActionProjectType.Any actionProjectType: ActionProjectType.Any
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret);
const project = await projectDAL.findProjectById(projectId); const project = await projectDAL.findProjectById(projectId);
@@ -4,7 +4,10 @@ import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType, TableName } from "@app/db/schemas"; import { ActionProjectType, TableName } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { CheckCanSecretsSubject, CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import {
hasSecretReadValueOrDescribePermission,
throwIfMissingSecretReadValueOrDescribePermission
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -94,7 +97,7 @@ export const secretImportServiceFactory = ({
); );
// check if user has permission to import from target path // check if user has permission to import from target path
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment: data.environment, environment: data.environment,
secretPath: data.path secretPath: data.path
}); });
@@ -404,7 +407,7 @@ export const secretImportServiceFactory = ({
if (!secretImportDoc.isReplication) throw new BadRequestError({ message: "Import is not in replication mode" }); if (!secretImportDoc.isReplication) throw new BadRequestError({ message: "Import is not in replication mode" });
// check if user has permission to import from target path // check if user has permission to import from target path
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment: secretImportDoc.importEnv.slug, environment: secretImportDoc.importEnv.slug,
secretPath: secretImportDoc.importPath secretPath: secretImportDoc.importPath
}); });
@@ -595,7 +598,7 @@ export const secretImportServiceFactory = ({
// so anything based on this order will also be in right position // so anything based on this order will also be in right position
const secretImports = await secretImportDAL.find({ folderId: folder.id, isReplication: false }); const secretImports = await secretImportDAL.find({ folderId: folder.id, isReplication: false });
const allowedImports = secretImports.filter((el) => const allowedImports = secretImports.filter((el) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: el.importEnv.slug, environment: el.importEnv.slug,
secretPath: el.importPath secretPath: el.importPath
}) })
@@ -645,7 +648,7 @@ export const secretImportServiceFactory = ({
secretImportDAL, secretImportDAL,
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""), decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""),
hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: expandEnvironment, environment: expandEnvironment,
secretPath: expandSecretPath, secretPath: expandSecretPath,
secretName: expandSecretKey, secretName: expandSecretKey,
@@ -663,7 +666,7 @@ export const secretImportServiceFactory = ({
}); });
const allowedImports = secretImports.filter((el) => const allowedImports = secretImports.filter((el) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: el.importEnv.slug, environment: el.importEnv.slug,
secretPath: el.importPath secretPath: el.importPath
}) })
@@ -1,7 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas"; import { ActionProjectType } from "@app/db/schemas";
import { CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionSecretActions, ProjectPermissionSecretActions,
@@ -179,7 +179,7 @@ export const secretSyncServiceFactory = ({
ProjectPermissionSub.SecretSyncs ProjectPermissionSub.SecretSyncs
); );
CheckForbiddenErrorSecretsSubject(projectPermission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(projectPermission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath secretPath
}); });
@@ -267,7 +267,7 @@ export const secretSyncServiceFactory = ({
if (!updatedEnvironment || !updatedSecretPath) if (!updatedEnvironment || !updatedSecretPath)
throw new BadRequestError({ message: "Must specify both source environment and secret path" }); throw new BadRequestError({ message: "Must specify both source environment and secret path" });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: updatedEnvironment, environment: updatedEnvironment,
secretPath: updatedSecretPath secretPath: updatedSecretPath
}); });
@@ -10,7 +10,10 @@ import {
TableName, TableName,
TSecretsV2 TSecretsV2
} from "@app/db/schemas"; } from "@app/db/schemas";
import { CheckCanSecretsSubject, CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import {
hasSecretReadValueOrDescribePermission,
throwIfMissingSecretReadValueOrDescribePermission
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -197,7 +200,7 @@ export const secretV2BridgeServiceFactory = ({
const referredSecretsGroupBySecretKey = groupBy(referredSecrets, (i) => i.key); const referredSecretsGroupBySecretKey = groupBy(referredSecrets, (i) => i.key);
references.forEach((el) => { references.forEach((el) => {
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: el.environment, environment: el.environment,
secretPath: el.secretPath, secretPath: el.secretPath,
secretName: el.secretKey, secretName: el.secretKey,
@@ -542,14 +545,18 @@ export const secretV2BridgeServiceFactory = ({
}); });
} }
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath, ProjectPermissionSecretActions.ReadValue,
secretName: inputSecret.secretName, {
...(tagsToCheck.length && { environment,
secretTags: tagsToCheck.map((el) => el.slug) secretPath,
}) secretName: inputSecret.secretName,
}); ...(tagsToCheck.length && {
secretTags: tagsToCheck.map((el) => el.slug)
})
}
);
return reshapeBridgeSecret( return reshapeBridgeSecret(
projectId, projectId,
@@ -650,12 +657,16 @@ export const secretV2BridgeServiceFactory = ({
projectId projectId
}); });
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath, ProjectPermissionSecretActions.ReadValue,
secretName: secretToDelete.key, {
secretTags: secretToDelete.tags?.map((el) => el.slug) environment,
}); secretPath,
secretName: secretToDelete.key,
secretTags: secretToDelete.tags?.map((el) => el.slug)
}
);
return reshapeBridgeSecret( return reshapeBridgeSecret(
projectId, projectId,
@@ -698,7 +709,7 @@ export const secretV2BridgeServiceFactory = ({
actorOrgId, actorOrgId,
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret);
} }
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environments, path); const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environments, path);
@@ -744,7 +755,7 @@ export const secretV2BridgeServiceFactory = ({
actorOrgId, actorOrgId,
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret);
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) return 0; if (!folder) return 0;
@@ -779,37 +790,27 @@ export const secretV2BridgeServiceFactory = ({
}); });
const decryptedSecrets = secrets const decryptedSecrets = secrets
.filter((el) => { .filter((el) =>
if ( hasSecretReadValueOrDescribePermission(projectPermission, filterByAction, {
filterByAction === ProjectPermissionSecretActions.ReadValue || environment: groupedFolderMappings[el.folderId][0].environment,
filterByAction === ProjectPermissionSecretActions.DescribeSecret secretPath: groupedFolderMappings[el.folderId][0].path,
) { secretName: el.key,
return CheckCanSecretsSubject(projectPermission, filterByAction, { secretTags: el.tags.map((i) => i.slug)
environment: groupedFolderMappings[el.folderId][0].environment, })
secretPath: groupedFolderMappings[el.folderId][0].path, )
secretName: el.key,
secretTags: el.tags.map((i) => i.slug)
});
}
return projectPermission.can(
filterByAction,
subject(ProjectPermissionSub.Secrets, {
environment: groupedFolderMappings[el.folderId][0].environment,
secretPath: groupedFolderMappings[el.folderId][0].path,
secretName: el.key,
secretTags: el.tags.map((i) => i.slug)
})
);
})
.map((secret) => { .map((secret) => {
// Note(Daniel): This is only relevant if the filterAction isn't set to ReadValue. This is needed for the frontend. // Note(Daniel): This is only relevant if the filterAction isn't set to ReadValue. This is needed for the frontend.
const secretValueHidden = !CheckCanSecretsSubject(projectPermission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment: groupedFolderMappings[secret.folderId][0].environment, projectPermission,
secretPath: groupedFolderMappings[secret.folderId][0].path, ProjectPermissionSecretActions.ReadValue,
secretName: secret.key, {
secretTags: secret.tags.map((i) => i.slug) environment: groupedFolderMappings[secret.folderId][0].environment,
}); secretPath: groupedFolderMappings[secret.folderId][0].path,
secretName: secret.key,
secretTags: secret.tags.map((i) => i.slug)
}
);
return reshapeBridgeSecret( return reshapeBridgeSecret(
projectId, projectId,
@@ -855,7 +856,7 @@ export const secretV2BridgeServiceFactory = ({
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
if (!isInternal) { if (!isInternal) {
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret);
} }
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environments, path); const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environments, path);
@@ -907,7 +908,7 @@ export const secretV2BridgeServiceFactory = ({
actorOrgId, actorOrgId,
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath: path, secretPath: path,
secretTags: params.tagSlugs secretTags: params.tagSlugs
@@ -950,12 +951,16 @@ export const secretV2BridgeServiceFactory = ({
const decryptedSecrets = secrets const decryptedSecrets = secrets
.filter((el) => { .filter((el) => {
const canDescribeSecret = CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { const canDescribeSecret = hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: groupedPaths[el.folderId][0].path, ProjectPermissionSecretActions.DescribeSecret,
secretName: el.key, {
secretTags: el.tags.map((i) => i.slug) environment,
}); secretPath: groupedPaths[el.folderId][0].path,
secretName: el.key,
secretTags: el.tags.map((i) => i.slug)
}
);
if (!canDescribeSecret) { if (!canDescribeSecret) {
return false; return false;
@@ -964,7 +969,7 @@ export const secretV2BridgeServiceFactory = ({
if (viewSecretValue) { if (viewSecretValue) {
// Recursive secret, should be filtered out // Recursive secret, should be filtered out
if (groupedPaths[el.folderId][0].path !== path) { if (groupedPaths[el.folderId][0].path !== path) {
const canReadRecursiveSecretValue = CheckCanSecretsSubject( const canReadRecursiveSecretValue = hasSecretReadValueOrDescribePermission(
permission, permission,
ProjectPermissionSecretActions.ReadValue, ProjectPermissionSecretActions.ReadValue,
{ {
@@ -981,7 +986,7 @@ export const secretV2BridgeServiceFactory = ({
} }
if (throwOnMissingReadValuePermission) { if (throwOnMissingReadValuePermission) {
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: groupedPaths[el.folderId][0].path, secretPath: groupedPaths[el.folderId][0].path,
secretName: el.key, secretName: el.key,
@@ -999,7 +1004,7 @@ export const secretV2BridgeServiceFactory = ({
const secretValueHidden = const secretValueHidden =
!viewSecretValue || !viewSecretValue ||
!CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { !hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: groupedPaths[secret.folderId][0].path, secretPath: groupedPaths[secret.folderId][0].path,
secretName: secret.key, secretName: secret.key,
@@ -1029,7 +1034,7 @@ export const secretV2BridgeServiceFactory = ({
secretDAL, secretDAL,
decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined), decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined),
canExpandValue: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => canExpandValue: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: expandEnvironment, environment: expandEnvironment,
secretPath: expandSecretPath, secretPath: expandSecretPath,
secretName: expandSecretKey, secretName: expandSecretKey,
@@ -1074,19 +1079,27 @@ export const secretV2BridgeServiceFactory = ({
expandSecretReferences, expandSecretReferences,
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""), decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""),
hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => { hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => {
const canDescribe = CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { const canDescribe = hasSecretReadValueOrDescribePermission(
environment: expandEnvironment, permission,
secretPath: expandSecretPath, ProjectPermissionSecretActions.DescribeSecret,
secretName: expandSecretKey, {
secretTags: expandSecretTags environment: expandEnvironment,
}); secretPath: expandSecretPath,
secretName: expandSecretKey,
secretTags: expandSecretTags
}
);
const canReadValue = CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const canReadValue = hasSecretReadValueOrDescribePermission(
environment: expandEnvironment, permission,
secretPath: expandSecretPath, ProjectPermissionSecretActions.ReadValue,
secretName: expandSecretKey, {
secretTags: expandSecretTags environment: expandEnvironment,
}); secretPath: expandSecretPath,
secretName: expandSecretKey,
secretTags: expandSecretTags
}
);
return viewSecretValue ? canDescribe && canReadValue : canDescribe; return viewSecretValue ? canDescribe && canReadValue : canDescribe;
} }
@@ -1128,7 +1141,7 @@ export const secretV2BridgeServiceFactory = ({
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: folderWithPath.environmentSlug, environment: folderWithPath.environmentSlug,
secretPath: folderWithPath.path, secretPath: folderWithPath.path,
secretName: secret.key, secretName: secret.key,
@@ -1240,7 +1253,7 @@ export const secretV2BridgeServiceFactory = ({
}) })
)); ));
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath: path, secretPath: path,
secretName, secretName,
@@ -1255,7 +1268,7 @@ export const secretV2BridgeServiceFactory = ({
secretDAL, secretDAL,
decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined), decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined),
canExpandValue: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => { canExpandValue: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => {
return CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { return hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: expandEnvironment, environment: expandEnvironment,
secretPath: expandSecretPath, secretPath: expandSecretPath,
secretName: expandSecretKey, secretName: expandSecretKey,
@@ -1280,7 +1293,7 @@ export const secretV2BridgeServiceFactory = ({
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""), decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : ""),
expandSecretReferences: shouldExpandSecretReferences ? expandSecretReferences : undefined, expandSecretReferences: shouldExpandSecretReferences ? expandSecretReferences : undefined,
hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => { hasSecretAccess: (expandEnvironment, expandSecretPath, expandSecretKey, expandSecretTags) => {
return CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { return hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment: expandEnvironment, environment: expandEnvironment,
secretPath: expandSecretPath, secretPath: expandSecretPath,
secretName: expandSecretKey, secretName: expandSecretKey,
@@ -1297,7 +1310,7 @@ export const secretV2BridgeServiceFactory = ({
if (viewSecretValue) { if (viewSecretValue) {
if ( if (
!CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { !hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: importedSecret.environment, environment: importedSecret.environment,
secretPath: importedSecrets[i].secretPath, secretPath: importedSecrets[i].secretPath,
secretName: importedSecret.key, secretName: importedSecret.key,
@@ -1350,7 +1363,7 @@ export const secretV2BridgeServiceFactory = ({
if (viewSecretValue) { if (viewSecretValue) {
if ( if (
!CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { !hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: path, secretPath: path,
secretName, secretName,
@@ -1523,12 +1536,16 @@ export const secretV2BridgeServiceFactory = ({
}); });
return newSecrets.map((el) => { return newSecrets.map((el) => {
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath, ProjectPermissionSecretActions.ReadValue,
secretName: el.key, {
secretTags: el.tags?.map((i) => i.slug) environment,
}); secretPath,
secretName: el.key,
secretTags: el.tags?.map((i) => i.slug)
}
);
return reshapeBridgeSecret( return reshapeBridgeSecret(
projectId, projectId,
@@ -1857,12 +1874,16 @@ export const secretV2BridgeServiceFactory = ({
); );
return updatedSecrets.map((el) => { return updatedSecrets.map((el) => {
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: el.secretPath, ProjectPermissionSecretActions.ReadValue,
secretName: el.key, {
secretTags: el.tags.map((i) => i.slug) environment,
}); secretPath: el.secretPath,
secretName: el.key,
secretTags: el.tags.map((i) => i.slug)
}
);
return { return {
...reshapeBridgeSecret( ...reshapeBridgeSecret(
@@ -1987,7 +2008,7 @@ export const secretV2BridgeServiceFactory = ({
const secretValueHidden = const secretValueHidden =
!secretToDeleteMatch || !secretToDeleteMatch ||
!CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { !hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath, secretPath,
secretName: el.key, secretName: el.key,
@@ -2049,14 +2070,18 @@ export const secretV2BridgeServiceFactory = ({
sort: [["createdAt", "desc"]] sort: [["createdAt", "desc"]]
}); });
return secretVersions.map((el) => { return secretVersions.map((el) => {
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment: folder.environment.envSlug, permission,
secretPath: folderWithPath.path, ProjectPermissionSecretActions.ReadValue,
secretName: el.key, {
...(el.tags?.length && { environment: folder.environment.envSlug,
secretTags: el.tags.map((tag) => tag.slug) secretPath: folderWithPath.path,
}) secretName: el.key,
}); ...(el.tags?.length && {
secretTags: el.tags.map((tag) => tag.slug)
})
}
);
return reshapeBridgeSecret( return reshapeBridgeSecret(
folder.projectId, folder.projectId,
@@ -2178,7 +2203,7 @@ export const secretV2BridgeServiceFactory = ({
sourceAction === ProjectPermissionSecretActions.DescribeSecret || sourceAction === ProjectPermissionSecretActions.DescribeSecret ||
sourceAction === ProjectPermissionSecretActions.ReadValue sourceAction === ProjectPermissionSecretActions.ReadValue
) { ) {
CheckForbiddenErrorSecretsSubject(permission, sourceAction, { throwIfMissingSecretReadValueOrDescribePermission(permission, sourceAction, {
environment: sourceEnvironment, environment: sourceEnvironment,
secretPath: sourceSecretPath, secretPath: sourceSecretPath,
secretName: secret.key, secretName: secret.key,
@@ -2517,7 +2542,7 @@ export const secretV2BridgeServiceFactory = ({
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath secretPath
}); });
@@ -2541,7 +2566,7 @@ export const secretV2BridgeServiceFactory = ({
type: SecretType.Shared type: SecretType.Shared
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.DescribeSecret, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
environment, environment,
secretPath, secretPath,
secretName, secretName,
@@ -2558,7 +2583,7 @@ export const secretV2BridgeServiceFactory = ({
secretDAL, secretDAL,
decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined), decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined),
canExpandValue: (expandEnvironment, expandSecretPath, expandSecretName, expandSecretTags) => canExpandValue: (expandEnvironment, expandSecretPath, expandSecretName, expandSecretTags) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: expandEnvironment, environment: expandEnvironment,
secretPath: expandSecretPath, secretPath: expandSecretPath,
secretName: expandSecretName, secretName: expandSecretName,
@@ -2567,7 +2592,7 @@ export const secretV2BridgeServiceFactory = ({
}); });
if ( if (
!CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { !hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath, secretPath,
secretName, secretName,
@@ -349,5 +349,5 @@ export type TGetSecretsRawByFolderMappingsDTO = {
folderMappings: { folderId: string; path: string; environment: string }[]; folderMappings: { folderId: string; path: string; environment: string }[];
userId: string; userId: string;
filters: TFindSecretsByFolderIdsFilter; filters: TFindSecretsByFolderIdsFilter;
filterByAction?: ProjectPermissionSecretActions; filterByAction?: ProjectPermissionSecretActions.DescribeSecret | ProjectPermissionSecretActions.ReadValue;
}; };
+2 -2
View File
@@ -11,7 +11,7 @@ import {
TSecretFolders, TSecretFolders,
TSecrets TSecrets
} from "@app/db/schemas"; } from "@app/db/schemas";
import { CheckCanSecretsSubject } from "@app/ee/services/permission/permission-fns"; import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionSecretActions } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionSecretActions } from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
@@ -191,7 +191,7 @@ export const recursivelyGetSecretPaths = ({
// Filter out paths that the user does not have permission to access, and paths that are not in the current path // Filter out paths that the user does not have permission to access, and paths that are not in the current path
const allowedPaths = paths.filter( const allowedPaths = paths.filter(
(folder) => (folder) =>
CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: folder.path secretPath: folder.path
}) && folder.path.startsWith(currentPath === "/" ? "" : currentPath) }) && folder.path.startsWith(currentPath === "/" ? "" : currentPath)
+54 -31
View File
@@ -13,7 +13,10 @@ import {
SecretType SecretType
} from "@app/db/schemas"; } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { CheckCanSecretsSubject, CheckForbiddenErrorSecretsSubject } from "@app/ee/services/permission/permission-fns"; import {
hasSecretReadValueOrDescribePermission,
throwIfMissingSecretReadValueOrDescribePermission
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
@@ -453,10 +456,14 @@ export const secretServiceFactory = ({
}); });
} }
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: path ProjectPermissionSecretActions.ReadValue,
}); {
environment,
secretPath: path
}
);
return { return {
...updatedSecret[0], ...updatedSecret[0],
@@ -560,10 +567,14 @@ export const secretServiceFactory = ({
}); });
} }
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: path ProjectPermissionSecretActions.ReadValue,
}); {
environment,
secretPath: path
}
);
return { return {
...deletedSecret[0], ...deletedSecret[0],
@@ -620,7 +631,7 @@ export const secretServiceFactory = ({
paths = deepPaths.map(({ folderId, path: p }) => ({ folderId, path: p })); paths = deepPaths.map(({ folderId, path: p }) => ({ folderId, path: p }));
} else { } else {
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: path secretPath: path
}); });
@@ -645,7 +656,7 @@ export const secretServiceFactory = ({
// if its service token allow full access over imported one // if its service token allow full access over imported one
actor === ActorType.SERVICE actor === ActorType.SERVICE
? true ? true
: CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { : hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: importEnv.slug, environment: importEnv.slug,
secretPath: importPath secretPath: importPath
}) })
@@ -699,7 +710,7 @@ export const secretServiceFactory = ({
actorOrgId, actorOrgId,
actionProjectType: ActionProjectType.SecretManager actionProjectType: ActionProjectType.SecretManager
}); });
CheckForbiddenErrorSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment, environment,
secretPath: path secretPath: path
}); });
@@ -750,7 +761,7 @@ export const secretServiceFactory = ({
// if its service token allow full access over imported one // if its service token allow full access over imported one
actor === ActorType.SERVICE actor === ActorType.SERVICE
? true ? true
: CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { : hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
environment: importEnv.slug, environment: importEnv.slug,
secretPath: importPath secretPath: importPath
}) })
@@ -969,10 +980,14 @@ export const secretServiceFactory = ({
secretVersionTagDAL secretVersionTagDAL
}); });
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: path ProjectPermissionSecretActions.ReadValue,
}); {
environment,
secretPath: path
}
);
return updatedSecrets.map((secret) => ({ return updatedSecrets.map((secret) => ({
...secret, ...secret,
@@ -1063,10 +1078,14 @@ export const secretServiceFactory = ({
}); });
} }
} }
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath: path ProjectPermissionSecretActions.ReadValue,
}); {
environment,
secretPath: path
}
);
return secrets.map((secret) => ({ return secrets.map((secret) => ({
...secret, ...secret,
@@ -1257,7 +1276,7 @@ export const secretServiceFactory = ({
action === ProjectPermissionSecretActions.DescribeSecret || action === ProjectPermissionSecretActions.DescribeSecret ||
action === ProjectPermissionSecretActions.ReadValue action === ProjectPermissionSecretActions.ReadValue
) { ) {
return CheckCanSecretsSubject(entityPermission.permission, action, { return hasSecretReadValueOrDescribePermission(entityPermission.permission, action, {
environment, environment,
secretPath, secretPath,
secretName, secretName,
@@ -2429,14 +2448,18 @@ export const secretServiceFactory = ({
key: botKey key: botKey
}); });
const secretValueHidden = !CheckCanSecretsSubject(permission, ProjectPermissionSecretActions.ReadValue, { const secretValueHidden = !hasSecretReadValueOrDescribePermission(
environment: folder.environment.envSlug, permission,
secretPath: folderWithPath.path, ProjectPermissionSecretActions.ReadValue,
secretName: secretKey, {
...(el.tags?.length && { environment: folder.environment.envSlug,
secretTags: el.tags.map((tag) => tag.slug) secretPath: folderWithPath.path,
}) secretName: secretKey,
}); ...(el.tags?.length && {
secretTags: el.tags.map((tag) => tag.slug)
})
}
);
return decryptSecretRaw( return decryptSecretRaw(
{ {
@@ -2839,7 +2862,7 @@ export const secretServiceFactory = ({
sourceAction === ProjectPermissionSecretActions.ReadValue || sourceAction === ProjectPermissionSecretActions.ReadValue ||
sourceAction === ProjectPermissionSecretActions.DescribeSecret sourceAction === ProjectPermissionSecretActions.DescribeSecret
) { ) {
CheckForbiddenErrorSecretsSubject(permission, sourceAction, { throwIfMissingSecretReadValueOrDescribePermission(permission, sourceAction, {
environment: sourceEnvironment, environment: sourceEnvironment,
secretPath: sourceSecretPath secretPath: sourceSecretPath
}); });
+1 -1
View File
@@ -7,7 +7,7 @@ import {
SecretSubjectFields SecretSubjectFields
} from "@app/context/ProjectPermissionContext/types"; } from "@app/context/ProjectPermissionContext/types";
export function secretsPermissionCan( export function hasSecretReadValueOrDescribePermission(
permission: MongoAbility<ProjectPermissionSet>, permission: MongoAbility<ProjectPermissionSet>,
action: Extract< action: Extract<
ProjectPermissionSecretActions, ProjectPermissionSecretActions,
@@ -29,11 +29,11 @@ const GeneralPolicyActionSchema = z.object({
const SecretPolicyActionSchema = z.object({ const SecretPolicyActionSchema = z.object({
[ProjectPermissionSecretActions.DescribeAndReadValue]: z.boolean().optional(), // existing read, gives both describe and read value [ProjectPermissionSecretActions.DescribeAndReadValue]: z.boolean().optional(), // existing read, gives both describe and read value
[ProjectPermissionSecretActions.DescribeSecret]: z.boolean().optional(), // describe secret, cannot read value [ProjectPermissionSecretActions.DescribeSecret]: z.boolean().optional(),
[ProjectPermissionSecretActions.ReadValue]: z.boolean().optional(), // read value [ProjectPermissionSecretActions.ReadValue]: z.boolean().optional(),
[ProjectPermissionSecretActions.Edit]: z.boolean().optional(), // edit secret [ProjectPermissionSecretActions.Edit]: z.boolean().optional(),
[ProjectPermissionSecretActions.Delete]: z.boolean().optional(), // delete secret [ProjectPermissionSecretActions.Delete]: z.boolean().optional(),
[ProjectPermissionSecretActions.Create]: z.boolean().optional() // create secret [ProjectPermissionSecretActions.Create]: z.boolean().optional()
}); });
const CmekPolicyActionSchema = z.object({ const CmekPolicyActionSchema = z.object({
@@ -15,7 +15,7 @@ import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionCo
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { useUpdateSecretV3 } from "@app/hooks/api"; import { useUpdateSecretV3 } from "@app/hooks/api";
import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types"; import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types";
import { secretsPermissionCan } from "@app/lib/fn/permission"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission";
enum SecretActionType { enum SecretActionType {
Created = "created", Created = "created",
@@ -52,7 +52,7 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }
secretTags: (secretDetails?.tags || []).map((i) => i.slug) secretTags: (secretDetails?.tags || []).map((i) => i.slug)
}); });
const isSecretInEnvReadOnly = const isSecretInEnvReadOnly =
secretsPermissionCan( hasSecretReadValueOrDescribePermission(
permission, permission,
ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSecretActions.DescribeSecret,
secretPermissionSubject secretPermissionSubject
@@ -38,7 +38,7 @@ import { useGetProjectSecretsDetails } from "@app/hooks/api/dashboard";
import { DashboardSecretsOrderBy } from "@app/hooks/api/dashboard/types"; import { DashboardSecretsOrderBy } from "@app/hooks/api/dashboard/types";
import { OrderByDirection } from "@app/hooks/api/generic/types"; import { OrderByDirection } from "@app/hooks/api/generic/types";
import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectType } from "@app/hooks/api/workspace/types";
import { secretsPermissionCan } from "@app/lib/fn/permission"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission";
import { SecretTableResourceCount } from "../OverviewPage/components/SecretTableResourceCount"; import { SecretTableResourceCount } from "../OverviewPage/components/SecretTableResourceCount";
import { SecretV2MigrationSection } from "../OverviewPage/components/SecretV2MigrationSection"; import { SecretV2MigrationSection } from "../OverviewPage/components/SecretV2MigrationSection";
@@ -105,7 +105,7 @@ const Page = () => {
const projectSlug = currentWorkspace?.slug || ""; const projectSlug = currentWorkspace?.slug || "";
const secretPath = (routerQueryParams.secretPath as string) || "/"; const secretPath = (routerQueryParams.secretPath as string) || "/";
const canReadSecret = secretsPermissionCan( const canReadSecret = hasSecretReadValueOrDescribePermission(
permission, permission,
ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSecretActions.DescribeSecret,
{ {
@@ -116,7 +116,7 @@ const Page = () => {
} }
); );
const canReadSecretValue = secretsPermissionCan( const canReadSecretValue = hasSecretReadValueOrDescribePermission(
permission, permission,
ProjectPermissionSecretActions.ReadValue, ProjectPermissionSecretActions.ReadValue,
{ {
@@ -57,7 +57,7 @@ import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { useGetSecretAccessList } from "@app/hooks/api/secrets/queries"; import { useGetSecretAccessList } from "@app/hooks/api/secrets/queries";
import { SecretV3RawSanitized, WsTag } from "@app/hooks/api/types"; import { SecretV3RawSanitized, WsTag } from "@app/hooks/api/types";
import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectType } from "@app/hooks/api/workspace/types";
import { secretsPermissionCan } from "@app/lib/fn/permission"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission";
import { CreateReminderForm } from "./CreateReminderForm"; import { CreateReminderForm } from "./CreateReminderForm";
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils"; import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
@@ -141,7 +141,7 @@ export const SecretDetailSidebar = ({
}) })
); );
const cannotReadSecretValue = !secretsPermissionCan( const cannotReadSecretValue = !hasSecretReadValueOrDescribePermission(
permission, permission,
ProjectPermissionSecretActions.ReadValue, ProjectPermissionSecretActions.ReadValue,
{ {
@@ -153,12 +153,16 @@ export const SecretDetailSidebar = ({
); );
const isReadOnly = const isReadOnly =
secretsPermissionCan(permission, ProjectPermissionSecretActions.DescribeSecret, { hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath, ProjectPermissionSecretActions.DescribeSecret,
secretName: secretKey, {
secretTags: selectTagSlugs environment,
}) && secretPath,
secretName: secretKey,
secretTags: selectTagSlugs
}
) &&
cannotEditSecret && cannotEditSecret &&
cannotReadSecretValue; cannotReadSecretValue;
@@ -361,11 +365,11 @@ export const SecretDetailSidebar = ({
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<InfisicalSecretInput <InfisicalSecretInput
isReadOnly={isReadOnly} isReadOnly={isReadOnly || !isAllowed}
environment={environment} environment={environment}
secretPath={secretPath} secretPath={secretPath}
key="secret-value" key="secret-value"
isDisabled={isOverridden || !isAllowed} isDisabled={isOverridden}
containerClassName="text-bunker-300 w-full hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-800 px-2 py-1.5" containerClassName="text-bunker-300 w-full hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-800 px-2 py-1.5"
{...field} {...field}
autoFocus={false} autoFocus={false}
@@ -47,7 +47,7 @@ import {
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
import { Blur } from "@app/components/v2/Blur"; import { Blur } from "@app/components/v2/Blur";
import { secretsPermissionCan } from "@app/lib/fn/permission"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission";
import { import {
FontAwesomeSpriteName, FontAwesomeSpriteName,
formSchema, formSchema,
@@ -132,12 +132,16 @@ export const SecretItem = memo(
}); });
const isReadOnly = const isReadOnly =
secretsPermissionCan(permission, ProjectPermissionSecretActions.DescribeSecret, { hasSecretReadValueOrDescribePermission(
environment, permission,
secretPath, ProjectPermissionSecretActions.DescribeSecret,
secretName, {
secretTags: selectedTagSlugs environment,
}) && secretPath,
secretName,
secretTags: selectedTagSlugs
}
) &&
permission.cannot( permission.cannot(
ProjectPermissionSecretActions.Edit, ProjectPermissionSecretActions.Edit,
subject(ProjectPermissionSub.Secrets, { subject(ProjectPermissionSub.Secrets, {