Merge branch 'main' into feat/vercelSecretSyncIntegration

This commit is contained in:
carlosmonastyrski
2025-04-09 09:15:52 -03:00
410 changed files with 14274 additions and 1902 deletions
+93 -5
View File
@@ -1,3 +1,8 @@
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
import {
SECRET_ROTATION_CONNECTION_MAP,
SECRET_ROTATION_NAME_MAP
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-maps";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { APP_CONNECTION_NAME_MAP } from "@app/services/app-connection/app-connection-maps";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
@@ -819,7 +824,8 @@ export const DASHBOARD = {
includeSecrets: "Whether to include project secrets in the response.",
includeFolders: "Whether to include project folders in the response.",
includeDynamicSecrets: "Whether to include dynamic project secrets in the response.",
includeImports: "Whether to include project secret imports in the response."
includeImports: "Whether to include project secret imports in the response.",
includeSecretRotations: "Whether to include project secret rotations in the response."
},
SECRET_DETAILS_LIST: {
projectId: "The ID of the project to list secrets/folders from.",
@@ -834,7 +840,8 @@ export const DASHBOARD = {
includeSecrets: "Whether to include project secrets in the response.",
includeFolders: "Whether to include project folders in the response.",
includeImports: "Whether to include project secret imports in the response.",
includeDynamicSecrets: "Whether to include dynamic project secrets in the response."
includeDynamicSecrets: "Whether to include dynamic project secrets in the response.",
includeSecretRotations: "Whether to include secret rotations in the response."
}
} as const;
@@ -1659,7 +1666,8 @@ export const AppConnections = {
name: `The name of the ${appName} Connection to create. Must be slug-friendly.`,
description: `An optional description for the ${appName} Connection.`,
credentials: `The credentials used to connect with ${appName}.`,
method: `The method used to authenticate with ${appName}.`
method: `The method used to authenticate with ${appName}.`,
isPlatformManagedCredentials: `Whether or not the ${appName} Connection credentials should be managed by Infisical. Once enabled this cannot be reversed.`
};
},
UPDATE: (app: AppConnection) => {
@@ -1669,12 +1677,25 @@ export const AppConnections = {
name: `The updated name of the ${appName} Connection. Must be slug-friendly.`,
description: `The updated description of the ${appName} Connection.`,
credentials: `The credentials used to connect with ${appName}.`,
method: `The method used to authenticate with ${appName}.`
method: `The method used to authenticate with ${appName}.`,
isPlatformManagedCredentials: `Whether or not the ${appName} Connection credentials should be managed by Infisical. Once enabled this cannot be reversed.`
};
},
DELETE: (app: AppConnection) => ({
connectionId: `The ID of the ${APP_CONNECTION_NAME_MAP[app]} Connection to be deleted.`
})
}),
CREDENTIALS: {
SQL_CONNECTION: {
host: "The hostname of the database server.",
port: "The port number of the database.",
database: "The name of the database to connect to.",
username: "The username to connect to the database with.",
password: "The password to connect to the database with.",
sslEnabled: "Whether or not to use SSL when connecting to the database.",
sslRejectUnauthorized: "Whether or not to reject unauthorized SSL certificates.",
sslCertificate: "The SSL certificate to use for connection."
}
}
};
export const SecretSyncs = {
@@ -1797,3 +1818,70 @@ export const SecretSyncs = {
}
}
};
export const SecretRotations = {
LIST: (type?: SecretRotation) => ({
projectId: `The ID of the project to list ${type ? SECRET_ROTATION_NAME_MAP[type] : "Secret"} Rotations from.`
}),
GET_BY_ID: (type: SecretRotation) => ({
rotationId: `The ID of the ${SECRET_ROTATION_NAME_MAP[type]} Rotation to retrieve.`
}),
GET_GENERATED_CREDENTIALS_BY_ID: (type: SecretRotation) => ({
rotationId: `The ID of the ${SECRET_ROTATION_NAME_MAP[type]} Rotation to retrieve the generated credentials for.`
}),
GET_BY_NAME: (type: SecretRotation) => ({
rotationName: `The name of the ${SECRET_ROTATION_NAME_MAP[type]} Rotation to retrieve.`,
projectId: `The ID of the project the ${SECRET_ROTATION_NAME_MAP[type]} Rotation is located in.`,
secretPath: `The secret path the ${SECRET_ROTATION_NAME_MAP[type]} Rotation is located at.`,
environment: `The environment the ${SECRET_ROTATION_NAME_MAP[type]} Rotation is located in.`
}),
CREATE: (type: SecretRotation) => {
const destinationName = SECRET_ROTATION_NAME_MAP[type];
return {
name: `The name of the ${destinationName} Rotation to create. Must be slug-friendly.`,
description: `An optional description for the ${destinationName} Rotation.`,
projectId: "The ID of the project to create the rotation in.",
environment: `The slug of the project environment to create the rotation in.`,
secretPath: `The secret path of the project to create the rotation in.`,
connectionId: `The ID of the ${
APP_CONNECTION_NAME_MAP[SECRET_ROTATION_CONNECTION_MAP[type]]
} Connection to use for rotation.`,
isAutoRotationEnabled: `Whether secrets should be automatically rotated when the specified rotation interval has elapsed.`,
rotationInterval: `The interval, in days, to automatically rotate secrets.`,
rotateAtUtc: `The hours and minutes rotation should occur at in UTC. Defaults to Midnight (00:00) UTC.`
};
},
UPDATE: (type: SecretRotation) => {
const typeName = SECRET_ROTATION_NAME_MAP[type];
return {
rotationId: `The ID of the ${typeName} Rotation to be updated.`,
name: `The updated name of the ${typeName} Rotation. Must be slug-friendly.`,
description: `The updated description of the ${typeName} Rotation.`,
isAutoRotationEnabled: `Whether secrets should be automatically rotated when the specified rotation interval has elapsed.`,
rotationInterval: `The updated interval, in days, to automatically rotate secrets.`,
rotateAtUtc: `The updated hours and minutes rotation should occur at in UTC.`
};
},
DELETE: (type: SecretRotation) => ({
rotationId: `The ID of the ${SECRET_ROTATION_NAME_MAP[type]} Rotation to be deleted.`,
deleteSecrets: `Whether the mapped secrets belonging to this rotation should be deleted.`,
revokeGeneratedCredentials: `Whether the generated credentials associated with this rotation should be revoked.`
}),
ROTATE: (type: SecretRotation) => ({
rotationId: `The ID of the ${SECRET_ROTATION_NAME_MAP[type]} Rotation to rotate generated credentials for.`
}),
PARAMETERS: {
SQL_CREDENTIALS: {
username1:
"The username of the first login to rotate passwords for. This user must already exists in your database.",
username2:
"The username of the second login to rotate passwords for. This user must already exists in your database."
}
},
SECRETS_MAPPING: {
SQL_CREDENTIALS: {
username: "The name of the secret that the active username will be mapped to.",
password: "The name of the secret that the generated password will be mapped to."
}
}
};
+3
View File
@@ -58,6 +58,7 @@ const envSchema = z
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),
QUEUE_WORKERS_ENABLED: zodStrBool.default("true"),
HTTPS_ENABLED: zodStrBool,
ROTATION_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
// smtp options
SMTP_HOST: zpStr(z.string().optional()),
SMTP_IGNORE_TLS: zodStrBool.default("false"),
@@ -192,6 +193,7 @@ const envSchema = z
GATEWAY_RELAY_REALM: zpStr(z.string().optional()),
GATEWAY_RELAY_AUTH_SECRET: zpStr(z.string().optional()),
DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"),
/* ----------------------------------------------------------------------------- */
/* App Connections ----------------------------------------------------------------------------- */
@@ -262,6 +264,7 @@ const envSchema = z
isSmtpConfigured: Boolean(data.SMTP_HOST),
isRedisConfigured: Boolean(data.REDIS_URL),
isDevelopmentMode: data.NODE_ENV === "development",
isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE,
isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED,
isSecretScanningConfigured:
+3 -1
View File
@@ -1,6 +1,8 @@
import { URL } from "url"; // Import the URL class
export const getDbConnectionHost = (urlString: string) => {
export const getDbConnectionHost = (urlString?: string) => {
if (!urlString) return null;
try {
const url = new URL(urlString);
// Split hostname and port (if provided)
+15 -5
View File
@@ -2,11 +2,17 @@ import { Knex } from "knex";
import { UnauthorizedError } from "../errors";
type TKnexDynamicPrimitiveOperator<T extends object> = {
operator: "eq" | "ne" | "startsWith" | "endsWith";
value: string;
field: Extract<keyof T, string>;
};
type TKnexDynamicPrimitiveOperator<T extends object> =
| {
operator: "eq" | "ne" | "startsWith" | "endsWith";
value: string;
field: Extract<keyof T, string>;
}
| {
operator: "notIn";
value: string[];
field: Extract<keyof T, string>;
};
type TKnexDynamicInOperator<T extends object> = {
operator: "in";
@@ -48,6 +54,10 @@ export const buildDynamicKnexQuery = <T extends object>(
void queryBuilder.whereILike(filterAst.field, `%${filterAst.value}`);
break;
}
case "notIn": {
void queryBuilder.whereNotIn(filterAst.field, filterAst.value);
break;
}
case "and": {
filterAst.value.forEach((el) => {
void queryBuilder.andWhere((subQueryBuilder) => {
@@ -7,7 +7,7 @@ export const prependTableNameToFindFilter = (tableName: TableName, filterObj: ob
Object.fromEntries(
Object.entries(filterObj).map(([key, value]) =>
key.startsWith("$")
? [key, prependTableNameToFindFilter(tableName, value as object)]
? [key, value ? prependTableNameToFindFilter(tableName, value as object) : value]
: [`${tableName}.${key}`, value]
)
);
+4 -2
View File
@@ -36,7 +36,8 @@ export enum CharacterType {
DoubleQuote = "doubleQuote", // "
Comma = "comma", // ,
Semicolon = "semicolon", // ;
Exclamation = "exclamation" // !
Exclamation = "exclamation", // !
Fullstop = "fullStop" // .
}
/**
@@ -81,7 +82,8 @@ export const characterValidator = (allowedCharacters: CharacterType[]) => {
[CharacterType.DoubleQuote]: '\\"',
[CharacterType.Comma]: ",",
[CharacterType.Semicolon]: ";",
[CharacterType.Exclamation]: "!"
[CharacterType.Exclamation]: "!",
[CharacterType.Fullstop]: "."
};
// Combine patterns from allowed characters