Moved tags to aws iam provider inputs

This commit is contained in:
carlosmonastyrski
2025-06-19 15:01:35 -03:00
parent b790dbb36f
commit 20f0eeed35
11 changed files with 45 additions and 68 deletions
@@ -1,21 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags");
if (!hasCol) {
await knex.schema.alterTable(TableName.DynamicSecret, (t) => {
t.jsonb("tags").nullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags");
if (hasCol) {
await knex.schema.alterTable(TableName.DynamicSecret, (t) => {
t.dropColumn("tags");
});
}
}
+1 -2
View File
@@ -29,8 +29,7 @@ export const DynamicSecretsSchema = z.object({
encryptedInput: zodBuffer, encryptedInput: zodBuffer,
projectGatewayId: z.string().uuid().nullable().optional(), projectGatewayId: z.string().uuid().nullable().optional(),
gatewayId: z.string().uuid().nullable().optional(), gatewayId: z.string().uuid().nullable().optional(),
usernameTemplate: z.string().nullable().optional(), usernameTemplate: z.string().nullable().optional()
tags: z.unknown().nullable().optional()
}); });
export type TDynamicSecrets = z.infer<typeof DynamicSecretsSchema>; export type TDynamicSecrets = z.infer<typeof DynamicSecretsSchema>;
@@ -80,7 +80,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1), environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name), name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name),
metadata: ResourceMetadataSchema.optional(), metadata: ResourceMetadataSchema.optional(),
tags: ResourceMetadataSchema.optional(),
usernameTemplate: userTemplateSchema.optional() usernameTemplate: userTemplateSchema.optional()
}), }),
response: { response: {
@@ -147,7 +146,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
.nullable(), .nullable(),
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(), newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(),
metadata: ResourceMetadataSchema.optional(), metadata: ResourceMetadataSchema.optional(),
tags: ResourceMetadataSchema.optional(),
usernameTemplate: userTemplateSchema.nullable().optional() usernameTemplate: userTemplateSchema.nullable().optional()
}) })
}), }),
@@ -166,7 +166,6 @@ export const dynamicSecretLeaseServiceFactory = ({
usernameTemplate: dynamicSecretCfg.usernameTemplate, usernameTemplate: dynamicSecretCfg.usernameTemplate,
identity, identity,
metadata: { projectId }, metadata: { projectId },
tags: dynamicSecretCfg.tags as Record<string, string>[] | undefined,
config config
}); });
} catch (error: unknown) { } catch (error: unknown) {
@@ -79,7 +79,6 @@ export const dynamicSecretServiceFactory = ({
defaultTTL, defaultTTL,
actorAuthMethod, actorAuthMethod,
metadata, metadata,
tags,
usernameTemplate usernameTemplate
}: TCreateDynamicSecretDTO) => { }: TCreateDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
@@ -166,8 +165,7 @@ export const dynamicSecretServiceFactory = ({
folderId: folder.id, folderId: folder.id,
name, name,
gatewayId: selectedGatewayId, gatewayId: selectedGatewayId,
usernameTemplate, usernameTemplate
tags: JSON.stringify(tags)
}, },
tx tx
); );
@@ -204,9 +202,10 @@ export const dynamicSecretServiceFactory = ({
actorOrgId, actorOrgId,
actorAuthMethod, actorAuthMethod,
metadata, metadata,
tags,
usernameTemplate usernameTemplate
}: TUpdateDynamicSecretDTO) => { }: TUpdateDynamicSecretDTO) => {
console.log({ inputs });
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
@@ -318,8 +317,7 @@ export const dynamicSecretServiceFactory = ({
name: newName ?? name, name: newName ?? name,
status: null, status: null,
gatewayId: selectedGatewayId, gatewayId: selectedGatewayId,
usernameTemplate, usernameTemplate
tags: JSON.stringify(tags)
}, },
tx tx
); );
@@ -23,7 +23,6 @@ export type TCreateDynamicSecretDTO = {
projectSlug: string; projectSlug: string;
metadata?: ResourceMetadataDTO; metadata?: ResourceMetadataDTO;
usernameTemplate?: string | null; usernameTemplate?: string | null;
tags?: ResourceMetadataDTO;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TUpdateDynamicSecretDTO = { export type TUpdateDynamicSecretDTO = {
@@ -36,7 +35,6 @@ export type TUpdateDynamicSecretDTO = {
inputs?: TProvider["inputs"]; inputs?: TProvider["inputs"];
projectSlug: string; projectSlug: string;
metadata?: ResourceMetadataDTO; metadata?: ResourceMetadataDTO;
tags?: ResourceMetadataDTO;
usernameTemplate?: string | null; usernameTemplate?: string | null;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
@@ -119,20 +119,20 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
identity?: { identity?: {
name: string; name: string;
}; };
tags?: Record<string, string>[];
metadata: { projectId: string }; metadata: { projectId: string };
}) => { }) => {
const { inputs, usernameTemplate, metadata, identity, tags } = data; const { inputs, usernameTemplate, metadata, identity } = data;
const providerInputs = await validateProviderInputs(inputs); const providerInputs = await validateProviderInputs(inputs);
console.log({ providerInputs, inputs });
const client = await $getClient(providerInputs, metadata.projectId); const client = await $getClient(providerInputs, metadata.projectId);
const username = generateUsername(usernameTemplate, identity); const username = generateUsername(usernameTemplate, identity);
const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs; const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs;
const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }]; const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }];
if (tags && Array.isArray(tags)) { if (providerInputs.tags && Array.isArray(providerInputs.tags)) {
const additionalTags = tags.map((tag) => ({ const additionalTags = providerInputs.tags.map((tag) => ({
Key: tag.key, Key: tag.key,
Value: tag.value Value: tag.value
})); }));
@@ -2,6 +2,7 @@ import RE2 from "re2";
import { z } from "zod"; import { z } from "zod";
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string"; import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
import { TDynamicSecretLeaseConfig } from "../../dynamic-secret-lease/dynamic-secret-lease-types"; import { TDynamicSecretLeaseConfig } from "../../dynamic-secret-lease/dynamic-secret-lease-types";
@@ -207,7 +208,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess(
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: ResourceMetadataSchema.optional()
}), }),
z.object({ z.object({
method: z.literal(AwsIamAuthType.AssumeRole), method: z.literal(AwsIamAuthType.AssumeRole),
@@ -217,7 +219,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess(
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: ResourceMetadataSchema.optional()
}) })
]) ])
); );
@@ -525,7 +528,6 @@ export type TDynamicProviderFns = {
name: string; name: string;
}; };
metadata: { projectId: string }; metadata: { projectId: string };
tags?: Record<string, string>[];
config?: TDynamicSecretLeaseConfig; config?: TDynamicSecretLeaseConfig;
}) => Promise<{ entityId: string; data: unknown }>; }) => Promise<{ entityId: string; data: unknown }>;
validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise<boolean>; validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise<boolean>;
@@ -34,7 +34,12 @@ const formSchema = z.object({
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: z
.array(
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
)
.optional()
}), }),
z.object({ z.object({
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole), method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
@@ -44,7 +49,12 @@ const formSchema = z.object({
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: z
.array(
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
)
.optional()
}) })
]), ]),
defaultTTL: z.string().superRefine((val, ctx) => { defaultTTL: z.string().superRefine((val, ctx) => {
@@ -69,12 +79,7 @@ const formSchema = z.object({
}), }),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
environment: z.object({ name: z.string(), slug: z.string() }), environment: z.object({ name: z.string(), slug: z.string() }),
usernameTemplate: z.string().nullable().optional(), usernameTemplate: z.string().nullable().optional()
tags: z
.array(
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
)
.optional()
}); });
type TForm = z.infer<typeof formSchema>; type TForm = z.infer<typeof formSchema>;
@@ -107,8 +112,7 @@ export const AwsIamInputForm = ({
usernameTemplate: "{{randomUsername}}", usernameTemplate: "{{randomUsername}}",
provider: { provider: {
method: DynamicSecretAwsIamAuth.AssumeRole method: DynamicSecretAwsIamAuth.AssumeRole
}, }
tags: []
} }
}); });
@@ -121,8 +125,7 @@ export const AwsIamInputForm = ({
provider, provider,
defaultTTL, defaultTTL,
environment, environment,
usernameTemplate, usernameTemplate
tags
}: TForm) => { }: TForm) => {
// wait till previous request is finished // wait till previous request is finished
if (createDynamicSecret.isPending) return; if (createDynamicSecret.isPending) return;
@@ -138,8 +141,7 @@ export const AwsIamInputForm = ({
projectSlug, projectSlug,
environmentSlug: environment.slug, environmentSlug: environment.slug,
usernameTemplate: usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate, !usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
tags
}); });
onCompleted(); onCompleted();
} catch { } catch {
@@ -408,7 +410,7 @@ export const AwsIamInputForm = ({
</FormControl> </FormControl>
)} )}
/> />
<MetadataForm control={control} name="tags" isValueRequired /> <MetadataForm control={control} name="provider.tags" title="Tags" isValueRequired />
{!isSingleEnvironmentMode && ( {!isSingleEnvironmentMode && (
<Controller <Controller
control={control} control={control}
@@ -23,7 +23,10 @@ const formSchema = z.object({
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: z
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
.optional(),
}), }),
z.object({ z.object({
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole), method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
@@ -33,7 +36,10 @@ const formSchema = z.object({
permissionBoundaryPolicyArn: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
userGroups: z.string().trim().optional(), userGroups: z.string().trim().optional(),
policyArns: z.string().trim().optional() policyArns: z.string().trim().optional(),
tags: z
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
.optional()
}) })
]), ]),
defaultTTL: z.string().superRefine((val, ctx) => { defaultTTL: z.string().superRefine((val, ctx) => {
@@ -58,9 +64,6 @@ const formSchema = z.object({
}) })
.nullable(), .nullable(),
newName: slugSchema().optional(), newName: slugSchema().optional(),
tags: z
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
.optional(),
usernameTemplate: z.string().trim().nullable().optional() usernameTemplate: z.string().trim().nullable().optional()
}); });
type TForm = z.infer<typeof formSchema>; type TForm = z.infer<typeof formSchema>;
@@ -95,7 +98,6 @@ export const EditDynamicSecretAwsIamForm = ({
inputs: { inputs: {
...(dynamicSecret.inputs as TForm["inputs"]) ...(dynamicSecret.inputs as TForm["inputs"])
}, },
tags: dynamicSecret.tags
} }
}); });
const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey; const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey;
@@ -107,8 +109,7 @@ export const EditDynamicSecretAwsIamForm = ({
maxTTL, maxTTL,
defaultTTL, defaultTTL,
newName, newName,
usernameTemplate, usernameTemplate
tags
}: TForm) => { }: TForm) => {
// wait till previous request is finished // wait till previous request is finished
if (updateDynamicSecret.isPending) return; if (updateDynamicSecret.isPending) return;
@@ -125,8 +126,7 @@ export const EditDynamicSecretAwsIamForm = ({
inputs, inputs,
newName: newName === dynamicSecret.name ? undefined : newName, newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate, !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
tags
} }
}); });
onClose(); onClose();
@@ -389,7 +389,7 @@ export const EditDynamicSecretAwsIamForm = ({
</FormControl> </FormControl>
)} )}
/> />
<MetadataForm control={control} name="tags" isValueRequired /> <MetadataForm control={control} name="inputs.tags" title="Tags" isValueRequired />
</div> </div>
</div> </div>
<div className="mt-4 flex items-center space-x-4"> <div className="mt-4 flex items-center space-x-4">
@@ -7,10 +7,12 @@ import { FormControl, FormLabel, IconButton, Input } from "@app/components/v2";
export const MetadataForm = ({ export const MetadataForm = ({
control, control,
name = "metadata", name = "metadata",
title = "Metadata",
isValueRequired = false isValueRequired = false
}: { }: {
control: Control<any>; control: Control<any>;
name?: string; name?: string;
title?: string;
isValueRequired?: boolean; isValueRequired?: boolean;
}) => { }) => {
const metadataFormFields = useFieldArray({ const metadataFormFields = useFieldArray({
@@ -19,7 +21,7 @@ export const MetadataForm = ({
}); });
return ( return (
<FormControl label={name.charAt(0).toUpperCase() + name.slice(1)}> <FormControl label={title}>
<div className="flex flex-col space-y-2"> <div className="flex flex-col space-y-2">
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => ( {metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
<div key={metadataFieldId} className="flex items-end space-x-2"> <div key={metadataFieldId} className="flex items-end space-x-2">