mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 01:27:31 +00:00
misc: addressed comments
This commit is contained in:
+4
-4
@@ -3,17 +3,17 @@ import { Knex } from "knex";
|
|||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
if (!(await knex.schema.hasColumn(TableName.Project, "secretDetectionIgnoreKeys"))) {
|
if (!(await knex.schema.hasColumn(TableName.Project, "secretDetectionIgnoreValues"))) {
|
||||||
await knex.schema.alterTable(TableName.Project, (t) => {
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
t.specificType("secretDetectionIgnoreKeys", "text[]");
|
t.specificType("secretDetectionIgnoreValues", "text[]");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
if (await knex.schema.hasColumn(TableName.Project, "secretDetectionIgnoreKeys")) {
|
if (await knex.schema.hasColumn(TableName.Project, "secretDetectionIgnoreValues")) {
|
||||||
await knex.schema.alterTable(TableName.Project, (t) => {
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
t.dropColumn("secretDetectionIgnoreKeys");
|
t.dropColumn("secretDetectionIgnoreValues");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ export const ProjectsSchema = z.object({
|
|||||||
secretSharing: z.boolean().default(true),
|
secretSharing: z.boolean().default(true),
|
||||||
showSnapshotsLegacy: z.boolean().default(false),
|
showSnapshotsLegacy: z.boolean().default(false),
|
||||||
defaultProduct: z.string().nullable().optional(),
|
defaultProduct: z.string().nullable().optional(),
|
||||||
secretDetectionIgnoreKeys: z.string().array().nullable().optional()
|
secretDetectionIgnoreValues: z.string().array().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjects = z.infer<typeof ProjectsSchema>;
|
export type TProjects = z.infer<typeof ProjectsSchema>;
|
||||||
|
|||||||
@@ -1410,6 +1410,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
await scanSecretPolicyViolations(
|
await scanSecretPolicyViolations(
|
||||||
|
projectId,
|
||||||
secretPath,
|
secretPath,
|
||||||
[
|
[
|
||||||
...(data[SecretOperations.Create] || []),
|
...(data[SecretOperations.Create] || []),
|
||||||
@@ -1418,7 +1419,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.secretKey,
|
secretKey: el.secretKey,
|
||||||
secretValue: el.secretValue as string
|
secretValue: el.secretValue as string
|
||||||
})),
|
})),
|
||||||
project.secretDetectionIgnoreKeys || []
|
project.secretDetectionIgnoreValues || []
|
||||||
);
|
);
|
||||||
|
|
||||||
// for created secret approval change
|
// for created secret approval change
|
||||||
|
|||||||
@@ -165,28 +165,29 @@ export const parseScanErrorMessage = (err: unknown): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const scanSecretPolicyViolations = async (
|
export const scanSecretPolicyViolations = async (
|
||||||
|
projectId: string,
|
||||||
secretPath: string,
|
secretPath: string,
|
||||||
secrets: { secretKey: string; secretValue: string }[],
|
secrets: { secretKey: string; secretValue: string }[],
|
||||||
ignoreKeys: string[]
|
ignoreValues: string[]
|
||||||
) => {
|
) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
if (!appCfg.PARAMS_FOLDER_SECRET_DETECTION_ENABLED) {
|
if (!appCfg.PARAMS_FOLDER_SECRET_DETECTION_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const paramFolderSecretDetectionPaths = appCfg.PARAMS_FOLDER_SECRET_DETECTION_PATHS?.map((el) => el.secretPath) ?? [];
|
|
||||||
const isPathMatched = paramFolderSecretDetectionPaths.some((pattern) =>
|
const match = appCfg.PARAMS_FOLDER_SECRET_DETECTION_PATHS?.find(
|
||||||
picomatch.isMatch(secretPath, pattern, { strictSlashes: false })
|
(el) => el.projectId === projectId && picomatch.isMatch(secretPath, el.secretPath, { strictSlashes: false })
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isPathMatched) {
|
if (!match) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempFolder = await createTempFolder();
|
const tempFolder = await createTempFolder();
|
||||||
try {
|
try {
|
||||||
const scanPromises = secrets
|
const scanPromises = secrets
|
||||||
.filter((secret) => !ignoreKeys.includes(secret.secretKey))
|
.filter((secret) => !ignoreValues.includes(secret.secretValue))
|
||||||
.map(async (secret) => {
|
.map(async (secret) => {
|
||||||
const secretFilePath = join(tempFolder, `${crypto.nativeCrypto.randomUUID()}.txt`);
|
const secretFilePath = join(tempFolder, `${crypto.nativeCrypto.randomUUID()}.txt`);
|
||||||
await writeTextToFile(secretFilePath, `${secret.secretKey}=${secret.secretValue}`);
|
await writeTextToFile(secretFilePath, `${secret.secretKey}=${secret.secretValue}`);
|
||||||
|
|||||||
@@ -705,7 +705,7 @@ export const PROJECTS = {
|
|||||||
secretSharing: "Enable or disable secret sharing for the project.",
|
secretSharing: "Enable or disable secret sharing for the project.",
|
||||||
showSnapshotsLegacy: "Enable or disable legacy snapshots for the project.",
|
showSnapshotsLegacy: "Enable or disable legacy snapshots for the project.",
|
||||||
defaultProduct: "The default product in which the project will open",
|
defaultProduct: "The default product in which the project will open",
|
||||||
secretDetectionIgnoreKeys: "The list of secret keys to ignore for secret detection."
|
secretDetectionIgnoreValues: "The list of secret values to ignore for secret detection."
|
||||||
},
|
},
|
||||||
GET_KEY: {
|
GET_KEY: {
|
||||||
workspaceId: "The ID of the project to get the key from."
|
workspaceId: "The ID of the project to get the key from."
|
||||||
|
|||||||
@@ -211,10 +211,9 @@ const envSchema = z
|
|||||||
.optional()
|
.optional()
|
||||||
.transform((val) => {
|
.transform((val) => {
|
||||||
if (!val) return undefined;
|
if (!val) return undefined;
|
||||||
return JSON.parse(val) as { secretPath: string }[];
|
return JSON.parse(val) as { secretPath: string; projectId: string }[];
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
PARAMS_FOLDER_SECRET_DETECTION_ENABLED: zodStrBool.default("false"),
|
|
||||||
|
|
||||||
// HSM
|
// HSM
|
||||||
HSM_LIB_PATH: zpStr(z.string().optional()),
|
HSM_LIB_PATH: zpStr(z.string().optional()),
|
||||||
@@ -353,7 +352,8 @@ const envSchema = z
|
|||||||
isHsmConfigured:
|
isHsmConfigured:
|
||||||
Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined,
|
Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined,
|
||||||
samlDefaultOrgSlug: data.DEFAULT_SAML_ORG_SLUG,
|
samlDefaultOrgSlug: data.DEFAULT_SAML_ORG_SLUG,
|
||||||
SECRET_SCANNING_ORG_WHITELIST: data.SECRET_SCANNING_ORG_WHITELIST?.split(",")
|
SECRET_SCANNING_ORG_WHITELIST: data.SECRET_SCANNING_ORG_WHITELIST?.split(","),
|
||||||
|
PARAMS_FOLDER_SECRET_DETECTION_ENABLED: (data.PARAMS_FOLDER_SECRET_DETECTION_PATHS?.length ?? 0) > 0
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type TEnvConfig = Readonly<z.infer<typeof envSchema>>;
|
export type TEnvConfig = Readonly<z.infer<typeof envSchema>>;
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ export const SanitizedProjectSchema = ProjectsSchema.pick({
|
|||||||
hasDeleteProtection: true,
|
hasDeleteProtection: true,
|
||||||
secretSharing: true,
|
secretSharing: true,
|
||||||
showSnapshotsLegacy: true,
|
showSnapshotsLegacy: true,
|
||||||
secretDetectionIgnoreKeys: true
|
secretDetectionIgnoreValues: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const SanitizedTagSchema = SecretTagsSchema.pick({
|
export const SanitizedTagSchema = SecretTagsSchema.pick({
|
||||||
|
|||||||
@@ -370,7 +370,10 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing),
|
secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing),
|
||||||
showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy),
|
showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy),
|
||||||
defaultProduct: z.nativeEnum(ProjectType).optional().describe(PROJECTS.UPDATE.defaultProduct),
|
defaultProduct: z.nativeEnum(ProjectType).optional().describe(PROJECTS.UPDATE.defaultProduct),
|
||||||
secretDetectionIgnoreKeys: z.array(z.string()).optional().describe(PROJECTS.UPDATE.secretDetectionIgnoreKeys)
|
secretDetectionIgnoreValues: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe(PROJECTS.UPDATE.secretDetectionIgnoreValues)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -394,7 +397,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
slug: req.body.slug,
|
slug: req.body.slug,
|
||||||
secretSharing: req.body.secretSharing,
|
secretSharing: req.body.secretSharing,
|
||||||
showSnapshotsLegacy: req.body.showSnapshotsLegacy,
|
showSnapshotsLegacy: req.body.showSnapshotsLegacy,
|
||||||
secretDetectionIgnoreKeys: req.body.secretDetectionIgnoreKeys
|
secretDetectionIgnoreValues: req.body.secretDetectionIgnoreValues
|
||||||
},
|
},
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
|
|||||||
@@ -667,9 +667,9 @@ export const projectServiceFactory = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update.secretDetectionIgnoreKeys && !hasRole(ProjectMembershipRole.Admin)) {
|
if (update.secretDetectionIgnoreValues && !hasRole(ProjectMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({
|
throw new ForbiddenRequestError({
|
||||||
message: "Only admins can update secret detection ignore keys"
|
message: "Only admins can update secret detection ignore values"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +683,7 @@ export const projectServiceFactory = ({
|
|||||||
secretSharing: update.secretSharing,
|
secretSharing: update.secretSharing,
|
||||||
defaultProduct: update.defaultProduct,
|
defaultProduct: update.defaultProduct,
|
||||||
showSnapshotsLegacy: update.showSnapshotsLegacy,
|
showSnapshotsLegacy: update.showSnapshotsLegacy,
|
||||||
secretDetectionIgnoreKeys: update.secretDetectionIgnoreKeys
|
secretDetectionIgnoreValues: update.secretDetectionIgnoreValues
|
||||||
});
|
});
|
||||||
|
|
||||||
return updatedProject;
|
return updatedProject;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export type TUpdateProjectDTO = {
|
|||||||
slug?: string;
|
slug?: string;
|
||||||
secretSharing?: boolean;
|
secretSharing?: boolean;
|
||||||
showSnapshotsLegacy?: boolean;
|
showSnapshotsLegacy?: boolean;
|
||||||
secretDetectionIgnoreKeys?: string[];
|
secretDetectionIgnoreValues?: string[];
|
||||||
};
|
};
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
await scanSecretPolicyViolations(
|
await scanSecretPolicyViolations(
|
||||||
|
projectId,
|
||||||
secretPath,
|
secretPath,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -308,7 +309,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretValue: inputSecret.secretValue
|
secretValue: inputSecret.secretValue
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
project.secretDetectionIgnoreKeys || []
|
project.secretDetectionIgnoreValues || []
|
||||||
);
|
);
|
||||||
|
|
||||||
const { nestedReferences, localReferences } = getAllSecretReferences(inputSecret.secretValue);
|
const { nestedReferences, localReferences } = getAllSecretReferences(inputSecret.secretValue);
|
||||||
@@ -525,6 +526,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
if (secretValue) {
|
if (secretValue) {
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
await scanSecretPolicyViolations(
|
await scanSecretPolicyViolations(
|
||||||
|
projectId,
|
||||||
secretPath,
|
secretPath,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -532,7 +534,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretValue
|
secretValue
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
project.secretDetectionIgnoreKeys || []
|
project.secretDetectionIgnoreValues || []
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1616,7 +1618,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: `Secret already exist: ${secrets.map((el) => el.key).join(",")}` });
|
throw new BadRequestError({ message: `Secret already exist: ${secrets.map((el) => el.key).join(",")}` });
|
||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
await scanSecretPolicyViolations(secretPath, inputSecrets, project.secretDetectionIgnoreKeys || []);
|
await scanSecretPolicyViolations(projectId, secretPath, inputSecrets, project.secretDetectionIgnoreValues || []);
|
||||||
|
|
||||||
// get all tags
|
// get all tags
|
||||||
const sanitizedTagIds = inputSecrets.flatMap(({ tagIds = [] }) => tagIds);
|
const sanitizedTagIds = inputSecrets.flatMap(({ tagIds = [] }) => tagIds);
|
||||||
@@ -1960,6 +1962,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
await scanSecretPolicyViolations(
|
await scanSecretPolicyViolations(
|
||||||
|
projectId,
|
||||||
secretPath,
|
secretPath,
|
||||||
secretsToUpdate
|
secretsToUpdate
|
||||||
.filter((el) => el.secretValue)
|
.filter((el) => el.secretValue)
|
||||||
@@ -1967,7 +1970,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretKey: el.newSecretName || el.secretKey,
|
secretKey: el.newSecretName || el.secretKey,
|
||||||
secretValue: el.secretValue as string
|
secretValue: el.secretValue as string
|
||||||
})),
|
})),
|
||||||
project.secretDetectionIgnoreKeys || []
|
project.secretDetectionIgnoreValues || []
|
||||||
);
|
);
|
||||||
|
|
||||||
const bulkUpdatedSecrets = await fnSecretBulkUpdate({
|
const bulkUpdatedSecrets = await fnSecretBulkUpdate({
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ export const useUpdateProject = () => {
|
|||||||
newSlug,
|
newSlug,
|
||||||
secretSharing,
|
secretSharing,
|
||||||
showSnapshotsLegacy,
|
showSnapshotsLegacy,
|
||||||
secretDetectionIgnoreKeys
|
secretDetectionIgnoreValues
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = await apiRequest.patch<{ workspace: Workspace }>(
|
const { data } = await apiRequest.patch<{ workspace: Workspace }>(
|
||||||
`/api/v1/workspace/${projectID}`,
|
`/api/v1/workspace/${projectID}`,
|
||||||
@@ -292,7 +292,7 @@ export const useUpdateProject = () => {
|
|||||||
slug: newSlug,
|
slug: newSlug,
|
||||||
secretSharing,
|
secretSharing,
|
||||||
showSnapshotsLegacy,
|
showSnapshotsLegacy,
|
||||||
secretDetectionIgnoreKeys
|
secretDetectionIgnoreValues
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return data.workspace;
|
return data.workspace;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export type Workspace = {
|
|||||||
hasDeleteProtection: boolean;
|
hasDeleteProtection: boolean;
|
||||||
secretSharing: boolean;
|
secretSharing: boolean;
|
||||||
showSnapshotsLegacy: boolean;
|
showSnapshotsLegacy: boolean;
|
||||||
secretDetectionIgnoreKeys: string[];
|
secretDetectionIgnoreValues: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WorkspaceEnv = {
|
export type WorkspaceEnv = {
|
||||||
@@ -82,7 +82,7 @@ export type UpdateProjectDTO = {
|
|||||||
newSlug?: string;
|
newSlug?: string;
|
||||||
secretSharing?: boolean;
|
secretSharing?: boolean;
|
||||||
showSnapshotsLegacy?: boolean;
|
showSnapshotsLegacy?: boolean;
|
||||||
secretDetectionIgnoreKeys?: string[];
|
secretDetectionIgnoreValues?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdatePitVersionLimitDTO = { projectSlug: string; pitVersionLimit: number };
|
export type UpdatePitVersionLimitDTO = { projectSlug: string; pitVersionLimit: number };
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ import { AutoCapitalizationSection } from "../AutoCapitalizationSection";
|
|||||||
import { BackfillSecretReferenceSecretion } from "../BackfillSecretReferenceSection";
|
import { BackfillSecretReferenceSecretion } from "../BackfillSecretReferenceSection";
|
||||||
import { EnvironmentSection } from "../EnvironmentSection";
|
import { EnvironmentSection } from "../EnvironmentSection";
|
||||||
import { PointInTimeVersionLimitSection } from "../PointInTimeVersionLimitSection";
|
import { PointInTimeVersionLimitSection } from "../PointInTimeVersionLimitSection";
|
||||||
import { SecretDetectionIgnoreKeysSection } from "../SecretDetectionIgnoreKeysSection/SecretDetectionIgnoreKeysSection";
|
import { SecretDetectionIgnoreValuesSection } from "../SecretDetectionIgnoreValuesSection/SecretDetectionIgnoreValuesSection";
|
||||||
import { SecretSharingSection } from "../SecretSharingSection";
|
import { SecretSharingSection } from "../SecretSharingSection";
|
||||||
import { SecretSnapshotsLegacySection } from "../SecretSnapshotsLegacySection";
|
import { SecretSnapshotsLegacySection } from "../SecretSnapshotsLegacySection";
|
||||||
import { SecretTagsSection } from "../SecretTagsSection";
|
import { SecretTagsSection } from "../SecretTagsSection";
|
||||||
@@ -20,7 +20,7 @@ export const SecretSettingsTab = () => {
|
|||||||
<SecretSharingSection />
|
<SecretSharingSection />
|
||||||
<SecretSnapshotsLegacySection />
|
<SecretSnapshotsLegacySection />
|
||||||
<PointInTimeVersionLimitSection />
|
<PointInTimeVersionLimitSection />
|
||||||
{config.paramsFolderSecretDetectionEnabled && <SecretDetectionIgnoreKeysSection />}
|
{config.paramsFolderSecretDetectionEnabled && <SecretDetectionIgnoreValuesSection />}
|
||||||
<BackfillSecretReferenceSecretion />
|
<BackfillSecretReferenceSecretion />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+31
-29
@@ -12,9 +12,9 @@ import { useUpdateProject } from "@app/hooks/api";
|
|||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
ignoreKeys: z
|
ignoreValues: z
|
||||||
.object({
|
.object({
|
||||||
key: z.string().trim().min(1, "Secret key name is required")
|
value: z.string().trim().min(1, "Secret value is required")
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
.default([])
|
.default([])
|
||||||
@@ -22,7 +22,7 @@ const formSchema = z.object({
|
|||||||
|
|
||||||
type TForm = z.infer<typeof formSchema>;
|
type TForm = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
export const SecretDetectionIgnoreKeysSection = () => {
|
export const SecretDetectionIgnoreValuesSection = () => {
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const { membership } = useProjectPermission();
|
const { membership } = useProjectPermission();
|
||||||
const { mutateAsync: updateProject } = useUpdateProject();
|
const { mutateAsync: updateProject } = useUpdateProject();
|
||||||
@@ -35,37 +35,39 @@ export const SecretDetectionIgnoreKeysSection = () => {
|
|||||||
} = useForm<TForm>({
|
} = useForm<TForm>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
ignoreKeys: []
|
ignoreValues: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ignoreKeysFormFields = useFieldArray({
|
const ignoreValuesFormFields = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "ignoreKeys"
|
name: "ignoreValues"
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const existingIgnoreKeys = currentWorkspace?.secretDetectionIgnoreKeys || [];
|
const existingIgnoreValues = currentWorkspace?.secretDetectionIgnoreValues || [];
|
||||||
reset({
|
reset({
|
||||||
ignoreKeys:
|
ignoreValues:
|
||||||
existingIgnoreKeys.length > 0 ? existingIgnoreKeys.map((key) => ({ key })) : [{ key: "" }] // Show one empty field by default
|
existingIgnoreValues.length > 0
|
||||||
|
? existingIgnoreValues.map((value) => ({ value }))
|
||||||
|
: [{ value: "" }] // Show one empty field by default
|
||||||
});
|
});
|
||||||
}, [currentWorkspace?.secretDetectionIgnoreKeys, reset]);
|
}, [currentWorkspace?.secretDetectionIgnoreValues, reset]);
|
||||||
|
|
||||||
const handleIgnoreKeysSubmit = async ({ ignoreKeys }: TForm) => {
|
const handleIgnoreValuesSubmit = async ({ ignoreValues }: TForm) => {
|
||||||
try {
|
try {
|
||||||
await updateProject({
|
await updateProject({
|
||||||
projectID: currentWorkspace.id,
|
projectID: currentWorkspace.id,
|
||||||
secretDetectionIgnoreKeys: ignoreKeys.map((item) => item.key)
|
secretDetectionIgnoreValues: ignoreValues.map((item) => item.value)
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Successfully updated secret detection ignore keys",
|
text: "Successfully updated secret detection ignore values",
|
||||||
type: "success"
|
type: "success"
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Failed updating secret detection ignore keys",
|
text: "Failed updating secret detection ignore values",
|
||||||
type: "error"
|
type: "error"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -78,41 +80,41 @@ export const SecretDetectionIgnoreKeysSection = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between">
|
||||||
<p className="text-xl font-semibold">Secret Detection Ignore Keys</p>
|
<p className="text-xl font-semibold">Secret Detection Ignore Values</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="mb-4 mt-2 max-w-2xl text-sm text-gray-400">
|
<p className="mb-4 mt-2 max-w-2xl text-sm text-gray-400">
|
||||||
Define secret keys that should be ignored when scanning parameter folders for misplaced
|
Define secret values that should be ignored when scanning parameter folders for misplaced
|
||||||
secrets. These keys will not trigger policy violation alerts even if they contain sensitive
|
secrets. These values will not trigger policy violation alerts even if they contain
|
||||||
data.
|
sensitive data.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(handleIgnoreKeysSubmit)} autoComplete="off">
|
<form onSubmit={handleSubmit(handleIgnoreValuesSubmit)} autoComplete="off">
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<p className="mb-3 text-sm font-medium text-gray-300">Ignored Secret Keys</p>
|
<p className="mb-3 text-sm font-medium text-gray-300">Ignored Secret Values</p>
|
||||||
<div className="flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
{ignoreKeysFormFields.fields.map(({ id: ignoreKeyFieldId }, i) => (
|
{ignoreValuesFormFields.fields.map(({ id: ignoreValueFieldId }, i) => (
|
||||||
<div key={ignoreKeyFieldId} className="flex items-end space-x-2">
|
<div key={ignoreValueFieldId} className="flex items-end space-x-2">
|
||||||
<div className="flex-grow">
|
<div className="flex-grow">
|
||||||
{i === 0 && <span className="text-xs text-mineshaft-400">Secret Key Name</span>}
|
{i === 0 && <span className="text-xs text-mineshaft-400">Secret Value</span>}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name={`ignoreKeys.${i}.key`}
|
name={`ignoreValues.${i}.value`}
|
||||||
render={({ field, fieldState: { error } }) => (
|
render={({ field, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isError={Boolean(error?.message)}
|
isError={Boolean(error?.message)}
|
||||||
errorText={error?.message}
|
errorText={error?.message}
|
||||||
className="mb-0"
|
className="mb-0"
|
||||||
>
|
>
|
||||||
<Input {...field} placeholder="PUBLIC_API_KEY" isDisabled={!isAdmin} />
|
<Input {...field} placeholder="sk-1234567890abcdef" isDisabled={!isAdmin} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<IconButton
|
<IconButton
|
||||||
ariaLabel="delete ignore key"
|
ariaLabel="delete ignore value"
|
||||||
className="bottom-0.5 h-9"
|
className="bottom-0.5 h-9"
|
||||||
variant="outline_bg"
|
variant="outline_bg"
|
||||||
onClick={() => ignoreKeysFormFields.remove(i)}
|
onClick={() => ignoreValuesFormFields.remove(i)}
|
||||||
isDisabled={!isAdmin}
|
isDisabled={!isAdmin}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faTrash} />
|
<FontAwesomeIcon icon={faTrash} />
|
||||||
@@ -124,10 +126,10 @@ export const SecretDetectionIgnoreKeysSection = () => {
|
|||||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
size="xs"
|
size="xs"
|
||||||
variant="outline_bg"
|
variant="outline_bg"
|
||||||
onClick={() => ignoreKeysFormFields.append({ key: "" })}
|
onClick={() => ignoreValuesFormFields.append({ value: "" })}
|
||||||
isDisabled={!isAdmin}
|
isDisabled={!isAdmin}
|
||||||
>
|
>
|
||||||
Add Ignore Key
|
Add Ignore Value
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user