misc: addressed comments

This commit is contained in:
Sheen Capadngan
2025-07-29 04:56:50 +08:00
parent 585cb1b30c
commit e430abfc9e
15 changed files with 72 additions and 62 deletions
@@ -3,17 +3,17 @@ import { Knex } from "knex";
import { TableName } from "../schemas";
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) => {
t.specificType("secretDetectionIgnoreKeys", "text[]");
t.specificType("secretDetectionIgnoreValues", "text[]");
});
}
}
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) => {
t.dropColumn("secretDetectionIgnoreKeys");
t.dropColumn("secretDetectionIgnoreValues");
});
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ export const ProjectsSchema = z.object({
secretSharing: z.boolean().default(true),
showSnapshotsLegacy: z.boolean().default(false),
defaultProduct: z.string().nullable().optional(),
secretDetectionIgnoreKeys: z.string().array().nullable().optional()
secretDetectionIgnoreValues: z.string().array().nullable().optional()
});
export type TProjects = z.infer<typeof ProjectsSchema>;
@@ -1410,6 +1410,7 @@ export const secretApprovalRequestServiceFactory = ({
const project = await projectDAL.findById(projectId);
await scanSecretPolicyViolations(
projectId,
secretPath,
[
...(data[SecretOperations.Create] || []),
@@ -1418,7 +1419,7 @@ export const secretApprovalRequestServiceFactory = ({
secretKey: el.secretKey,
secretValue: el.secretValue as string
})),
project.secretDetectionIgnoreKeys || []
project.secretDetectionIgnoreValues || []
);
// for created secret approval change
@@ -165,28 +165,29 @@ export const parseScanErrorMessage = (err: unknown): string => {
};
export const scanSecretPolicyViolations = async (
projectId: string,
secretPath: string,
secrets: { secretKey: string; secretValue: string }[],
ignoreKeys: string[]
ignoreValues: string[]
) => {
const appCfg = getConfig();
if (!appCfg.PARAMS_FOLDER_SECRET_DETECTION_ENABLED) {
return;
}
const paramFolderSecretDetectionPaths = appCfg.PARAMS_FOLDER_SECRET_DETECTION_PATHS?.map((el) => el.secretPath) ?? [];
const isPathMatched = paramFolderSecretDetectionPaths.some((pattern) =>
picomatch.isMatch(secretPath, pattern, { strictSlashes: false })
const match = appCfg.PARAMS_FOLDER_SECRET_DETECTION_PATHS?.find(
(el) => el.projectId === projectId && picomatch.isMatch(secretPath, el.secretPath, { strictSlashes: false })
);
if (!isPathMatched) {
if (!match) {
return;
}
const tempFolder = await createTempFolder();
try {
const scanPromises = secrets
.filter((secret) => !ignoreKeys.includes(secret.secretKey))
.filter((secret) => !ignoreValues.includes(secret.secretValue))
.map(async (secret) => {
const secretFilePath = join(tempFolder, `${crypto.nativeCrypto.randomUUID()}.txt`);
await writeTextToFile(secretFilePath, `${secret.secretKey}=${secret.secretValue}`);
+1 -1
View File
@@ -705,7 +705,7 @@ export const PROJECTS = {
secretSharing: "Enable or disable secret sharing for the project.",
showSnapshotsLegacy: "Enable or disable legacy snapshots for the project.",
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: {
workspaceId: "The ID of the project to get the key from."
+3 -3
View File
@@ -211,10 +211,9 @@ const envSchema = z
.optional()
.transform((val) => {
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_LIB_PATH: zpStr(z.string().optional()),
@@ -353,7 +352,8 @@ const envSchema = z
isHsmConfigured:
Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined,
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>>;
@@ -265,7 +265,7 @@ export const SanitizedProjectSchema = ProjectsSchema.pick({
hasDeleteProtection: true,
secretSharing: true,
showSnapshotsLegacy: true,
secretDetectionIgnoreKeys: true
secretDetectionIgnoreValues: true
});
export const SanitizedTagSchema = SecretTagsSchema.pick({
@@ -370,7 +370,10 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing),
showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy),
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: {
200: z.object({
@@ -394,7 +397,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
slug: req.body.slug,
secretSharing: req.body.secretSharing,
showSnapshotsLegacy: req.body.showSnapshotsLegacy,
secretDetectionIgnoreKeys: req.body.secretDetectionIgnoreKeys
secretDetectionIgnoreValues: req.body.secretDetectionIgnoreValues
},
actorAuthMethod: req.permission.authMethod,
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({
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,
defaultProduct: update.defaultProduct,
showSnapshotsLegacy: update.showSnapshotsLegacy,
secretDetectionIgnoreKeys: update.secretDetectionIgnoreKeys
secretDetectionIgnoreValues: update.secretDetectionIgnoreValues
});
return updatedProject;
@@ -96,7 +96,7 @@ export type TUpdateProjectDTO = {
slug?: string;
secretSharing?: boolean;
showSnapshotsLegacy?: boolean;
secretDetectionIgnoreKeys?: string[];
secretDetectionIgnoreValues?: string[];
};
} & Omit<TProjectPermission, "projectId">;
@@ -301,6 +301,7 @@ export const secretV2BridgeServiceFactory = ({
const project = await projectDAL.findById(projectId);
await scanSecretPolicyViolations(
projectId,
secretPath,
[
{
@@ -308,7 +309,7 @@ export const secretV2BridgeServiceFactory = ({
secretValue: inputSecret.secretValue
}
],
project.secretDetectionIgnoreKeys || []
project.secretDetectionIgnoreValues || []
);
const { nestedReferences, localReferences } = getAllSecretReferences(inputSecret.secretValue);
@@ -525,6 +526,7 @@ export const secretV2BridgeServiceFactory = ({
if (secretValue) {
const project = await projectDAL.findById(projectId);
await scanSecretPolicyViolations(
projectId,
secretPath,
[
{
@@ -532,7 +534,7 @@ export const secretV2BridgeServiceFactory = ({
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(",")}` });
const project = await projectDAL.findById(projectId);
await scanSecretPolicyViolations(secretPath, inputSecrets, project.secretDetectionIgnoreKeys || []);
await scanSecretPolicyViolations(projectId, secretPath, inputSecrets, project.secretDetectionIgnoreValues || []);
// get all tags
const sanitizedTagIds = inputSecrets.flatMap(({ tagIds = [] }) => tagIds);
@@ -1960,6 +1962,7 @@ export const secretV2BridgeServiceFactory = ({
const project = await projectDAL.findById(projectId);
await scanSecretPolicyViolations(
projectId,
secretPath,
secretsToUpdate
.filter((el) => el.secretValue)
@@ -1967,7 +1970,7 @@ export const secretV2BridgeServiceFactory = ({
secretKey: el.newSecretName || el.secretKey,
secretValue: el.secretValue as string
})),
project.secretDetectionIgnoreKeys || []
project.secretDetectionIgnoreValues || []
);
const bulkUpdatedSecrets = await fnSecretBulkUpdate({