mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 07:27:43 +00:00
Improve types and maps for secret sync warning logic
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
||||||
|
import { DestinationDuplicateCheckFn } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
||||||
[SecretSync.AWSParameterStore]: "AWS Parameter Store",
|
[SecretSync.AWSParameterStore]: "AWS Parameter Store",
|
||||||
@@ -99,3 +100,101 @@ export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
|
|||||||
[SecretSync.Netlify]: SecretSyncPlanType.Regular,
|
[SecretSync.Netlify]: SecretSyncPlanType.Regular,
|
||||||
[SecretSync.Bitbucket]: SecretSyncPlanType.Regular
|
[SecretSync.Bitbucket]: SecretSyncPlanType.Regular
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SECRET_SYNC_SKIP_FIELDS_MAP: Record<SecretSync, string[]> = {
|
||||||
|
[SecretSync.AWSParameterStore]: [],
|
||||||
|
[SecretSync.AWSSecretsManager]: ["mappingBehavior", "secretName"],
|
||||||
|
[SecretSync.GitHub]: [],
|
||||||
|
[SecretSync.GCPSecretManager]: [],
|
||||||
|
[SecretSync.AzureKeyVault]: [],
|
||||||
|
[SecretSync.AzureAppConfiguration]: ["label"],
|
||||||
|
[SecretSync.AzureDevOps]: ["devopsProjectName"],
|
||||||
|
[SecretSync.Databricks]: [],
|
||||||
|
[SecretSync.Humanitec]: [],
|
||||||
|
[SecretSync.TerraformCloud]: ["variableSetName", "workspaceName"],
|
||||||
|
[SecretSync.Camunda]: [],
|
||||||
|
[SecretSync.Vercel]: ["appName"],
|
||||||
|
[SecretSync.Windmill]: [],
|
||||||
|
[SecretSync.HCVault]: [],
|
||||||
|
[SecretSync.TeamCity]: [],
|
||||||
|
[SecretSync.OCIVault]: [],
|
||||||
|
[SecretSync.OnePass]: ["valueLabel"],
|
||||||
|
[SecretSync.Heroku]: ["appName"],
|
||||||
|
[SecretSync.Render]: [],
|
||||||
|
[SecretSync.Flyio]: [],
|
||||||
|
[SecretSync.GitLab]: [
|
||||||
|
"projectName",
|
||||||
|
"shouldProtectSecrets",
|
||||||
|
"shouldMaskSecrets",
|
||||||
|
"shouldHideSecrets",
|
||||||
|
"targetEnvironment",
|
||||||
|
"groupName",
|
||||||
|
"groupId",
|
||||||
|
"projectId"
|
||||||
|
],
|
||||||
|
[SecretSync.CloudflarePages]: [],
|
||||||
|
[SecretSync.CloudflareWorkers]: [],
|
||||||
|
[SecretSync.Supabase]: ["projectName"],
|
||||||
|
[SecretSync.Zabbix]: ["hostName", "macroType"],
|
||||||
|
[SecretSync.Railway]: ["projectName", "environmentName", "serviceName"],
|
||||||
|
[SecretSync.Checkly]: ["groupName", "accountName"],
|
||||||
|
[SecretSync.DigitalOceanAppPlatform]: ["appName"],
|
||||||
|
[SecretSync.Netlify]: ["accountName", "siteName"],
|
||||||
|
[SecretSync.Bitbucket]: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultDuplicateCheck: DestinationDuplicateCheckFn = () => true;
|
||||||
|
|
||||||
|
export const DESTINATION_DUPLICATE_CHECK_MAP: Record<SecretSync, DestinationDuplicateCheckFn> = {
|
||||||
|
[SecretSync.AWSParameterStore]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.AWSSecretsManager]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.GitHub]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.GCPSecretManager]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.AzureKeyVault]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.AzureAppConfiguration]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.AzureDevOps]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Databricks]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Humanitec]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.TerraformCloud]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Camunda]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Vercel]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Windmill]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.HCVault]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.TeamCity]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.OCIVault]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.OnePass]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Heroku]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Render]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Flyio]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.GitLab]: (existingConfig, newConfig) => {
|
||||||
|
const existingTargetEnv = existingConfig.targetEnvironment as string | undefined;
|
||||||
|
const newTargetEnv = newConfig.targetEnvironment as string | undefined;
|
||||||
|
|
||||||
|
const wildcardValues = ["*", ""];
|
||||||
|
// If either has wildcard, it conflicts with any targetEnvironment
|
||||||
|
if (
|
||||||
|
!existingTargetEnv ||
|
||||||
|
!newTargetEnv ||
|
||||||
|
wildcardValues.includes(existingTargetEnv) ||
|
||||||
|
wildcardValues.includes(newTargetEnv)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
existingTargetEnv === newTargetEnv &&
|
||||||
|
((newConfig.scope as string) === "group"
|
||||||
|
? existingConfig.groupId === newConfig.groupId
|
||||||
|
: existingConfig.projectId === newConfig.projectId)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[SecretSync.CloudflarePages]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.CloudflareWorkers]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Supabase]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Zabbix]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Railway]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Checkly]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.DigitalOceanAppPlatform]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Netlify]: defaultDuplicateCheck,
|
||||||
|
[SecretSync.Bitbucket]: defaultDuplicateCheck
|
||||||
|
};
|
||||||
|
|||||||
@@ -37,7 +37,12 @@ import {
|
|||||||
|
|
||||||
import { TSecretImportDALFactory } from "../secret-import/secret-import-dal";
|
import { TSecretImportDALFactory } from "../secret-import/secret-import-dal";
|
||||||
import { TSecretSyncDALFactory } from "./secret-sync-dal";
|
import { TSecretSyncDALFactory } from "./secret-sync-dal";
|
||||||
import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP } from "./secret-sync-maps";
|
import {
|
||||||
|
DESTINATION_DUPLICATE_CHECK_MAP,
|
||||||
|
SECRET_SYNC_CONNECTION_MAP,
|
||||||
|
SECRET_SYNC_NAME_MAP,
|
||||||
|
SECRET_SYNC_SKIP_FIELDS_MAP
|
||||||
|
} from "./secret-sync-maps";
|
||||||
import { TSecretSyncQueueFactory } from "./secret-sync-queue";
|
import { TSecretSyncQueueFactory } from "./secret-sync-queue";
|
||||||
|
|
||||||
type TSecretSyncServiceFactoryDep = {
|
type TSecretSyncServiceFactoryDep = {
|
||||||
@@ -698,83 +703,11 @@ export const secretSyncServiceFactory = ({
|
|||||||
return updatedSecretSync as TSecretSync;
|
return updatedSecretSync as TSecretSync;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSkipFieldsForDestination = (destination: SecretSync): string[] => {
|
|
||||||
switch (destination) {
|
|
||||||
case SecretSync.AWSSecretsManager:
|
|
||||||
return ["mappingBehavior", "secretName"];
|
|
||||||
case SecretSync.OnePass:
|
|
||||||
return ["valueLabel"];
|
|
||||||
case SecretSync.AzureAppConfiguration:
|
|
||||||
return ["label"];
|
|
||||||
case SecretSync.AzureDevOps:
|
|
||||||
return ["devopsProjectName"];
|
|
||||||
case SecretSync.Checkly:
|
|
||||||
return ["groupName", "accountName"];
|
|
||||||
case SecretSync.DigitalOceanAppPlatform:
|
|
||||||
return ["appName"];
|
|
||||||
case SecretSync.GitLab:
|
|
||||||
return [
|
|
||||||
"projectName",
|
|
||||||
"shouldProtectSecrets",
|
|
||||||
"shouldMaskSecrets",
|
|
||||||
"shouldHideSecrets",
|
|
||||||
"targetEnvironment",
|
|
||||||
"groupName",
|
|
||||||
"groupId",
|
|
||||||
"projectId"
|
|
||||||
];
|
|
||||||
case SecretSync.Heroku:
|
|
||||||
return ["appName"];
|
|
||||||
case SecretSync.Netlify:
|
|
||||||
return ["accountName", "siteName"];
|
|
||||||
case SecretSync.Railway:
|
|
||||||
return ["projectName", "environmentName", "serviceName"];
|
|
||||||
case SecretSync.Supabase:
|
|
||||||
return ["projectName"];
|
|
||||||
case SecretSync.TerraformCloud:
|
|
||||||
return ["variableSetName", "workspaceName"];
|
|
||||||
case SecretSync.Vercel:
|
|
||||||
return ["appName"];
|
|
||||||
case SecretSync.Zabbix:
|
|
||||||
return ["hostName", "macroType"];
|
|
||||||
default:
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSpecialCaseDuplicateCheck = (
|
|
||||||
destination: SecretSync,
|
|
||||||
existingConfig: Record<string, unknown>,
|
|
||||||
newConfig: Record<string, unknown>
|
|
||||||
): boolean => {
|
|
||||||
switch (destination) {
|
|
||||||
case SecretSync.GitLab: {
|
|
||||||
const existingTargetEnv = existingConfig.targetEnvironment as string | undefined;
|
|
||||||
const newTargetEnv = newConfig.targetEnvironment as string | undefined;
|
|
||||||
|
|
||||||
// If either has wildcard '*', it conflicts with any targetEnvironment
|
|
||||||
if (existingTargetEnv === "*" || newTargetEnv === "*") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
existingTargetEnv === newTargetEnv &&
|
|
||||||
((newConfig.scope as string) === "group"
|
|
||||||
? existingConfig.groupId === newConfig.groupId
|
|
||||||
: existingConfig.projectId === newConfig.projectId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// For other sync types, no special handling needed
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkDuplicateDestination = async (
|
const checkDuplicateDestination = async (
|
||||||
{ destination, destinationConfig, excludeSyncId, projectId }: TCheckDuplicateDestinationDTO,
|
{ destination, destinationConfig, excludeSyncId, projectId }: TCheckDuplicateDestinationDTO,
|
||||||
actor: OrgServiceActor
|
actor: OrgServiceActor
|
||||||
) => {
|
) => {
|
||||||
const skipFields = getSkipFieldsForDestination(destination);
|
const skipFields = SECRET_SYNC_SKIP_FIELDS_MAP[destination];
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor: actor.type,
|
actor: actor.type,
|
||||||
actorId: actor.id,
|
actorId: actor.id,
|
||||||
@@ -804,8 +737,7 @@ export const secretSyncServiceFactory = ({
|
|||||||
try {
|
try {
|
||||||
const baseFieldsMatch = deepEqualSkipFields(sync.destinationConfig, destinationConfig, skipFields);
|
const baseFieldsMatch = deepEqualSkipFields(sync.destinationConfig, destinationConfig, skipFields);
|
||||||
if (baseFieldsMatch) {
|
if (baseFieldsMatch) {
|
||||||
return handleSpecialCaseDuplicateCheck(
|
return DESTINATION_DUPLICATE_CHECK_MAP[destination](
|
||||||
destination,
|
|
||||||
sync.destinationConfig as Record<string, unknown>,
|
sync.destinationConfig as Record<string, unknown>,
|
||||||
destinationConfig
|
destinationConfig
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -415,3 +415,8 @@ export type TSecretMap = Record<
|
|||||||
secretMetadata?: ResourceMetadataDTO;
|
secretMetadata?: ResourceMetadataDTO;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export type DestinationDuplicateCheckFn = (
|
||||||
|
existingConfig: Record<string, unknown>,
|
||||||
|
newConfig: Record<string, unknown>
|
||||||
|
) => boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user