diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 0ac2c8764..c2cae374a 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -1803,7 +1803,7 @@ export const AppConnections = { clientSecret: "The client secret used to authenticate with Camunda." }, WINDMILL: { - instanceUrl: "The Windmill instance URL to connect with (defaults to https://dev.windmill.app).", + instanceUrl: "The Windmill instance URL to connect with (defaults to https://app.windmill.dev).", accessToken: "The access token to use to connect with Windmill." } } diff --git a/backend/src/services/app-connection/windmill/windmill-connection-schemas.ts b/backend/src/services/app-connection/windmill/windmill-connection-schemas.ts index b3f079bb6..eb7f74ecd 100644 --- a/backend/src/services/app-connection/windmill/windmill-connection-schemas.ts +++ b/backend/src/services/app-connection/windmill/windmill-connection-schemas.ts @@ -44,7 +44,7 @@ export const ValidateWindmillConnectionCredentialsSchema = z.discriminatedUnion( z.object({ method: z .literal(WindmillConnectionMethod.AccessToken) - .describe(AppConnections?.CREATE(AppConnection.Windmill).method), + .describe(AppConnections.CREATE(AppConnection.Windmill).method), credentials: WindmillConnectionAccessTokenCredentialsSchema.describe( AppConnections.CREATE(AppConnection.Windmill).credentials ) diff --git a/backend/src/services/secret-sync/windmill/windmill-sync-fns.ts b/backend/src/services/secret-sync/windmill/windmill-sync-fns.ts index 557de2f38..2e2c36740 100644 --- a/backend/src/services/secret-sync/windmill/windmill-sync-fns.ts +++ b/backend/src/services/secret-sync/windmill/windmill-sync-fns.ts @@ -36,11 +36,11 @@ const listWindmillVariables = async ({ instanceUrl, workspace, accessToken, path } ); - // eslint-disable-next-line no-await-in-loop - for await (const variable of variablesPage) { + for (const variable of variablesPage) { const variableName = variable.path.replace(path, ""); if (variable.is_secret) { + // eslint-disable-next-line no-await-in-loop const { data: variableValue } = await request.get( `${instanceUrl}/api/w/${workspace}/variables/get_value/${variable.path}`, { diff --git a/backend/src/services/secret-sync/windmill/windmill-sync-schemas.ts b/backend/src/services/secret-sync/windmill/windmill-sync-schemas.ts index dcf402d71..5740e21c9 100644 --- a/backend/src/services/secret-sync/windmill/windmill-sync-schemas.ts +++ b/backend/src/services/secret-sync/windmill/windmill-sync-schemas.ts @@ -30,9 +30,9 @@ const WindmillSyncDestinationConfigSchema = z.object({ val.split("/").length >= 3 && val .split("/") - .filter(Boolean) - .every((segment) => pathCharacterValidator(segment)), - 'Invalid path - must follow Windmill path format. ex: "/f/folder/path/"' + .slice(0, -1) // Remove last empty segment from trailing slash + .every((segment) => segment && pathCharacterValidator(segment)), + 'Invalid path - must follow Windmill path format. ex: "f/folder/path/"' ) .describe(SecretSyncs.DESTINATION_CONFIG.WINDMILL.path) }); diff --git a/docs/integrations/app-connections/windmill.mdx b/docs/integrations/app-connections/windmill.mdx index fef0ade5b..a87ed2658 100644 --- a/docs/integrations/app-connections/windmill.mdx +++ b/docs/integrations/app-connections/windmill.mdx @@ -7,8 +7,18 @@ Infisical supports connecting to Windmill using an **Access Token** to securely ## Get a Windmill Access Token +Ensure the user generating the access token has the required role and permissions based on your use-case: + + + + The user generating the access token should be at least a `Developer` in the configured workspace and have `write` permissions for the workspace path secrets will be synced to. + + + + + - + In Windmill, click on your user in the sidebar and select **Account Settings**. ![Windmill Account Settings](/images/app-connections/windmill/windmill-account-settings.png) @@ -25,7 +35,7 @@ Infisical supports connecting to Windmill using an **Access Token** to securely Copy your new access token and save it for the steps below. - ![Windmill Create Token](/images/app-connections/windmill/windmill-copy-token.png) + ![Windmill Copy Token](/images/app-connections/windmill/windmill-copy-token.png) diff --git a/docs/integrations/secret-syncs/windmill.mdx b/docs/integrations/secret-syncs/windmill.mdx index d92c0dc0c..90d35f8b8 100644 --- a/docs/integrations/secret-syncs/windmill.mdx +++ b/docs/integrations/secret-syncs/windmill.mdx @@ -6,7 +6,7 @@ description: "Learn how to configure a Windmill Sync for Infisical." **Prerequisites:** - Set up and add secrets to [Infisical Cloud](https://app.infisical.com) - - Create a [Windmill Connection](/integrations/app-connections/windmill) + - Create a [Windmill Connection](/integrations/app-connections/windmill) with the required **Secret Sync** permissions @@ -42,7 +42,7 @@ description: "Learn how to configure a Windmill Sync for Infisical." - **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync. - **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical. - - **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over Vercel when keys conflict. + - **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over Windmill when keys conflict. - **Import Secrets (Prioritize Windmill)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Windmill over Infisical when keys conflict. - **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only. - **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical. diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/WindmillSyncFields.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/WindmillSyncFields.tsx index e31bfc156..8578fa63c 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/WindmillSyncFields.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/WindmillSyncFields.tsx @@ -72,6 +72,8 @@ export const WindmillSyncFields = () => { )} /> ( { )} - control={control} - name="destinationConfig.path" /> ); diff --git a/frontend/src/components/secret-syncs/forms/schemas/windmill-sync-destination-schema.ts b/frontend/src/components/secret-syncs/forms/schemas/windmill-sync-destination-schema.ts index 15f5b249b..242f77140 100644 --- a/frontend/src/components/secret-syncs/forms/schemas/windmill-sync-destination-schema.ts +++ b/frontend/src/components/secret-syncs/forms/schemas/windmill-sync-destination-schema.ts @@ -7,14 +7,14 @@ export const WindmillSyncDestinationSchema = BaseSecretSyncSchema().merge( z.object({ destination: z.literal(SecretSync.Windmill), destinationConfig: z.object({ - workspace: z.string().trim().min(1, "Project required"), + workspace: z.string().trim().min(1, "Workspace required"), path: z .string() .trim() - .min(1, "Project required") + .min(1, "Path required") .regex( /^([uf])\/([a-zA-Z0-9_-]+)(\/[a-zA-Z0-9_-]+)*\/$/, - 'Invalid path - must follow Windmill path format. ex: "/f/folder/path/"' + 'Invalid path - must follow Windmill path format. ex: "f/folder/path/"' ) }) })