From 15b0b278775b95f32451e8409cae19b18ae55dac Mon Sep 17 00:00:00 2001 From: AlexRV12 <71396855+AlexRV12@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:12:20 +0200 Subject: [PATCH] chore: bump windmill-utils-internal to 1.8.3 and drop its workarounds (#11942) * chore: bump windmill-utils-internal to 1.8.3 and drop frontend workarounds * chore: resolve windmill-utils-internal 1.8.3 in the frontend lockfile --- cli/windmill-utils-internal/package-lock.json | 4 +- cli/windmill-utils-internal/package.json | 2 +- cli/windmill-utils-internal/src/deploy.ts | 6 +- .../src/inline-scripts/replacer.ts | 2 +- .../src/path-utils/path-assigner.ts | 2 +- frontend/package-lock.json | 8 +- frontend/package.json | 2 +- .../src/lib/utils_workspace_deploy.test.ts | 4 +- frontend/src/lib/utils_workspace_deploy.ts | 107 +++--------------- 9 files changed, 35 insertions(+), 102 deletions(-) diff --git a/cli/windmill-utils-internal/package-lock.json b/cli/windmill-utils-internal/package-lock.json index a2fb09f3dc..b9508332f0 100644 --- a/cli/windmill-utils-internal/package-lock.json +++ b/cli/windmill-utils-internal/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-utils-internal", - "version": "1.7.0", + "version": "1.8.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-utils-internal", - "version": "1.7.0", + "version": "1.8.3", "license": "Apache 2.0", "devDependencies": { "@types/node": "^24.2.0", diff --git a/cli/windmill-utils-internal/package.json b/cli/windmill-utils-internal/package.json index 525bb0fc0b..cf4138e6fc 100644 --- a/cli/windmill-utils-internal/package.json +++ b/cli/windmill-utils-internal/package.json @@ -1,6 +1,6 @@ { "name": "windmill-utils-internal", - "version": "1.8.2", + "version": "1.8.3", "description": "Internal utility functions for Windmill", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", diff --git a/cli/windmill-utils-internal/src/deploy.ts b/cli/windmill-utils-internal/src/deploy.ts index d73cb3562c..b2c11253af 100644 --- a/cli/windmill-utils-internal/src/deploy.ts +++ b/cli/windmill-utils-internal/src/deploy.ts @@ -926,7 +926,11 @@ export async function getItemValue( path, decryptSecret: true, }); - return variable.value; + return { + value: variable.value, + is_secret: variable.is_secret, + description: variable.description, + }; } else if (kind === "resource") { const resource = await provider.getResource({ workspace, path }); // Each workspace resolves its own agent identity, which a deploy never copies. diff --git a/cli/windmill-utils-internal/src/inline-scripts/replacer.ts b/cli/windmill-utils-internal/src/inline-scripts/replacer.ts index d926467b86..b6ed4a4376 100644 --- a/cli/windmill-utils-internal/src/inline-scripts/replacer.ts +++ b/cli/windmill-utils-internal/src/inline-scripts/replacer.ts @@ -190,7 +190,7 @@ export async function replacePathScriptsWithLocal( } const localScript = await scriptReader(toolValue.path); if (localScript) { - (tool as AiAgent["tools"][number]).value = { + (tool as NonNullable[number]).value = { tool_type: "flowmodule", type: "rawscript", content: localScript.content, diff --git a/cli/windmill-utils-internal/src/path-utils/path-assigner.ts b/cli/windmill-utils-internal/src/path-utils/path-assigner.ts index 6aaeea4db1..c718e64e0c 100644 --- a/cli/windmill-utils-internal/src/path-utils/path-assigner.ts +++ b/cli/windmill-utils-internal/src/path-utils/path-assigner.ts @@ -5,7 +5,7 @@ const INLINE_SCRIPT_PREFIX = "inline_script"; /** * Union type of all supported programming languages in Windmill */ -export type SupportedLanguage = RawScript["language"] | "frontend" | "bunnative" | "oracledb" | "rust" | "csharp" | "nu" | "ansible" | "java" | "duckdb"; +export type SupportedLanguage = RawScript["language"] | "frontend" | "bunnative" | "oracledb" | "rust" | "csharp" | "nu" | "ansible" | "java" | "duckdb" | "dbt"; /** * Mapping of supported languages to their file extensions diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 16d216ce25..c550f2d978 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -110,7 +110,7 @@ "windmill-parser-wasm-wac": "1.830.0", "windmill-parser-wasm-yaml": "1.770.0", "windmill-sql-datatype-parser-wasm": "1.512.0", - "windmill-utils-internal": "1.8.2", + "windmill-utils-internal": "1.8.3", "xterm": "^5.3.0", "xterm-readline": "^1.1.2", "y-monaco": "^0.1.4", @@ -14719,9 +14719,9 @@ "integrity": "sha512-uHNL8F72/Tf96xF3hOHnPDjkEyqXw7fNjcPJiUhth9sTQkcwUIoJMOdwm8/cs+j9kKVRJ4tgNYMHEBLylazp6g==" }, "node_modules/windmill-utils-internal": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/windmill-utils-internal/-/windmill-utils-internal-1.8.2.tgz", - "integrity": "sha512-Otdn4iCE0QiOtMKPdHX5I89oECfZa3vmO2jdLdSETf7MBSv/gw9gvQm3oUQ29ymIHXLeuhQk/ebPD+WYolQJEA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/windmill-utils-internal/-/windmill-utils-internal-1.8.3.tgz", + "integrity": "sha512-Lp8fVM/uHUvO6q01rIODIR46hTQ9D9R9BEiKoZHQqw9NJoy1OxhcsvX4usBbkXff/GbHlkWiQfZXCOn0ozJeKQ==", "license": "Apache 2.0" }, "node_modules/word-wrap": { diff --git a/frontend/package.json b/frontend/package.json index 3d7b92656d..98d33e5fb3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -177,7 +177,7 @@ "windmill-parser-wasm-wac": "1.830.0", "windmill-parser-wasm-yaml": "1.770.0", "windmill-sql-datatype-parser-wasm": "1.512.0", - "windmill-utils-internal": "1.8.2", + "windmill-utils-internal": "1.8.3", "xterm": "^5.3.0", "xterm-readline": "^1.1.2", "y-monaco": "^0.1.4", diff --git a/frontend/src/lib/utils_workspace_deploy.test.ts b/frontend/src/lib/utils_workspace_deploy.test.ts index b970600ee7..5db05d041a 100644 --- a/frontend/src/lib/utils_workspace_deploy.test.ts +++ b/frontend/src/lib/utils_workspace_deploy.test.ts @@ -32,8 +32,8 @@ vi.mock('$lib/gen', async (importOriginal) => ({ } })) -// The deploy runs the published shared package, whose variable body has no `labels`: this -// pins that the adapter still carries them until a version that does is installed. +// The variable body is built by the installed shared package: this pins that a deploy from the +// app sends the source's labels on create and on update. describe('deploying a variable to another workspace', () => { it('carries its labels on create and on update', async () => { for (const workspaceTo of ['lacks-it', 'has-it']) { diff --git a/frontend/src/lib/utils_workspace_deploy.ts b/frontend/src/lib/utils_workspace_deploy.ts index 9d5b5409b8..efa7f09115 100644 --- a/frontend/src/lib/utils_workspace_deploy.ts +++ b/frontend/src/lib/utils_workspace_deploy.ts @@ -186,30 +186,13 @@ export type AppIdentity = { email: string; permissionedAs: string } export type DeployConflict = { hit: boolean } /** - * `deployItem` overrides only the email half of the identity, while the body it builds - * spreads the *source* item — which carries the source workspace's permissioned_as, valid - * nowhere else since usernames are per-workspace. The key is therefore always overwritten: - * with the picked user's principal for a custom choice, and cleared otherwise so the - * backend derives the target's own from the email it is given. The shared `deployItem` - * does the same, but this app consumes the published package, so the rewrite has to exist - * on both sides until that version ships. - * - * An app carries both halves inside its `policy` instead, so it needs both stamped here: - * the published package leaves the policy untouched, and a source principal beside a - * target address is rejected as a pair naming two different accounts. - * - * A group kept as the target identity travels as its synthetic `group-*@windmill.dev` - * address, which an admin-created account holding it would win on the backend: known and - * accepted, see `users::permissioned_as_from_email`. - * - * An agent carries its principal inside its resource value, and is handed the chosen one as a - * principal, as a trigger is. Every read here drops the source's, so a diff never shows it and - * the published `deployItem` copies none; the write then stamps the chosen one, or none, which - * leaves the backend to make it the deployer's. + * `deployItem` takes the identity only as an email and clears the source workspace's + * principal, leaving the backend to derive the target's own from that email. When the user + * picked a specific user, their principal is known here, so it is stamped on the body: on a + * flow or script directly, and inside the `policy` for an app, which holds both halves. */ function makeProvider( onBehalfOfPrincipal?: string, - onBehalfOf?: string, /** * Refuse the writes the shared `deployItem` reaches for only when the item already exists in * the target, turning its silent switch to an update into a failure the caller can act on. @@ -219,48 +202,16 @@ function makeProvider( */ conflict?: DeployConflict ): DeployProvider { - const withPermissionedAs = >(requestBody: T): T => ({ - ...requestBody, - on_behalf_of: onBehalfOfPrincipal - }) + const withPermissionedAs = >(requestBody: T): T => + onBehalfOfPrincipal ? { ...requestBody, on_behalf_of: onBehalfOfPrincipal } : requestBody const withPolicyIdentity = >(app: T): T => - app.policy - ? { - ...app, - policy: { - ...app.policy, - on_behalf_of: onBehalfOfPrincipal, - on_behalf_of_email: onBehalfOf - } - } + onBehalfOfPrincipal && app.policy + ? { ...app, policy: { ...app.policy, on_behalf_of: onBehalfOfPrincipal } } : app - const agents = new Set() - const withAgentIdentity = >(requestBody: T, path: string): T => - agents.has(path) && requestBody.value && typeof requestBody.value === 'object' - ? { - ...requestBody, - value: onBehalfOf - ? { ...requestBody.value, on_behalf_of: onBehalfOf } - : requestBody.value, - preserve_on_behalf_of: onBehalfOf !== undefined - } - : requestBody const refuseUpdate = (): never => { if (conflict) conflict.hit = true throw new Error('item already exists in the target workspace') } - // The published package builds variable, resource and folder bodies field by field without - // `labels`, so carry the source item's across from the read `deployItem` does just before the - // write. One provider serves one deploy, so the read always belongs to the write that follows. - let sourceLabels: string[] | undefined - const readLabels = (item: T): T => { - sourceLabels = item.labels - return item - } - const withLabels = >(requestBody: T): T => ({ - ...requestBody, - labels: sourceLabels - }) return { existsFlowByPath: (p) => FlowService.existsFlowByPath(p), existsScriptByPath: (p) => ScriptService.existsScriptByPath(p), @@ -305,43 +256,21 @@ function makeProvider( getPublicSecretOfLatestVersionOfApp: (p) => AppService.getPublicSecretOfLatestVersionOfApp(p), getRawAppData: (p) => AppService.getRawAppData(p), deleteApp: (p) => AppService.deleteApp(p), - getVariable: (p) => VariableService.getVariable(p).then(readLabels), - createVariable: (p) => - VariableService.createVariable({ ...p, requestBody: withLabels(p.requestBody) }), - updateVariable: (p) => - VariableService.updateVariable({ ...p, requestBody: withLabels(p.requestBody) }), + getVariable: (p) => VariableService.getVariable(p), + createVariable: (p) => VariableService.createVariable(p), + updateVariable: (p) => VariableService.updateVariable(p), deleteVariable: (p) => VariableService.deleteVariable(p), - getResource: async (p) => { - const resource = readLabels(await ResourceService.getResource(p)) - if (resource.resource_type !== 'ai_agent' || !resource.value) return resource - agents.add(p.path) - const { on_behalf_of: _, ...value } = resource.value as Record - return { ...resource, value } - }, - createResource: (p) => - ResourceService.createResource({ - ...p, - requestBody: withAgentIdentity(withLabels(p.requestBody), p.requestBody.path) - }), - updateResource: (p) => - ResourceService.updateResource({ - ...p, - requestBody: withAgentIdentity(withLabels(p.requestBody), p.path) - }), + getResource: (p) => ResourceService.getResource(p), + createResource: (p) => ResourceService.createResource(p), + updateResource: (p) => ResourceService.updateResource(p), deleteResource: (p) => ResourceService.deleteResource(p), getResourceType: (p) => ResourceService.getResourceType(p), createResourceType: (p) => ResourceService.createResourceType(p), updateResourceType: (p) => ResourceService.updateResourceType(p), deleteResourceType: (p) => ResourceService.deleteResourceType(p), - getFolder: (p) => FolderService.getFolder(p).then(readLabels), - createFolder: (p) => - FolderService.createFolder({ ...p, requestBody: withLabels(p.requestBody) }), - // A folder with no labels reads back without the field, so clearing them needs an explicit []. - updateFolder: (p) => - FolderService.updateFolder({ - ...p, - requestBody: { ...p.requestBody, labels: sourceLabels ?? [] } - }), + getFolder: (p) => FolderService.getFolder(p), + createFolder: (p) => FolderService.createFolder(p), + updateFolder: (p) => FolderService.updateFolder(p), deleteFolder: (p) => FolderService.deleteFolder(p), // Triggers existsTriggerByKind: (kind, p) => triggerServiceFor(kind).exists(p), @@ -483,7 +412,7 @@ export async function deployItem( const conflict: DeployConflict | undefined = createOnly ? { hit: false } : undefined const result = await sharedDeployItem( - makeProvider(onBehalfOfPrincipal, onBehalfOf, conflict), + makeProvider(onBehalfOfPrincipal, conflict), kind as DeployKind, path, workspaceFrom,