fix: view secret value (requested changes)

This commit is contained in:
Daniel Hougaard
2025-03-05 22:47:40 +04:00
parent 3c2c70912f
commit ea9da6d2a8
5 changed files with 64 additions and 26 deletions
@@ -5,6 +5,7 @@ import { ActionProjectType, SecretFoldersSchema, SecretImportsSchema } from "@ap
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import { import {
ProjectPermissionDynamicSecretActions, ProjectPermissionDynamicSecretActions,
ProjectPermissionSecretActions,
ProjectPermissionSub ProjectPermissionSub
} from "@app/ee/services/permission/project-permission"; } from "@app/ee/services/permission/project-permission";
import { DASHBOARD } from "@app/lib/api-docs"; import { DASHBOARD } from "@app/lib/api-docs";
@@ -688,6 +689,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
.optional(), .optional(),
secrets: secretRawSchema secrets: secretRawSchema
.extend({ .extend({
secretValueHidden: z.boolean(),
secretPath: z.string().optional(), secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(), secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional() tags: SanitizedTagSchema.array().optional()
@@ -734,6 +736,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.getSecretsRawByFolderMappings( const secrets = await server.services.secret.getSecretsRawByFolderMappings(
{ {
filterByAction: ProjectPermissionSecretActions.DescribeSecret,
projectId, projectId,
folderMappings, folderMappings,
filters: { filters: {
@@ -120,6 +120,7 @@ export const InfisicalSecretInput = forwardRef<HTMLTextAreaElement, Props>(
const isPopupOpen = Boolean(suggestionSource.isOpen) && isFocused; const isPopupOpen = Boolean(suggestionSource.isOpen) && isFocused;
const { data: secrets } = useGetProjectSecrets({ const { data: secrets } = useGetProjectSecrets({
viewSecretValue: false,
environment: suggestionSource.environment || "", environment: suggestionSource.environment || "",
secretPath: suggestionSource.secretPath || "", secretPath: suggestionSource.secretPath || "",
workspaceId, workspaceId,
+18 -5
View File
@@ -26,8 +26,13 @@ import {
export const secretKeys = { export const secretKeys = {
// this is also used in secretSnapshot part // this is also used in secretSnapshot part
getProjectSecret: ({ workspaceId, environment, secretPath }: TGetProjectSecretsKey) => getProjectSecret: ({
[{ workspaceId, environment, secretPath }, "secrets"] as const, workspaceId,
environment,
secretPath,
viewSecretValue
}: TGetProjectSecretsKey) =>
[{ workspaceId, environment, secretPath, viewSecretValue }, "secrets"] as const,
getSecretVersion: (secretId: string) => [{ secretId }, "secret-versions"] as const, getSecretVersion: (secretId: string) => [{ secretId }, "secret-versions"] as const,
getSecretAccessList: ({ getSecretAccessList: ({
workspaceId, workspaceId,
@@ -44,13 +49,15 @@ export const fetchProjectSecrets = async ({
environment, environment,
secretPath, secretPath,
includeImports, includeImports,
expandSecretReferences expandSecretReferences,
viewSecretValue
}: TGetProjectSecretsKey) => { }: TGetProjectSecretsKey) => {
const { data } = await apiRequest.get<SecretV3RawResponse>("/api/v3/secrets/raw", { const { data } = await apiRequest.get<SecretV3RawResponse>("/api/v3/secrets/raw", {
params: { params: {
environment, environment,
workspaceId, workspaceId,
secretPath, secretPath,
viewSecretValue,
expandSecretReferences, expandSecretReferences,
include_imports: includeImports include_imports: includeImports
} }
@@ -108,6 +115,7 @@ export const useGetProjectSecrets = ({
workspaceId, workspaceId,
environment, environment,
secretPath, secretPath,
viewSecretValue,
options options
}: TGetProjectSecretsDTO & { }: TGetProjectSecretsDTO & {
options?: Omit< options?: Omit<
@@ -124,8 +132,13 @@ export const useGetProjectSecrets = ({
...options, ...options,
// wait for all values to be available // wait for all values to be available
enabled: Boolean(workspaceId && environment) && (options?.enabled ?? true), enabled: Boolean(workspaceId && environment) && (options?.enabled ?? true),
queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }), queryKey: secretKeys.getProjectSecret({
queryFn: () => fetchProjectSecrets({ workspaceId, environment, secretPath }), workspaceId,
environment,
secretPath,
viewSecretValue
}),
queryFn: () => fetchProjectSecrets({ workspaceId, environment, secretPath, viewSecretValue }),
select: useCallback( select: useCallback(
(data: Awaited<ReturnType<typeof fetchProjectSecrets>>) => mergePersonalSecrets(data.secrets), (data: Awaited<ReturnType<typeof fetchProjectSecrets>>) => mergePersonalSecrets(data.secrets),
[] []
+1
View File
@@ -113,6 +113,7 @@ export type TGetProjectSecretsKey = {
environment: string; environment: string;
secretPath?: string; secretPath?: string;
includeImports?: boolean; includeImports?: boolean;
viewSecretValue?: boolean;
expandSecretReferences?: boolean; expandSecretReferences?: boolean;
}; };
@@ -110,21 +110,31 @@ export const QuickSearchSecretItem = ({
</Badge> </Badge>
)} )}
{isSingleEnv ? ( {isSingleEnv ? (
<IconButton <Tooltip
size="md" isDisabled={!groupSecret?.secretValueHidden}
variant="plain" content={
colorSchema="secondary" groupSecret?.secretValueHidden
ariaLabel="Copy secret value" ? "You do not have permission to view this secret value"
onClick={(e) => { : ""
e.stopPropagation(); }
const el = envSlugMap.get(groupSecret.env)?.name;
if (el) {
handleCopy(groupSecret.value!, el);
}
}}
> >
<FontAwesomeIcon icon={isUrlCopied ? faCheck : faCopy} /> <IconButton
</IconButton> size="md"
isDisabled={groupSecret?.secretValueHidden}
variant="plain"
colorSchema="secondary"
ariaLabel="Copy secret value"
onClick={(e) => {
e.stopPropagation();
const el = envSlugMap.get(groupSecret.env)?.name;
if (el) {
handleCopy(groupSecret.value!, el);
}
}}
>
<FontAwesomeIcon icon={isUrlCopied ? faCheck : faCopy} />
</IconButton>
</Tooltip>
) : ( ) : (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@@ -158,14 +168,24 @@ export const QuickSearchSecretItem = ({
)} )}
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<IconButton <Tooltip
size="md" isDisabled={!groupSecret?.secretValueHidden}
variant="plain" content={
colorSchema="secondary" groupSecret?.secretValueHidden
ariaLabel="View secret value" ? "You do not have permission to view this secret value"
: ""
}
> >
<FontAwesomeIcon icon={faEye} /> <IconButton
</IconButton> size="md"
isDisabled={groupSecret?.secretValueHidden}
variant="plain"
colorSchema="secondary"
ariaLabel="View secret value"
>
<FontAwesomeIcon icon={faEye} />
</IconButton>
</Tooltip>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuLabel>Hover to Reveal...</DropdownMenuLabel> <DropdownMenuLabel>Hover to Reveal...</DropdownMenuLabel>