mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 15:28:58 +00:00
misc: added handling for case enforcement
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasEnforceCapitalizationCol = await knex.schema.hasColumn(TableName.Project, "enforceCapitalization");
|
||||||
|
const hasAutoCapitalizationCol = await knex.schema.hasColumn(TableName.Project, "autoCapitalization");
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
if (!hasEnforceCapitalizationCol) {
|
||||||
|
t.boolean("enforceCapitalization").defaultTo(false).notNullable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAutoCapitalizationCol) {
|
||||||
|
t.boolean("autoCapitalization").defaultTo(false).alter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasEnforceCapitalizationCol = await knex.schema.hasColumn(TableName.Project, "enforceCapitalization");
|
||||||
|
const hasAutoCapitalizationCol = await knex.schema.hasColumn(TableName.Project, "autoCapitalization");
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
if (hasEnforceCapitalizationCol) {
|
||||||
|
t.dropColumn("enforceCapitalization");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAutoCapitalizationCol) {
|
||||||
|
t.boolean("autoCapitalization").defaultTo(true).alter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ export const ProjectsSchema = z.object({
|
|||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
slug: z.string(),
|
slug: z.string(),
|
||||||
autoCapitalization: z.boolean().default(true).nullable().optional(),
|
autoCapitalization: z.boolean().default(false).nullable().optional(),
|
||||||
orgId: z.string().uuid(),
|
orgId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
@@ -25,7 +25,8 @@ export const ProjectsSchema = z.object({
|
|||||||
kmsSecretManagerKeyId: z.string().uuid().nullable().optional(),
|
kmsSecretManagerKeyId: z.string().uuid().nullable().optional(),
|
||||||
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
|
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
|
||||||
description: z.string().nullable().optional(),
|
description: z.string().nullable().optional(),
|
||||||
type: z.string()
|
type: z.string(),
|
||||||
|
enforceCapitalization: z.boolean().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjects = z.infer<typeof ProjectsSchema>;
|
export type TProjects = z.infer<typeof ProjectsSchema>;
|
||||||
|
|||||||
@@ -1267,9 +1267,10 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
if (secrets.length)
|
|
||||||
|
if (secrets.length !== secretsWithNewName.length)
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Secret does not exist: ${secretsToUpdateStoredInDB.map((el) => el.key).join(",")}`
|
message: `Secret does not exist: ${secrets.map((el) => el.key).join(",")}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -544,8 +544,10 @@ export const projectServiceFactory = ({
|
|||||||
const updatedProject = await projectDAL.updateById(project.id, {
|
const updatedProject = await projectDAL.updateById(project.id, {
|
||||||
name: update.name,
|
name: update.name,
|
||||||
description: update.description,
|
description: update.description,
|
||||||
autoCapitalization: update.autoCapitalization
|
autoCapitalization: update.autoCapitalization,
|
||||||
|
enforceCapitalization: update.autoCapitalization
|
||||||
});
|
});
|
||||||
|
|
||||||
return updatedProject;
|
return updatedProject;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -567,7 +569,11 @@ export const projectServiceFactory = ({
|
|||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
|
||||||
|
|
||||||
const updatedProject = await projectDAL.updateById(projectId, { autoCapitalization });
|
const updatedProject = await projectDAL.updateById(projectId, {
|
||||||
|
autoCapitalization,
|
||||||
|
enforceCapitalization: autoCapitalization
|
||||||
|
});
|
||||||
|
|
||||||
return updatedProject;
|
return updatedProject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ type TSecretServiceFactoryDep = {
|
|||||||
secretDAL: TSecretDALFactory;
|
secretDAL: TSecretDALFactory;
|
||||||
secretTagDAL: TSecretTagDALFactory;
|
secretTagDAL: TSecretTagDALFactory;
|
||||||
secretVersionDAL: TSecretVersionDALFactory;
|
secretVersionDAL: TSecretVersionDALFactory;
|
||||||
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus" | "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus" | "findProjectBySlug" | "findById">;
|
||||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
|
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
|
||||||
folderDAL: Pick<
|
folderDAL: Pick<
|
||||||
TSecretFolderDALFactory,
|
TSecretFolderDALFactory,
|
||||||
@@ -1466,6 +1466,16 @@ export const secretServiceFactory = ({
|
|||||||
secretMetadata
|
secretMetadata
|
||||||
}: TCreateSecretRawDTO) => {
|
}: TCreateSecretRawDTO) => {
|
||||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||||
|
const project = await projectDAL.findById(projectId);
|
||||||
|
if (project.enforceCapitalization) {
|
||||||
|
if (secretName !== secretName.toUpperCase()) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Secret names must be in UPPERCASE per project requirements. You can disable this requirement in project settings."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const policy =
|
const policy =
|
||||||
actor === ActorType.USER && type === SecretType.Shared
|
actor === ActorType.USER && type === SecretType.Shared
|
||||||
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
||||||
@@ -1609,6 +1619,16 @@ export const secretServiceFactory = ({
|
|||||||
secretMetadata
|
secretMetadata
|
||||||
}: TUpdateSecretRawDTO) => {
|
}: TUpdateSecretRawDTO) => {
|
||||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||||
|
const project = await projectDAL.findById(projectId);
|
||||||
|
if (project.enforceCapitalization) {
|
||||||
|
if (newSecretName && newSecretName !== newSecretName.toUpperCase()) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Secret names must be in UPPERCASE per project requirements. You can disable this requirement in project settings."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const policy =
|
const policy =
|
||||||
actor === ActorType.USER && type === SecretType.Shared
|
actor === ActorType.USER && type === SecretType.Shared
|
||||||
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
||||||
@@ -1858,7 +1878,23 @@ export const secretServiceFactory = ({
|
|||||||
actor === ActorType.USER
|
actor === ActorType.USER
|
||||||
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
|
const project = await projectDAL.findById(projectId);
|
||||||
|
if (project.enforceCapitalization) {
|
||||||
|
const caseViolatingSecretKeys = inputSecrets
|
||||||
|
.filter((sec) => sec.secretKey !== sec.secretKey.toUpperCase())
|
||||||
|
.map((sec) => sec.secretKey);
|
||||||
|
|
||||||
|
if (caseViolatingSecretKeys.length) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Secret names must be in UPPERCASE per project requirements: ${caseViolatingSecretKeys.join(
|
||||||
|
", "
|
||||||
|
)}. You can disable this requirement in project settings`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval = await secretApprovalRequestService.generateSecretApprovalRequestV2Bridge({
|
const approval = await secretApprovalRequestService.generateSecretApprovalRequestV2Bridge({
|
||||||
policy,
|
policy,
|
||||||
@@ -1987,6 +2023,21 @@ export const secretServiceFactory = ({
|
|||||||
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
? await secretApprovalPolicyService.getSecretApprovalPolicy(projectId, environment, secretPath)
|
||||||
: undefined;
|
: undefined;
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
|
const project = await projectDAL.findById(projectId);
|
||||||
|
if (project.enforceCapitalization) {
|
||||||
|
const caseViolatingSecretKeys = inputSecrets
|
||||||
|
.filter((sec) => sec.newSecretName && sec.newSecretName !== sec.newSecretName.toUpperCase())
|
||||||
|
.map((sec) => sec.newSecretName);
|
||||||
|
|
||||||
|
if (caseViolatingSecretKeys.length) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Secret names must be in UPPERCASE per project requirements: ${caseViolatingSecretKeys.join(
|
||||||
|
", "
|
||||||
|
)}. You can disable this requirement in project settings`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval = await secretApprovalRequestService.generateSecretApprovalRequestV2Bridge({
|
const approval = await secretApprovalRequestService.generateSecretApprovalRequestV2Bridge({
|
||||||
policy,
|
policy,
|
||||||
|
|||||||
@@ -301,8 +301,8 @@
|
|||||||
"project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ",
|
"project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ",
|
||||||
"auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.",
|
"auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.",
|
||||||
"docs": "Infisical Docs",
|
"docs": "Infisical Docs",
|
||||||
"auto-capitalization": "Auto Capitalization",
|
"enforce-capitalization": "Enforce Capitalization",
|
||||||
"auto-capitalization-description": "According to standards, Infisical will automatically capitalize your keys. If you want to disable this feature, you can do so here."
|
"enforce-capitalization-description": "According to standards, Infisical enforces uppercase secret keys. If you want to disable this feature, you can do so here."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"signup": {
|
"signup": {
|
||||||
|
|||||||
@@ -289,8 +289,8 @@
|
|||||||
"project-id-description2": "Para más guías, incluyendo ejemplos de código en diferentes lenguajes y frameworks, visita ",
|
"project-id-description2": "Para más guías, incluyendo ejemplos de código en diferentes lenguajes y frameworks, visita ",
|
||||||
"auto-generated": "Este es el ID único y autogenerado de proyecto. No se puede modificar.",
|
"auto-generated": "Este es el ID único y autogenerado de proyecto. No se puede modificar.",
|
||||||
"docs": "Documentación de Infisical",
|
"docs": "Documentación de Infisical",
|
||||||
"auto-capitalization": "Mayúsculas automáticas",
|
"enforce-capitalization": "Hacer cumplir la capitalización",
|
||||||
"auto-capitalization-description": "De acuerdo con los estándares, Infisical pondrá en mayúsculas tus claves. Si quieres desactivar esta funcionalidad, lo puedes hacer aquí."
|
"enforce-capitalization-description": "Según los estándares, Infisical aplica claves secretas en mayúsculas. Si desea desactivar esta función, puede hacerlo aquí."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"signup": {
|
"signup": {
|
||||||
|
|||||||
@@ -266,8 +266,8 @@
|
|||||||
"project-id-description2": "Para obter mais orientações, incluindo trechos de código para várias linguagens e frameworks, consulte ",
|
"project-id-description2": "Para obter mais orientações, incluindo trechos de código para várias linguagens e frameworks, consulte ",
|
||||||
"auto-generated": "Este é o identificador exclusivo - gerado automaticamente - do seu projeto. Não pode ser alterado.",
|
"auto-generated": "Este é o identificador exclusivo - gerado automaticamente - do seu projeto. Não pode ser alterado.",
|
||||||
"docs": "Documentação do Infisical",
|
"docs": "Documentação do Infisical",
|
||||||
"auto-capitalization": "Converter em caixa alta automaticamente",
|
"enforce-capitalization": "Aplicar capitalização",
|
||||||
"auto-capitalization-description": "Por padrão, Infisical converte automaticamente as chaves em caixa alta. Se você quiser desativar essa funcionalidade, pode fazê-lo aqui."
|
"enforce-capitalization-description": "De acordo com os padrões, o Infisical impõe chaves secretas em letras maiúsculas. Se quiser desabilitar esse recurso, você pode fazer isso aqui."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"signup": {
|
"signup": {
|
||||||
|
|||||||
+2
-2
@@ -169,8 +169,8 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
|
|||||||
|
|
||||||
if (!secretKey || isWholeKeyHighlighted) {
|
if (!secretKey || isWholeKeyHighlighted) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const keyStr = currentWorkspace.autoCapitalization ? key.toUpperCase() : key;
|
||||||
setValue("key", key);
|
setValue("key", keyStr);
|
||||||
if (value) {
|
if (value) {
|
||||||
setValue("value", value);
|
setValue("value", value);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -125,8 +125,8 @@ export const CreateSecretForm = ({
|
|||||||
|
|
||||||
if (!secretKey || isWholeKeyHighlighted) {
|
if (!secretKey || isWholeKeyHighlighted) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const keyStr = autoCapitalize ? key.toUpperCase() : key;
|
||||||
setValue("key", key);
|
setValue("key", keyStr);
|
||||||
if (value) {
|
if (value) {
|
||||||
setValue("value", value);
|
setValue("value", value);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -37,7 +37,7 @@ export const AutoCapitalizationSection = () => {
|
|||||||
|
|
||||||
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">
|
||||||
<p className="mb-3 text-xl font-semibold">{t("settings.project.auto-capitalization")}</p>
|
<p className="mb-3 text-xl font-semibold">{t("settings.project.enforce-capitalization")}</p>
|
||||||
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<div className="w-max">
|
<div className="w-max">
|
||||||
@@ -50,7 +50,7 @@ export const AutoCapitalizationSection = () => {
|
|||||||
handleToggleCapitalizationToggle(state as boolean);
|
handleToggleCapitalizationToggle(state as boolean);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("settings.project.auto-capitalization-description")}
|
{t("settings.project.enforce-capitalization-description")}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user