From 946a752cc00b3099817c9a9738d724379a3970b8 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Fri, 13 Mar 2026 16:43:43 +0100 Subject: [PATCH 01/33] chore: bump milaboratories.software-small-binaries to ^2.0.2 --- .changeset/new-islands-rhyme.md | 5 +++++ .vscode/settings.json | 2 ++ pnpm-workspace.yaml | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/new-islands-rhyme.md diff --git a/.changeset/new-islands-rhyme.md b/.changeset/new-islands-rhyme.md new file mode 100644 index 0000000000..853f0aba77 --- /dev/null +++ b/.changeset/new-islands-rhyme.md @@ -0,0 +1,5 @@ +--- +"@platforma-sdk/workflow-tengo": patch +--- + +fix: xsv converter can be launched in k8s installations. diff --git a/.vscode/settings.json b/.vscode/settings.json index 8f77820e27..77380d7d86 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,4 +50,6 @@ "platforma", "ptable" ], + "markdown.extension.completion.enabled": false, + "markdown.extension.tableFormatter.enabled": false, } diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 69c96cb363..e07ccd3caf 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -276,7 +276,7 @@ catalog: # SW "@milaboratories/software-pframes-conv": &pframes-version 2.2.9 - "@platforma-open/milaboratories.software-small-binaries": ^2.0.1 + "@platforma-open/milaboratories.software-small-binaries": ^2.0.2 "@platforma-open/milaboratories.software-test-utils": ^1.1.1 "@platforma-open/milaboratories.software-conda-empty": ^0.0.3 "@platforma-open/milaboratories.runenv-python-3": 1.7.4 From f49515858fe303c0141950574b998b15494f41ae Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Fri, 27 Mar 2026 20:03:44 +0100 Subject: [PATCH 02/33] fix: use busybox docker image and sh in logs.test.ts RunCommand needs dockerImageTag when runner has --runner-enable-docker (DockerSupportOnlyDocker mode). Changed bash to sh for busybox compat. --- lib/node/pl-drivers/src/drivers/logs.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index be4dd64924..b94f6a82d6 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -50,7 +50,7 @@ test("should get all logs", async () => { ); const logs = new LogsDriver(logger, logsStream, download); - await createRunCommandWithStdoutStream(client, "bash", ["-c", "echo 1; sleep 1; echo 2"]); + await createRunCommandWithStdoutStream(client, "sh", ["-c", "echo 1; sleep 1; echo 2"]); const c = Computable.make((ctx) => { const streamManager = ctx.accessor(tree.entry()).node().traverse("result")?.persist(); @@ -109,7 +109,7 @@ test("should get last line with a prefix", async () => { expect(await c.getValue()).toBeUndefined(); - await createRunCommandWithStdoutStream(client, "bash", [ + await createRunCommandWithStdoutStream(client, "sh", [ "-c", "echo PREFIX1; echo PREFIX2; echo 3; sleep 0.1; echo PREFIX4", ]); @@ -162,7 +162,7 @@ test("should get log smart object and get log lines from that", async () => { return logs.getLogHandle(streamManager, ctx); }); - await createRunCommandWithStdoutStream(client, "bash", ["-c", "echo 1; sleep 1; echo 2"]); + await createRunCommandWithStdoutStream(client, "sh", ["-c", "echo 1; sleep 1; echo 2"]); let handle = await c.getValue(); @@ -266,6 +266,7 @@ function createRunCommand( redirectStdout: "logs.txt", redirectStderr: "logs.txt", envs: [], + dockerImageTag: "busybox", }; const runCmdId = tx.createEphemeral({ name: "RunCommand/executor", version: "2" }); From 350cb9abba683913d37b60ac1272cd00840c8f5b Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 30 Mar 2026 12:13:14 +0200 Subject: [PATCH 03/33] fix: pl-drivers test timeout too short for K8s job scheduling --- lib/node/pl-drivers/vitest.config.mts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/node/pl-drivers/vitest.config.mts b/lib/node/pl-drivers/vitest.config.mts index 44a8aa24f0..5fb99050fb 100644 --- a/lib/node/pl-drivers/vitest.config.mts +++ b/lib/node/pl-drivers/vitest.config.mts @@ -4,6 +4,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig( createVitestConfig({ test: { + testTimeout: 30_000, coverage: { exclude: ["src/proto", "**/*.js"], }, From a2096333f72fc6825dc686c0d62fab983dfe16b6 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 30 Mar 2026 14:43:42 +0200 Subject: [PATCH 04/33] fix: pl-drivers tests time out with K8s Kueue scheduling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase global testTimeout from 30s to 90s — Kueue batch job scheduling adds ~30s overhead, causing all 3 logs.test.ts tests to hit the 30s limit in CI. --- lib/node/pl-drivers/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/pl-drivers/vitest.config.mts b/lib/node/pl-drivers/vitest.config.mts index 5fb99050fb..342e337093 100644 --- a/lib/node/pl-drivers/vitest.config.mts +++ b/lib/node/pl-drivers/vitest.config.mts @@ -4,7 +4,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig( createVitestConfig({ test: { - testTimeout: 30_000, + testTimeout: 90_000, coverage: { exclude: ["src/proto", "**/*.js"], }, From 9251bd96ac7241fe4592ce60372b20eb4273c511 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 30 Mar 2026 14:44:11 +0200 Subject: [PATCH 05/33] fixup! fix: pl-drivers tests time out with K8s Kueue scheduling --- lib/node/pl-drivers/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/pl-drivers/vitest.config.mts b/lib/node/pl-drivers/vitest.config.mts index 342e337093..d14fe8040f 100644 --- a/lib/node/pl-drivers/vitest.config.mts +++ b/lib/node/pl-drivers/vitest.config.mts @@ -4,7 +4,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig( createVitestConfig({ test: { - testTimeout: 90_000, + testTimeout: 300_000, coverage: { exclude: ["src/proto", "**/*.js"], }, From b4283e28c5752ff26386ae78888a7f821eb20350 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 30 Mar 2026 19:28:25 +0200 Subject: [PATCH 06/33] bump test deps --- pnpm-lock.yaml | 35 ++++++++++++++++++++--------------- pnpm-workspace.yaml | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed3b25f6f9..5e1cd746cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,8 +43,8 @@ catalogs: specifier: ^0.0.3 version: 0.0.3 '@platforma-open/milaboratories.software-small-binaries': - specifier: ^2.0.1 - version: 2.0.1 + specifier: ^2.0.3 + version: 2.0.3 '@platforma-open/milaboratories.software-test-utils': specifier: ^1.1.1 version: 1.1.1 @@ -2849,7 +2849,7 @@ importers: version: link:../../lib/ptexter '@platforma-open/milaboratories.software-small-binaries': specifier: 'catalog:' - version: 2.0.1 + version: 2.0.3 devDependencies: '@platforma-sdk/tengo-builder': specifier: workspace:* @@ -5042,14 +5042,17 @@ packages: '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.4': resolution: {integrity: sha512-cN8zSWqn2PzO7xI3XLkWNySEOZ5TACH4zzbgTSnG6lWsqk0z/9gkubvYe4GUVWm2pAlngSw/nEju8CdcD7xmNA==} - '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.2': - resolution: {integrity: sha512-qRKXBUpZJUb02yi3qTPvf0vTEPg3zLFUuD/pKMcSj3FJTiObnWn/HOlmW68m2mPEfEpvAOPRxoIR1eiRIk72NQ==} + '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.6': + resolution: {integrity: sha512-THFReXiKsW7WMhQXBEcYA8luz7ZoWazOzhI9fkoWwHqQNOqfthdeVbmZC4fIwemPkw+KBSDcR8huNW2vIt0o9w==} - '@platforma-open/milaboratories.software-small-binaries.table-converter@1.3.2': - resolution: {integrity: sha512-A6cTLbRtyooPSD6PLYdv2fak/IucuPc0H/sQZvAQ55SBRFFlbOoxKHw73apigCRJ5U6+kSQ+3TQa9lksU42t1A==} + '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.4': + resolution: {integrity: sha512-rLdqmqbAQgXzgV+bubFwX/f2iCyQeQnHxQKFu7v8FOj/iYcvQjrGrDc7iA6DXfKw1vAVtXxKBU45BmE2LzWKDg==} - '@platforma-open/milaboratories.software-small-binaries@2.0.1': - resolution: {integrity: sha512-gKWNwDWRmOfGLrJ25BL20eE4y7aD5yLB2abBcFoTiZfF9Z1F7lenFRAbpaZ7/TlcnCjD+Wf6dvcVL4EOVk00wQ==} + '@platforma-open/milaboratories.software-small-binaries.table-converter@1.3.4': + resolution: {integrity: sha512-2yjDPrVaseGYQC3MZIzcmtgsniuT/Ww5JltJ5i+ydUMAHJhUumqOeOZRhHAwfWJD1xRTWckZjxIZqX1TQnNhUA==} + + '@platforma-open/milaboratories.software-small-binaries@2.0.3': + resolution: {integrity: sha512-oluTZekUavkbqCnt+2zPGl3tuadRhznp485TxcKT7u7HvlgTXPbJ7KeCvYVTTAFBs5W9KW7GLyX3CtFtpSyg0g==} '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.0': resolution: {integrity: sha512-LJyDo1kfM2Cw6TE2mIi04ntLCReRYDGtw2pwAdry9fXXtP/EtGQTw3Sfe5Mq7i/d7Pg9oCpF1behBoH4Nly9Jw==} @@ -10951,16 +10954,18 @@ snapshots: '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.4': {} - '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.2': {} + '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.6': {} + + '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.4': {} - '@platforma-open/milaboratories.software-small-binaries.table-converter@1.3.2': {} + '@platforma-open/milaboratories.software-small-binaries.table-converter@1.3.4': {} - '@platforma-open/milaboratories.software-small-binaries@2.0.1': + '@platforma-open/milaboratories.software-small-binaries@2.0.3': dependencies: - '@platforma-open/milaboratories.software-small-binaries.hello-world': 1.1.4 + '@platforma-open/milaboratories.software-small-binaries.hello-world': 1.1.6 '@platforma-open/milaboratories.software-small-binaries.hello-world-py': 1.0.9 - '@platforma-open/milaboratories.software-small-binaries.mnz-client': 1.6.2 - '@platforma-open/milaboratories.software-small-binaries.table-converter': 1.3.2 + '@platforma-open/milaboratories.software-small-binaries.mnz-client': 1.6.4 + '@platforma-open/milaboratories.software-small-binaries.table-converter': 1.3.4 '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.0': {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e07ccd3caf..76634eaf9c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -276,7 +276,7 @@ catalog: # SW "@milaboratories/software-pframes-conv": &pframes-version 2.2.9 - "@platforma-open/milaboratories.software-small-binaries": ^2.0.2 + "@platforma-open/milaboratories.software-small-binaries": ^2.0.3 "@platforma-open/milaboratories.software-test-utils": ^1.1.1 "@platforma-open/milaboratories.software-conda-empty": ^0.0.3 "@platforma-open/milaboratories.runenv-python-3": 1.7.4 From 073d56178e4a77154ab730a6fe3b2185ef5794d2 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 30 Mar 2026 20:17:32 +0200 Subject: [PATCH 07/33] fix: increase timeout for 'should get all logs' test --- lib/node/pl-drivers/src/drivers/logs.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index b94f6a82d6..a8534a7a83 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -28,7 +28,7 @@ const downloadDriverOps = { rangesCacheMaxSizeBytes: 1024, }; -test("should get all logs", async () => { +test("should get all logs", { timeout: 300000 }, async () => { await TestHelpers.withTempRoot(async (client) => { const logger = new ConsoleLoggerAdapter(); From 81f0e5d7a8f43a811e4aaf0d775373fcdcef019a Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 31 Mar 2026 10:44:31 +0200 Subject: [PATCH 08/33] test: increase test timeout --- tests/drivers-ml-blocks-integration/src/ml-v3.test.ts | 2 +- tests/drivers-ml-blocks-integration/vitest.config.mts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers-ml-blocks-integration/src/ml-v3.test.ts b/tests/drivers-ml-blocks-integration/src/ml-v3.test.ts index 0df23e9b3a..78a7524127 100644 --- a/tests/drivers-ml-blocks-integration/src/ml-v3.test.ts +++ b/tests/drivers-ml-blocks-integration/src/ml-v3.test.ts @@ -1316,7 +1316,7 @@ blockTest( blockTest( "v3: should create blob-url-custom-protocol block, render it and gets outputs from its config", - { timeout: 30000 }, + { timeout: 90000 }, async ({ rawPrj: project, ml, expect }) => { const blockId = await project.addBlock("DownloadBlobUrl", downloadBlobURLSpec); diff --git a/tests/drivers-ml-blocks-integration/vitest.config.mts b/tests/drivers-ml-blocks-integration/vitest.config.mts index b0eeaa1d98..a202277275 100644 --- a/tests/drivers-ml-blocks-integration/vitest.config.mts +++ b/tests/drivers-ml-blocks-integration/vitest.config.mts @@ -4,7 +4,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig( createVitestConfig({ test: { - testTimeout: 10000, + testTimeout: 90000, }, }), ); From f54a312c7cc5c29417c9032d5f3bf61646d99190 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 31 Mar 2026 11:26:41 +0200 Subject: [PATCH 09/33] fix: increase test timeout to 60 seconds --- tests/workflow-tengo/src/pframes/proc_1.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workflow-tengo/src/pframes/proc_1.test.ts b/tests/workflow-tengo/src/pframes/proc_1.test.ts index 0bfb304a60..6c6ab651d9 100644 --- a/tests/workflow-tengo/src/pframes/proc_1.test.ts +++ b/tests/workflow-tengo/src/pframes/proc_1.test.ts @@ -5,7 +5,7 @@ import { assertBlob, assertJson, assertResource, eTplTest } from "./extended_tpl import { getLongTestTimeout } from "@milaboratories/test-helpers"; import { vi } from "vitest"; -const TIMEOUT = getLongTestTimeout(15_000); +const TIMEOUT = getLongTestTimeout(30_000); vi.setConfig({ testTimeout: TIMEOUT, From ef477fe1fe452a09c9c7115379e516097c854553 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 31 Mar 2026 19:10:32 +0200 Subject: [PATCH 10/33] fix: update test timeout to 60 seconds and ensure reporters are set --- lib/node/pl-drivers/vitest.config.mts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/node/pl-drivers/vitest.config.mts b/lib/node/pl-drivers/vitest.config.mts index d14fe8040f..caedd953a7 100644 --- a/lib/node/pl-drivers/vitest.config.mts +++ b/lib/node/pl-drivers/vitest.config.mts @@ -4,7 +4,8 @@ import { defineConfig } from "vitest/config"; export default defineConfig( createVitestConfig({ test: { - testTimeout: 300_000, + testTimeout: 90_000, + reporters: ["default", "github-actions"], // or just ["github-actions"] coverage: { exclude: ["src/proto", "**/*.js"], }, From 3dc2d4711f8b2085e62584cb2592e4e9205f666b Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 31 Mar 2026 19:44:26 +0200 Subject: [PATCH 11/33] fix: increase timeout for blob-url-custom-protocol block test to 90 seconds --- tests/drivers-ml-blocks-integration/src/ml-legacy.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers-ml-blocks-integration/src/ml-legacy.test.ts b/tests/drivers-ml-blocks-integration/src/ml-legacy.test.ts index 8e38d32517..bbcac020a7 100644 --- a/tests/drivers-ml-blocks-integration/src/ml-legacy.test.ts +++ b/tests/drivers-ml-blocks-integration/src/ml-legacy.test.ts @@ -1255,7 +1255,7 @@ blockTest( blockTest( "should create blob-url-custom-protocol block, render it and gets outputs from its config", - { timeout: 30000 }, + { timeout: 90000 }, async ({ rawPrj: project, ml, expect }) => { const blockId = await project.addBlock("DownloadBlobUrl", downloadBlobURLSpec); From 7e298f8891c21509b81e03dfb3f8ea168706c458 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 7 Apr 2026 10:41:20 +0200 Subject: [PATCH 12/33] fix: update test configuration to set timeout for 'should get all logs' test --- lib/node/pl-drivers/src/drivers/logs.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index a8534a7a83..e181a9883d 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -1,4 +1,4 @@ -import { expect, test } from "vitest"; +import { expect, test, vi } from "vitest"; import { Computable } from "@milaboratories/computable"; import type { AnyFieldRef, @@ -28,7 +28,11 @@ const downloadDriverOps = { rangesCacheMaxSizeBytes: 1024, }; -test("should get all logs", { timeout: 300000 }, async () => { +vi.setConfig({ + testTimeout: 60000, +}); + +test("should get all logs", async () => { await TestHelpers.withTempRoot(async (client) => { const logger = new ConsoleLoggerAdapter(); From f3b107018807dcfbb3d71a3c13e6c6f0153aa702 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 7 Apr 2026 17:00:28 +0200 Subject: [PATCH 13/33] fix: bump test docker images to published versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit software-test-utils.docker-images 1.1.0 → 1.1.1 software-conda-empty 0.0.3 → 1.0.1 Old versions referenced images not present in containers.pl-open.science, causing ImagePullBackOff on k8s batch job pods in e2e tests. --- pnpm-lock.yaml | 20 ++++++++++---------- pnpm-workspace.yaml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e1cd746cf..cd0a5d2a81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,8 +40,8 @@ catalogs: specifier: 1.7.4 version: 1.7.4 '@platforma-open/milaboratories.software-conda-empty': - specifier: ^0.0.3 - version: 0.0.3 + specifier: ^1.0.1 + version: 1.0.1 '@platforma-open/milaboratories.software-small-binaries': specifier: ^2.0.3 version: 2.0.3 @@ -3147,7 +3147,7 @@ importers: dependencies: '@platforma-open/milaboratories.software-conda-empty': specifier: 'catalog:' - version: 0.0.3 + version: 1.0.1 '@platforma-sdk/workflow-tengo': specifier: workspace:* version: link:../../sdk/workflow-tengo @@ -5030,8 +5030,8 @@ packages: '@platforma-open/milaboratories.runenv-python-3@1.7.4': resolution: {integrity: sha512-svzu4a3DVzbM1lkoY3ITO9jhXvN1NNI90IBIF3njs62zHqIOkMo6gps7yr3W6hRLJAAzGHZ3R5XjNLRTn3wBKQ==} - '@platforma-open/milaboratories.software-conda-empty@0.0.3': - resolution: {integrity: sha512-HC4MsQWBQZGNPVPkCpViGoqTUXFLLMh/VAJ5sxrprDT7DLm6ObTaYDIzVm3Iq0FcyFdZAemWyFwT/ILTHXxQOg==} + '@platforma-open/milaboratories.software-conda-empty@1.0.1': + resolution: {integrity: sha512-nftT6/lXdHvDu7Wedc3HCXiLrzHrIl7B4/8jRGgP5EAJy4agIrAk95Ht7/DGBzGIqXUkRdgN2XB46LxMWt1l3g==} '@platforma-open/milaboratories.software-ptabler.schema@1.13.19': resolution: {integrity: sha512-S1g5idMNu3KL2AdWKwivCgd0ZRwXrpCK+TkhAfuXBafezRwHAw0k+A1F62BY7OBA8pOGd5R7yvU2LpMpCnaPOQ==} @@ -5054,8 +5054,8 @@ packages: '@platforma-open/milaboratories.software-small-binaries@2.0.3': resolution: {integrity: sha512-oluTZekUavkbqCnt+2zPGl3tuadRhznp485TxcKT7u7HvlgTXPbJ7KeCvYVTTAFBs5W9KW7GLyX3CtFtpSyg0g==} - '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.0': - resolution: {integrity: sha512-LJyDo1kfM2Cw6TE2mIi04ntLCReRYDGtw2pwAdry9fXXtP/EtGQTw3Sfe5Mq7i/d7Pg9oCpF1behBoH4Nly9Jw==} + '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.1': + resolution: {integrity: sha512-R5GjUghsz2fFAW5NqK5FcxbXnLWHFoOXy6LecHIvcKLvGTOOavEZ6s1M6JHx41uV9G9yrhntB/kk0zpR3QApNA==} '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.3': resolution: {integrity: sha512-v45++DKXrOFmJQBZBiSymF3H1+IG4tFAwp6NYNOm1Ev2qKBsrXCcm0spRSFLuWm3nbZRYuOpIsqzHaNCErmyvA==} @@ -10944,7 +10944,7 @@ snapshots: '@platforma-open/milaboratories.runenv-python-3.12.10-rapids': 1.4.3 '@platforma-open/milaboratories.runenv-python-3.12.10-sccoda': 1.3.4 - '@platforma-open/milaboratories.software-conda-empty@0.0.3': {} + '@platforma-open/milaboratories.software-conda-empty@1.0.1': {} '@platforma-open/milaboratories.software-ptabler.schema@1.13.19': dependencies: @@ -10967,7 +10967,7 @@ snapshots: '@platforma-open/milaboratories.software-small-binaries.mnz-client': 1.6.4 '@platforma-open/milaboratories.software-small-binaries.table-converter': 1.3.4 - '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.0': {} + '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.1': {} '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.3': {} @@ -10989,7 +10989,7 @@ snapshots: dependencies: '@platforma-open/milaboratories.software-small-binaries.hello-world': 1.1.4 '@platforma-open/milaboratories.software-small-binaries.hello-world-py': 1.0.9 - '@platforma-open/milaboratories.software-test-utils.docker-images': 1.1.0 + '@platforma-open/milaboratories.software-test-utils.docker-images': 1.1.1 '@platforma-open/milaboratories.software-test-utils.guided-command': 1.1.3 '@platforma-open/milaboratories.software-test-utils.java-stub': 1.0.5 '@platforma-open/milaboratories.software-test-utils.python-stub': 1.0.5 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 76634eaf9c..036e320beb 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -278,7 +278,7 @@ catalog: "@milaboratories/software-pframes-conv": &pframes-version 2.2.9 "@platforma-open/milaboratories.software-small-binaries": ^2.0.3 "@platforma-open/milaboratories.software-test-utils": ^1.1.1 - "@platforma-open/milaboratories.software-conda-empty": ^0.0.3 + "@platforma-open/milaboratories.software-conda-empty": ^1.0.1 "@platforma-open/milaboratories.runenv-python-3": 1.7.4 # Test From 7b03070d51ab479e6e54e901530b3cb09b424f34 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Thu, 9 Apr 2026 14:42:38 +0200 Subject: [PATCH 14/33] fix: update software-test-utils version to 1.1.6 --- pnpm-lock.yaml | 4 ++-- pnpm-workspace.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd0a5d2a81..ab031fd494 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ catalogs: specifier: ^2.0.3 version: 2.0.3 '@platforma-open/milaboratories.software-test-utils': - specifier: ^1.1.1 - version: 1.1.1 + specifier: ^1.1.6 + version: 1.1.6 '@protobuf-ts/grpc-transport': specifier: 2.11.1 version: 2.11.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 036e320beb..f113d38748 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -277,7 +277,7 @@ catalog: "@milaboratories/software-pframes-conv": &pframes-version 2.2.9 "@platforma-open/milaboratories.software-small-binaries": ^2.0.3 - "@platforma-open/milaboratories.software-test-utils": ^1.1.1 + "@platforma-open/milaboratories.software-test-utils": ^1.1.6 "@platforma-open/milaboratories.software-conda-empty": ^1.0.1 "@platforma-open/milaboratories.runenv-python-3": 1.7.4 From c3995df439060f64c4bba23ea6fddf0128852e3a Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 13 Apr 2026 14:33:31 +0200 Subject: [PATCH 15/33] feat: increase test timeout and conditionally set docker image tag --- lib/node/pl-drivers/src/drivers/logs.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index e181a9883d..5b8c2af871 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -28,8 +28,10 @@ const downloadDriverOps = { rangesCacheMaxSizeBytes: 1024, }; +const useDocker = process.env.PL_TEST_USE_DOCKER === 'true'; + vi.setConfig({ - testTimeout: 60000, + testTimeout: 90000, }); test("should get all logs", async () => { @@ -265,13 +267,15 @@ function createRunCommand( value: arg, }; }); - const optsData = { + const optsData: Record = { errorLines: 200, redirectStdout: "logs.txt", redirectStderr: "logs.txt", envs: [], - dockerImageTag: "busybox", }; + if (useDocker) { + optsData.dockerImageTag = 'busybox'; + } const runCmdId = tx.createEphemeral({ name: "RunCommand/executor", version: "2" }); From 5f473c4e54946e4da012ff8cd3fddfbb58c62f32 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 13 Apr 2026 15:15:13 +0200 Subject: [PATCH 16/33] fix: standardize string quotes in logs.test.ts --- lib/node/pl-drivers/src/drivers/logs.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index 5b8c2af871..c8d68416e8 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -28,7 +28,7 @@ const downloadDriverOps = { rangesCacheMaxSizeBytes: 1024, }; -const useDocker = process.env.PL_TEST_USE_DOCKER === 'true'; +const useDocker = process.env.PL_TEST_USE_DOCKER === "true"; vi.setConfig({ testTimeout: 90000, @@ -274,7 +274,7 @@ function createRunCommand( envs: [], }; if (useDocker) { - optsData.dockerImageTag = 'busybox'; + optsData.dockerImageTag = "busybox"; } const runCmdId = tx.createEphemeral({ name: "RunCommand/executor", version: "2" }); From a042478b10c9b2bcd1d192881c9e79890a548e5f Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Wed, 22 Apr 2026 16:47:40 +0200 Subject: [PATCH 17/33] fix: pass PL_TEST_USE_DOCKER through turbo env Add PL_TEST_USE_DOCKER to passThroughEnv in turbo.json test task so docker image tags are set on test commands in k8s CI environment. --- turbo.json | 1 + 1 file changed, 1 insertion(+) diff --git a/turbo.json b/turbo.json index 4b97414d12..153f94790e 100644 --- a/turbo.json +++ b/turbo.json @@ -50,6 +50,7 @@ "PL_TEST_USER", "PL_TEST_PROXY", "PL_TEST_STORAGE_ID", + "PL_TEST_USE_DOCKER", "DEBUG", "MI_LICENSE", "PL_DOCKER_REGISTRY_PUSH_TO", From 8ab446310b1706a423b6e8841147c0b6a1c44601 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Wed, 22 Apr 2026 17:30:19 +0200 Subject: [PATCH 18/33] fix: release DownloadUrlDriver in tests to prevent vitest teardown errors --- lib/node/pl-drivers/src/drivers/download_url/driver.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts b/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts index 760228fe48..6926225aee 100644 --- a/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts +++ b/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts @@ -41,6 +41,7 @@ test("should download a tar archive and extracts its content and then deleted", expect(indexJsCode).toContain("use strict"); c.resetState(); + await driver.releaseAll(); }); }, 45000); @@ -68,6 +69,7 @@ test( expect(url2).not.toBeUndefined(); expect(url2?.error).not.toBeUndefined(); expect(url2?.url).toBeUndefined(); + await driver.releaseAll(); }); }, 60000, @@ -93,6 +95,7 @@ test("should abort a downloading process when we reset a state of a computable", const url2 = await c.getValue(); expect(url2).toBeUndefined(); + await driver.releaseAll(); }); }); From c738dbdb88bf4392abe68dd94a557eb48576a375 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Wed, 22 Apr 2026 18:37:08 +0200 Subject: [PATCH 19/33] fix: increase test timeout to 180 seconds for logs tests --- lib/node/pl-drivers/src/drivers/logs.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/pl-drivers/src/drivers/logs.test.ts b/lib/node/pl-drivers/src/drivers/logs.test.ts index c8d68416e8..ce8cdb6fbc 100644 --- a/lib/node/pl-drivers/src/drivers/logs.test.ts +++ b/lib/node/pl-drivers/src/drivers/logs.test.ts @@ -31,7 +31,7 @@ const downloadDriverOps = { const useDocker = process.env.PL_TEST_USE_DOCKER === "true"; vi.setConfig({ - testTimeout: 90000, + testTimeout: 180000, }); test("should get all logs", async () => { From 0b6a9c52047ccbea9f4820bdfc4fe2ca42738b79 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Wed, 22 Apr 2026 19:41:05 +0200 Subject: [PATCH 20/33] fix: update version specifier for software-test-utils to 1.1.6 in pnpm files --- pnpm-lock.yaml | 109 +++++++++++++++++++++++--------------------- pnpm-workspace.yaml | 2 +- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddaba4d466..bb6c798233 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,8 +52,8 @@ catalogs: specifier: ^2.0.3 version: 2.0.3 '@platforma-open/milaboratories.software-test-utils': - specifier: ^1.1.6 - version: 1.1.1 + specifier: 1.1.6 + version: 1.1.6 '@protobuf-ts/grpc-transport': specifier: 2.11.1 version: 2.11.1 @@ -800,7 +800,7 @@ importers: devDependencies: '@platforma-open/milaboratories.software-test-utils': specifier: 'catalog:' - version: 1.1.1 + version: 1.1.6 '@platforma-sdk/tengo-builder': specifier: workspace:* version: link:../../../../tools/tengo-builder @@ -1061,7 +1061,7 @@ importers: devDependencies: '@platforma-open/milaboratories.software-test-utils': specifier: 'catalog:' - version: 1.1.1 + version: 1.1.6 '@platforma-sdk/tengo-builder': specifier: workspace:* version: link:../../../../tools/tengo-builder @@ -1344,7 +1344,7 @@ importers: devDependencies: '@platforma-open/milaboratories.software-test-utils': specifier: 'catalog:' - version: 1.1.1 + version: 1.1.6 '@platforma-sdk/tengo-builder': specifier: workspace:* version: link:../../../../tools/tengo-builder @@ -3343,7 +3343,7 @@ importers: version: link:../../lib/node/ts-helpers '@platforma-open/milaboratories.software-test-utils': specifier: 'catalog:' - version: 1.1.1 + version: 1.1.6 '@platforma-sdk/tengo-builder': specifier: workspace:* version: link:../../tools/tengo-builder @@ -5233,15 +5233,18 @@ packages: '@platforma-open/milaboratories.software-conda-empty@1.0.1': resolution: {integrity: sha512-nftT6/lXdHvDu7Wedc3HCXiLrzHrIl7B4/8jRGgP5EAJy4agIrAk95Ht7/DGBzGIqXUkRdgN2XB46LxMWt1l3g==} + '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.10': + resolution: {integrity: sha512-16BGRLIrsVW+YIaXwWLX6Nbm80PS5mQJEclHhjNbRrRTLHPaKI4RygZfBC0lLNzvHBiTXU4Qkh1+WmdovkshDg==} + '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.9': resolution: {integrity: sha512-pCg5NZREkrzBqx7jXv14MQMGWh2nfB9JJMn4MoF0lYJjLGkXpyFyYSVErW8IIvbNHcFLE5tU1pG7zilP/wSPvg==} - '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.4': - resolution: {integrity: sha512-cN8zSWqn2PzO7xI3XLkWNySEOZ5TACH4zzbgTSnG6lWsqk0z/9gkubvYe4GUVWm2pAlngSw/nEju8CdcD7xmNA==} - '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.6': resolution: {integrity: sha512-THFReXiKsW7WMhQXBEcYA8luz7ZoWazOzhI9fkoWwHqQNOqfthdeVbmZC4fIwemPkw+KBSDcR8huNW2vIt0o9w==} + '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.7': + resolution: {integrity: sha512-CqXbfFld2l6Y/8rtcZXRPsa5kqNnaS3QWUxrcfMYwNxultbhLzjZGdqSR7ejV9xRWilXpeg6DdZJIKF3+KDH8g==} + '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.4': resolution: {integrity: sha512-rLdqmqbAQgXzgV+bubFwX/f2iCyQeQnHxQKFu7v8FOj/iYcvQjrGrDc7iA6DXfKw1vAVtXxKBU45BmE2LzWKDg==} @@ -5251,35 +5254,35 @@ packages: '@platforma-open/milaboratories.software-small-binaries@2.0.3': resolution: {integrity: sha512-oluTZekUavkbqCnt+2zPGl3tuadRhznp485TxcKT7u7HvlgTXPbJ7KeCvYVTTAFBs5W9KW7GLyX3CtFtpSyg0g==} - '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.1': - resolution: {integrity: sha512-R5GjUghsz2fFAW5NqK5FcxbXnLWHFoOXy6LecHIvcKLvGTOOavEZ6s1M6JHx41uV9G9yrhntB/kk0zpR3QApNA==} + '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.2': + resolution: {integrity: sha512-KLih91Biwao8JcIk3J1zwQiHmiAzChgMfmcVqUxXjoipZPSc43OBwqX4x8sarSZCWSzUBLT5bfLWO5VG8kJaRg==} - '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.3': - resolution: {integrity: sha512-v45++DKXrOFmJQBZBiSymF3H1+IG4tFAwp6NYNOm1Ev2qKBsrXCcm0spRSFLuWm3nbZRYuOpIsqzHaNCErmyvA==} + '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.6': + resolution: {integrity: sha512-wzsuP40HBaao04npEI7Diq/5dAhpSZvIJDZzrqWUmJ5UHsEw/3aOE2SASW/W4vWEsu3EBmne0b7HoHVN2KF6Jw==} - '@platforma-open/milaboratories.software-test-utils.java-stub@1.0.5': - resolution: {integrity: sha512-73JkM/EtaRXNFVq+MlFPw1+RQ56ldbuC4spLw2DoKhyP2UStA5kqVUZObyKe9SZpWjJpQ1nDhCCSx4X472We8Q==} + '@platforma-open/milaboratories.software-test-utils.java-stub@1.0.6': + resolution: {integrity: sha512-D3MzMj/6v8ssGRvLbrc4b/rI6iFsKJt83z7UqycvMZLyP9IEGhdcQMdgCpe2JemrR6Mqn+E70BR4zzqD6vB3nA==} - '@platforma-open/milaboratories.software-test-utils.python-stub@1.0.5': - resolution: {integrity: sha512-tGt9KL65zZsCrtzU9szE+9qlsJkE2i99wb2qKCspAq5xxBEBVHI336xrJeAWo7XjdKwlFsLPIEweguprlEew1w==} + '@platforma-open/milaboratories.software-test-utils.python-stub@1.0.6': + resolution: {integrity: sha512-07AXO1UXuQfE2jrPs1UKONTdSujmQu+EZgEEZFZMqQwH2yaHOCGWdmeNSuXCTA/RF3+cPup4W4zMmQw+aTs1Mw==} - '@platforma-open/milaboratories.software-test-utils.read-with-sleep@1.1.3': - resolution: {integrity: sha512-H+DuQ86tsHqv+fKlhcaGkRcg+Yzfesov37qN51TtITFbVYZc9FM5kPHpoXc7QXbPAnXCe4qx1qu3SG3hrcAMbA==} + '@platforma-open/milaboratories.software-test-utils.read-with-sleep@1.1.6': + resolution: {integrity: sha512-8Pg46xK1I+G5NMkQnryTJEAwaq/86tshJ6e7sV9YJfWmeHjiv1jCSUP4bDM5dRNLk/0sKjhEJ4swpZkbe6eJAA==} - '@platforma-open/milaboratories.software-test-utils.runenv-java-stub@1.0.7': - resolution: {integrity: sha512-E+C3meLzp7Alo56S//fQVbtsrHq3IbUX5LfbZIgT9zBoX0r2iM0hj4JZuHDSsvLoCDAPFHFsZ4j4KalJj52seQ==} + '@platforma-open/milaboratories.software-test-utils.runenv-java-stub@1.0.8': + resolution: {integrity: sha512-yuvhpZQ3ErsGJnOhjw285QMfCICM17tmM74mNAQyN0YXFHOs6mLcdL/KMH98SB5Y4dQxIyqGqQJWfYMqZOWHIQ==} - '@platforma-open/milaboratories.software-test-utils.runenv-python-stub@1.0.8': - resolution: {integrity: sha512-/8zTUvq/0WPXVVRnfPw9vlW/4VDljjVHHZ0CV3LvhGyHuGwV2wWxjSV5iZQnBUtUI4RvRSdAgLrLTmh0kYvyKg==} + '@platforma-open/milaboratories.software-test-utils.runenv-python-stub@1.0.9': + resolution: {integrity: sha512-0NjzM+vBOMhN13frMxHoeX5lcKTW0tYrgfIAY0zRprXxluUm/tFm31PYIOI9zPHY6STrExQ3fq5ZJQTAXs7Ckw==} - '@platforma-open/milaboratories.software-test-utils.sleep@1.1.3': - resolution: {integrity: sha512-c/ifFAzIZXuCMIcvcGJu5CxahyII6cJs2K1IxOccuGHMD88UsHKW4+W0F8oJ8jsyML1dx5AR9LTRqnGDVFpyJg==} + '@platforma-open/milaboratories.software-test-utils.sleep@1.1.6': + resolution: {integrity: sha512-Tm/cNLbB82NKiBf84glhALN8gAJIA6S3oAotvTFxlsg7KPGd1Lzt5I0cKol6o8ykZEu19cfpgjhZ5R6iCQWf2Q==} - '@platforma-open/milaboratories.software-test-utils.small-asset@1.1.6': - resolution: {integrity: sha512-bYxb22fq1MkSTq+nucQSsy4b/h/D4PRsZCoKGYEcEstDJwffRo4OZNwG+Oh/Ru+P8w3VRcprK744TPbU/IXFZg==} + '@platforma-open/milaboratories.software-test-utils.small-asset@1.1.7': + resolution: {integrity: sha512-c+ChMmsXglruBhiOABTcrkoRk/guh0Mtp6ZQmYJNKYmNAMfwkV4WsjZbl1sUuh1v5PNw5AdeiRdxkPc6XvIeWw==} - '@platforma-open/milaboratories.software-test-utils@1.1.1': - resolution: {integrity: sha512-hifh8Y27H5F/nGW2zvk1/PV7Qyx7qI5s7CiZsstHbGHAm0+cUEGI09ZcFbFpBfKzdX2Qu73U5BiUPHevGGlpeQ==} + '@platforma-open/milaboratories.software-test-utils@1.1.6': + resolution: {integrity: sha512-J8pfFRfKtwU0YEkYb0mCIP0lqPst0pRfZdZy4Gn0jsJIutLYwPKolLlEdV12ziPBZ1VK73TVRZuRh4O/sM4Now==} '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} @@ -11371,12 +11374,14 @@ snapshots: '@platforma-open/milaboratories.software-conda-empty@1.0.1': {} - '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.9': {} + '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.10': {} - '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.4': {} + '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.9': {} '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.6': {} + '@platforma-open/milaboratories.software-small-binaries.hello-world@1.1.7': {} + '@platforma-open/milaboratories.software-small-binaries.mnz-client@1.6.4': {} '@platforma-open/milaboratories.software-small-binaries.table-converter@1.3.4': {} @@ -11388,37 +11393,37 @@ snapshots: '@platforma-open/milaboratories.software-small-binaries.mnz-client': 1.6.4 '@platforma-open/milaboratories.software-small-binaries.table-converter': 1.3.4 - '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.1': {} + '@platforma-open/milaboratories.software-test-utils.docker-images@1.1.2': {} - '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.3': {} + '@platforma-open/milaboratories.software-test-utils.guided-command@1.1.6': {} - '@platforma-open/milaboratories.software-test-utils.java-stub@1.0.5': {} + '@platforma-open/milaboratories.software-test-utils.java-stub@1.0.6': {} - '@platforma-open/milaboratories.software-test-utils.python-stub@1.0.5': {} + '@platforma-open/milaboratories.software-test-utils.python-stub@1.0.6': {} - '@platforma-open/milaboratories.software-test-utils.read-with-sleep@1.1.3': {} + '@platforma-open/milaboratories.software-test-utils.read-with-sleep@1.1.6': {} - '@platforma-open/milaboratories.software-test-utils.runenv-java-stub@1.0.7': {} + '@platforma-open/milaboratories.software-test-utils.runenv-java-stub@1.0.8': {} - '@platforma-open/milaboratories.software-test-utils.runenv-python-stub@1.0.8': {} + '@platforma-open/milaboratories.software-test-utils.runenv-python-stub@1.0.9': {} - '@platforma-open/milaboratories.software-test-utils.sleep@1.1.3': {} + '@platforma-open/milaboratories.software-test-utils.sleep@1.1.6': {} - '@platforma-open/milaboratories.software-test-utils.small-asset@1.1.6': {} + '@platforma-open/milaboratories.software-test-utils.small-asset@1.1.7': {} - '@platforma-open/milaboratories.software-test-utils@1.1.1': + '@platforma-open/milaboratories.software-test-utils@1.1.6': dependencies: - '@platforma-open/milaboratories.software-small-binaries.hello-world': 1.1.4 - '@platforma-open/milaboratories.software-small-binaries.hello-world-py': 1.0.9 - '@platforma-open/milaboratories.software-test-utils.docker-images': 1.1.1 - '@platforma-open/milaboratories.software-test-utils.guided-command': 1.1.3 - '@platforma-open/milaboratories.software-test-utils.java-stub': 1.0.5 - '@platforma-open/milaboratories.software-test-utils.python-stub': 1.0.5 - '@platforma-open/milaboratories.software-test-utils.read-with-sleep': 1.1.3 - '@platforma-open/milaboratories.software-test-utils.runenv-java-stub': 1.0.7 - '@platforma-open/milaboratories.software-test-utils.runenv-python-stub': 1.0.8 - '@platforma-open/milaboratories.software-test-utils.sleep': 1.1.3 - '@platforma-open/milaboratories.software-test-utils.small-asset': 1.1.6 + '@platforma-open/milaboratories.software-small-binaries.hello-world': 1.1.7 + '@platforma-open/milaboratories.software-small-binaries.hello-world-py': 1.0.10 + '@platforma-open/milaboratories.software-test-utils.docker-images': 1.1.2 + '@platforma-open/milaboratories.software-test-utils.guided-command': 1.1.6 + '@platforma-open/milaboratories.software-test-utils.java-stub': 1.0.6 + '@platforma-open/milaboratories.software-test-utils.python-stub': 1.0.6 + '@platforma-open/milaboratories.software-test-utils.read-with-sleep': 1.1.6 + '@platforma-open/milaboratories.software-test-utils.runenv-java-stub': 1.0.8 + '@platforma-open/milaboratories.software-test-utils.runenv-python-stub': 1.0.9 + '@platforma-open/milaboratories.software-test-utils.sleep': 1.1.6 + '@platforma-open/milaboratories.software-test-utils.small-asset': 1.1.7 '@pnpm/config.env-replace@1.1.0': {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 129e254a02..bf41acdcf0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -283,7 +283,7 @@ catalog: "@milaboratories/software-pframes-conv": &pframes-version 2.2.9 "@platforma-open/milaboratories.software-small-binaries": ^2.0.3 - "@platforma-open/milaboratories.software-test-utils": ^1.1.6 + "@platforma-open/milaboratories.software-test-utils": 1.1.6 "@platforma-open/milaboratories.software-conda-empty": ^1.0.1 "@platforma-open/milaboratories.runenv-python-3": 1.7.4 From 9a8677887edaaad225665abbed9cae815caca683 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 22 Jun 2026 13:48:23 +0200 Subject: [PATCH 21/33] MILAB-5933: use admin user in pl-client tests requiring elevated permissions In strict security mode (MILAB-5933 backend), ResourceNameExists and ResourceCreateRoot require admin/controller role. Tests that initialize PlClient or create root resources now use PL_TEST_ADMIN_USER credentials. Add getTestAdminClient/getTestAdminLLClient/withAdminTempRoot helpers to test_config.ts, driven by PL_TEST_ADMIN_USER/PL_TEST_ADMIN_PASSWORD env vars. --- lib/node/pl-client/src/core/client.test.ts | 10 +-- lib/node/pl-client/src/core/ll_client.test.ts | 9 ++- .../pl-client/src/core/ll_transaction.test.ts | 6 +- .../pl-client/src/core/transaction.test.ts | 12 ++-- lib/node/pl-client/src/test/test_config.ts | 71 +++++++++++++++++++ 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/lib/node/pl-client/src/core/client.test.ts b/lib/node/pl-client/src/core/client.test.ts index f16c423ee0..a995daee81 100644 --- a/lib/node/pl-client/src/core/client.test.ts +++ b/lib/node/pl-client/src/core/client.test.ts @@ -1,4 +1,4 @@ -import { getTestClient, getTestClientConf } from "../test/test_config"; +import { getTestAdminClient, getTestAdminClientConf } from "../test/test_config"; import { PlClient } from "./client"; import { PlDriver, PlDriverDefinition } from "./driver"; import { Dispatcher, request } from "undici"; @@ -6,12 +6,12 @@ import { GrpcClientProviderFactory } from "./grpc"; import { test, expect } from "vitest"; test("test client init", async () => { - await getTestClient(undefined); + await getTestAdminClient(undefined); }); test("test client alternative root init", async () => { const aRootName = "test_root"; - const { conf, auth } = await getTestClientConf(); + const { conf, auth } = await getTestAdminClientConf(); await PlClient.init({ ...conf, alternativeRoot: aRootName }, auth); const clientB = await PlClient.init(conf, auth); const result = await clientB.deleteAlternativeRoot(aRootName); @@ -19,7 +19,7 @@ test("test client alternative root init", async () => { }); test("test client init 2", async () => { - await getTestClient(); + await getTestAdminClient(); }); interface SimpleDriver extends PlDriver { @@ -46,7 +46,7 @@ const SimpleDriverDefinition: PlDriverDefinition = { }; test("test driver", async () => { - const client = await getTestClient(); + const client = await getTestAdminClient(); const drv = client.getDriver(SimpleDriverDefinition); expect(await drv.ping()).toEqual("pong"); }); diff --git a/lib/node/pl-client/src/core/ll_client.test.ts b/lib/node/pl-client/src/core/ll_client.test.ts index 94d0644d96..4b30fecd1e 100644 --- a/lib/node/pl-client/src/core/ll_client.test.ts +++ b/lib/node/pl-client/src/core/ll_client.test.ts @@ -3,6 +3,8 @@ import { getTestConfig, plAddressToTestConfig, getTestLLClient, + getTestAdminLLClient, + getTestAdminClient, getTestClientConf, } from "../test/test_config"; import { TxAPI_Open_Request_WritableTx } from "../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api"; @@ -144,7 +146,12 @@ test("test https call via proxy", async () => { }); test("list user resources returns user root", async () => { - const client = await getTestLLClient(); + // PlClient.init() creates the user root via the legacy path (requires admin role). + // After that, listUserResources returns it. + const plClient = await getTestAdminClient(); + await plClient.close(); + + const client = await getTestAdminLLClient(); const responses = await client.listUserResources({ limit: 1 }); // First message is always the user root. diff --git a/lib/node/pl-client/src/core/ll_transaction.test.ts b/lib/node/pl-client/src/core/ll_transaction.test.ts index c2a3eca09b..d6b890dfce 100644 --- a/lib/node/pl-client/src/core/ll_transaction.test.ts +++ b/lib/node/pl-client/src/core/ll_transaction.test.ts @@ -1,4 +1,4 @@ -import { getTestLLClient } from "../test/test_config"; +import { getTestLLClient, getTestAdminLLClient } from "../test/test_config"; import { TxAPI_Open_Request_WritableTx } from "../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api"; import { createLocalResourceId } from "./types"; import { test, expect } from "vitest"; @@ -79,7 +79,7 @@ test("check timeout error type (passive)", async () => { }); test("check timeout error type (active)", async () => { - const client = await getTestLLClient(); + const client = await getTestAdminLLClient(); const tx = client.createTx(true, { timeout: 500 }); try { @@ -143,7 +143,7 @@ test("check timeout error type (active)", async () => { }); test("check is abort error (active)", async () => { - const client = await getTestLLClient(); + const client = await getTestAdminLLClient(); const tx = client.createTx(true, { abortSignal: AbortSignal.timeout(100) }); try { diff --git a/lib/node/pl-client/src/core/transaction.test.ts b/lib/node/pl-client/src/core/transaction.test.ts index 66d373f69d..fd3ca4aa23 100644 --- a/lib/node/pl-client/src/core/transaction.test.ts +++ b/lib/node/pl-client/src/core/transaction.test.ts @@ -1,4 +1,4 @@ -import { withTempRoot } from "../test/test_config"; +import { withAdminTempRoot } from "../test/test_config"; import { StructTestResource, ValueTestResource } from "../helpers/pl"; import { field, toGlobalFieldId, toGlobalResourceId } from "./transaction"; import { RecoverablePlError } from "./errors"; @@ -7,7 +7,7 @@ import { test, expect } from "vitest"; import { StatefulPromise } from "./StatefulPromise"; test("get field", async () => { - await withTempRoot(async (pl) => { + await withAdminTempRoot(async (pl) => { const [rr0, theField1] = await pl.withWriteTx("resource1", async (tx) => { const r0 = tx.createStruct(StructTestResource); const r1 = tx.createStruct(StructTestResource); @@ -54,7 +54,7 @@ test("get field", async () => { }); test("handle absent resource error", async () => { - await withTempRoot(async (pl) => { + await withAdminTempRoot(async (pl) => { const [rr0, ff0] = await pl.withWriteTx("testCreateResource", async (tx) => { const r0 = tx.createStruct(StructTestResource); const f0 = { resourceId: tx.clientRoot, fieldName: "test0" }; @@ -114,7 +114,7 @@ test("handle absent resource error", async () => { }); test("handle KV storage", async () => { - await withTempRoot(async (pl) => { + await withAdminTempRoot(async (pl) => { await pl.withWriteTx("writeKV", async (tx) => { tx.setKValue(tx.clientRoot, "a", "a"); tx.setKValue(tx.clientRoot, "b", "b"); @@ -151,7 +151,7 @@ test("handle KV storage", async () => { }); test("handle empty KV storage", async () => { - await withTempRoot(async (pl) => { + await withAdminTempRoot(async (pl) => { await pl.withReadTx("testReadIndividualAndList", async (tx) => { expect(await tx.listKeyValuesString(tx.clientRoot)).toEqual([]); }); @@ -159,7 +159,7 @@ test("handle empty KV storage", async () => { }); test("handle KV storage 2", async () => { - await withTempRoot(async (pl) => { + await withAdminTempRoot(async (pl) => { const r1 = await pl.withWriteTx("writeKV", async (tx) => { const rr1 = tx.createEphemeral(StructTestResource); tx.createField(field(rr1, "a"), "Dynamic", rr1); diff --git a/lib/node/pl-client/src/test/test_config.ts b/lib/node/pl-client/src/test/test_config.ts index 0546f56ea9..dca5f78c70 100644 --- a/lib/node/pl-client/src/test/test_config.ts +++ b/lib/node/pl-client/src/test/test_config.ts @@ -19,6 +19,8 @@ export interface TestConfig { test_proxy?: string; test_user?: string; test_password?: string; + test_admin_user?: string; + test_admin_password?: string; } const CONFIG_FILE = "test_config.json"; @@ -44,6 +46,11 @@ export function getTestConfig(): TestConfig { if (process.env.PL_TEST_PROXY !== undefined) conf.test_proxy = process.env.PL_TEST_PROXY; + if (process.env.PL_TEST_ADMIN_USER !== undefined) conf.test_admin_user = process.env.PL_TEST_ADMIN_USER; + + if (process.env.PL_TEST_ADMIN_PASSWORD !== undefined) + conf.test_admin_password = process.env.PL_TEST_ADMIN_PASSWORD; + if (conf.address === undefined) throw new Error( `can't resolve platform address (checked ${CONFIG_FILE} file and PL_ADDRESS environment var)`, @@ -157,6 +164,70 @@ export async function getTestLLClient(confOverrides: Partial = { return await LLPlClient.build({ ...conf, ...confOverrides }, { auth }); } +export async function getTestAdminClientConf(): Promise<{ conf: PlClientConfig; auth: AuthOps }> { + const tConf = getTestConfig(); + + if (tConf.test_admin_user === undefined || tConf.test_admin_password === undefined) + throw new Error( + `No admin auth found in config (${CONFIG_FILE}) or env vars: PL_TEST_ADMIN_USER, PL_TEST_ADMIN_PASSWORD`, + ); + + const plConf = plAddressToTestConfig(tConf.address); + const uClient = await UnauthenticatedPlClient.build(plConf); + const authInformation = await uClient.login(tConf.test_admin_user, tConf.test_admin_password); + + return { + conf: plConf, + auth: { + authInformation, + onUpdate: () => {}, + onAuthError: () => {}, + onUpdateError: () => {}, + }, + }; +} + +export async function getTestAdminLLClient(confOverrides: Partial = {}) { + const { conf, auth } = await getTestAdminClientConf(); + return await LLPlClient.build({ ...conf, ...confOverrides }, { auth }); +} + +export async function getTestAdminClient( + alternativeRoot?: string, + confOverrides: Partial = {}, +) { + const { conf, auth } = await getTestAdminClientConf(); + if (alternativeRoot !== undefined && conf.alternativeRoot !== undefined) + throw new Error("test pl address configured with alternative root"); + return await PlClient.init({ ...conf, ...confOverrides, alternativeRoot }, auth); +} + +export async function withAdminTempRoot(body: (pl: PlClient) => Promise): Promise { + const alternativeRoot = `test_${Date.now()}_${randomUUID()}`; + let altRootId: OptionalResourceId = NullResourceId; + try { + const client = await getTestAdminClient(alternativeRoot); + altRootId = client.clientRoot; + try { + const value = await body(client); + const rawClient = await getTestAdminClient(); + try { + await rawClient.deleteAlternativeRoot(alternativeRoot); + } catch (cleanupErr: any) { + console.warn(`Failed to clean up alternative root ${alternativeRoot}:`, cleanupErr.message); + } finally { + await rawClient.close(); + } + return value; + } finally { + await client.close(); + } + } catch (err: any) { + console.log(`ALTERNATIVE ROOT: ${alternativeRoot} (${resourceIdToString(altRootId)})`); + throw err; + } +} + export async function getTestClient( alternativeRoot?: string, confOverrides: Partial = {}, From 37a68861751c6aaccf32f7a88d4dc5ffcab48171 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 22 Jun 2026 14:11:58 +0200 Subject: [PATCH 22/33] MILAB-5933: add PL_TEST_ADMIN_USER/PASSWORD to turbo passThroughEnv --- turbo.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/turbo.json b/turbo.json index 153f94790e..de2a065432 100644 --- a/turbo.json +++ b/turbo.json @@ -49,6 +49,8 @@ "PL_TEST_PASSWORD", "PL_TEST_USER", "PL_TEST_PROXY", + "PL_TEST_ADMIN_USER", + "PL_TEST_ADMIN_PASSWORD", "PL_TEST_STORAGE_ID", "PL_TEST_USE_DOCKER", "DEBUG", From 613f0589fe07a2988b72accf0678177fb98beb5a Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 22 Jun 2026 14:36:31 +0200 Subject: [PATCH 23/33] MILAB-5933: fix GetJWTToken to use ROLE_UNSPECIFIED so admin users get admin role When authenticating via the deprecated GetJWTToken path, requesting USER role caused admin users to be downgraded to regular user role. ROLE_UNSPECIFIED tells the server to issue a JWT with the caller's natural role, preserving admin role for users in AdminUsers list. --- lib/node/pl-client/src/core/ll_client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/pl-client/src/core/ll_client.ts b/lib/node/pl-client/src/core/ll_client.ts index 52edb21ac8..8ba6b01e8e 100644 --- a/lib/node/pl-client/src/core/ll_client.ts +++ b/lib/node/pl-client/src/core/ll_client.ts @@ -474,7 +474,7 @@ export class LLPlClient implements WireClientProviderFactory { await cl.getJWTToken( { expiration: { seconds: ttlSeconds, nanos: 0 }, - requestedRole: AuthAPI_GetJWTToken_Role.USER, + requestedRole: AuthAPI_GetJWTToken_Role.ROLE_UNSPECIFIED, }, { meta }, ).response @@ -483,7 +483,7 @@ export class LLPlClient implements WireClientProviderFactory { const headers: Record = {}; if (options?.authorization) headers.authorization = options.authorization; const resp = cl.POST("/v1/auth/jwt-token", { - body: { expiration: `${ttlSeconds}s`, requestedRole: AuthAPI_GetJWTToken_Role.USER }, + body: { expiration: `${ttlSeconds}s`, requestedRole: AuthAPI_GetJWTToken_Role.ROLE_UNSPECIFIED }, headers, }); return notEmpty((await resp).data, "REST: empty response for JWT token request").token; From c230508c1ef69de65a454d0ef8a9e0b7177e4b5c Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Mon, 22 Jun 2026 19:59:32 +0200 Subject: [PATCH 24/33] MILAB-5933: fix EnvironmentTeardownError in pl-drivers download_url test Use noop logger instead of ConsoleLoggerAdapter to prevent background TaskProcessor workers from triggering vitest's onUserConsoleLog RPC after test ends, which caused EnvironmentTeardownError on teardown. --- .../src/drivers/download_url/driver.test.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts b/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts index 21fbf254bf..9bf9c8fe4a 100644 --- a/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts +++ b/lib/node/pl-drivers/src/drivers/download_url/driver.test.ts @@ -1,5 +1,6 @@ import { TestHelpers } from "@milaboratories/pl-client"; -import { ConsoleLoggerAdapter, HmacSha256Signer } from "@milaboratories/ts-helpers"; +import { HmacSha256Signer } from "@milaboratories/ts-helpers"; +import type { MiLogger } from "@milaboratories/ts-helpers"; import * as os from "node:os"; import { text } from "node:stream/consumers"; import { Readable } from "node:stream"; @@ -10,9 +11,13 @@ import { DownloadUrlDriver } from "./driver"; import { test, expect } from "vitest"; import { TestTags } from "@milaboratories/build-configs"; +// ponytail: noop logger prevents background TaskProcessor workers from triggering +// vitest's onUserConsoleLog RPC after test ends, which causes EnvironmentTeardownError +const noopLogger: MiLogger = { info: () => {}, warn: () => {}, error: () => {} }; + test("should download a tar archive and extracts its content and then deleted", async () => { await TestHelpers.withTempRoot(async (client) => { - const logger = new ConsoleLoggerAdapter(); + const logger = noopLogger; const dir = await fsp.mkdtemp(path.join(os.tmpdir(), "test1-")); const driver = new DownloadUrlDriver(logger, client.httpDispatcher, dir, genSigner()); @@ -51,7 +56,7 @@ test( { tag: [TestTags.Flaky] }, async () => { await TestHelpers.withTempRoot(async (client) => { - const logger = new ConsoleLoggerAdapter(); + const logger = noopLogger; const dir = await fsp.mkdtemp(path.join(os.tmpdir(), "test1-")); const driver = new DownloadUrlDriver(logger, client.httpDispatcher, dir, genSigner()); @@ -78,7 +83,7 @@ test( test("should abort a downloading process when we reset a state of a computable", async () => { await TestHelpers.withTempRoot(async (client) => { - const logger = new ConsoleLoggerAdapter(); + const logger = noopLogger; const dir = await fsp.mkdtemp(path.join(os.tmpdir(), "test2-")); const driver = new DownloadUrlDriver(logger, client.httpDispatcher, dir, genSigner()); From f20b189da27983fdb2d0d84c6fd288cfda3700f7 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 23 Jun 2026 12:44:12 +0200 Subject: [PATCH 25/33] MILAB-5933: raise workflow-tengo maxWorkers 2->4 to parallelize e2e suite --- tests/workflow-tengo/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workflow-tengo/vitest.config.mts b/tests/workflow-tengo/vitest.config.mts index d76084168d..c607f2f1f3 100644 --- a/tests/workflow-tengo/vitest.config.mts +++ b/tests/workflow-tengo/vitest.config.mts @@ -8,7 +8,7 @@ export default defineConfig( setupFiles: ["./vitest/setup.worker-jitter.ts"], testTimeout: 15000, maxConcurrency: 1, - maxWorkers: 2, + maxWorkers: 4, retry: 2, reporters: ["verbose"], sequence: { From 9b415897807ae1976dad4f31bb09ba3b4c89f547 Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 23 Jun 2026 13:48:03 +0200 Subject: [PATCH 26/33] MILAB-5933: dial workflow-tengo maxWorkers 4->3 to avoid backend saturation --- tests/workflow-tengo/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workflow-tengo/vitest.config.mts b/tests/workflow-tengo/vitest.config.mts index c607f2f1f3..f4bc9d963e 100644 --- a/tests/workflow-tengo/vitest.config.mts +++ b/tests/workflow-tengo/vitest.config.mts @@ -8,7 +8,7 @@ export default defineConfig( setupFiles: ["./vitest/setup.worker-jitter.ts"], testTimeout: 15000, maxConcurrency: 1, - maxWorkers: 4, + maxWorkers: 3, retry: 2, reporters: ["verbose"], sequence: { From 9aacd7c11169a682e95b3ca3c30fa0472fd6285e Mon Sep 17 00:00:00 2001 From: Vitalii Popov Date: Tue, 23 Jun 2026 14:12:11 +0200 Subject: [PATCH 27/33] MILAB-5933: set workflow-tengo maxWorkers to 2 (proven-safe, no backend saturation) --- tests/workflow-tengo/vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workflow-tengo/vitest.config.mts b/tests/workflow-tengo/vitest.config.mts index f4bc9d963e..d76084168d 100644 --- a/tests/workflow-tengo/vitest.config.mts +++ b/tests/workflow-tengo/vitest.config.mts @@ -8,7 +8,7 @@ export default defineConfig( setupFiles: ["./vitest/setup.worker-jitter.ts"], testTimeout: 15000, maxConcurrency: 1, - maxWorkers: 3, + maxWorkers: 2, retry: 2, reporters: ["verbose"], sequence: { From 6150096448d56be9a763c78d69526b116b4bd833 Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Fri, 26 Jun 2026 19:16:08 +0200 Subject: [PATCH 28/33] MILAB-5933: pass PL_DOCKER_REGISTRY + PL_PKG_DEV through to turbo build task (so dev-built software images target the dev public ECR, not quay) --- turbo.json | 76 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/turbo.json b/turbo.json index de2a065432..abefe9388a 100644 --- a/turbo.json +++ b/turbo.json @@ -3,31 +3,54 @@ "tasks": { "fmt": { "outputs": [], - "inputs": ["$TURBO_DEFAULT$"] + "inputs": [ + "$TURBO_DEFAULT$" + ] }, "check": { "outputs": [], - "inputs": ["$TURBO_DEFAULT$"], - "dependsOn": ["^build"] + "inputs": [ + "$TURBO_DEFAULT$" + ], + "dependsOn": [ + "^build" + ] }, "formatter:check": { "outputs": [], - "inputs": ["$TURBO_DEFAULT$"] + "inputs": [ + "$TURBO_DEFAULT$" + ] }, "linter:check": { "outputs": [], - "inputs": ["$TURBO_DEFAULT$"] + "inputs": [ + "$TURBO_DEFAULT$" + ] }, "types:check": { "outputs": [], - "inputs": ["$TURBO_DEFAULT$"], - "dependsOn": ["^build"] + "inputs": [ + "$TURBO_DEFAULT$" + ], + "dependsOn": [ + "^build" + ] }, "build": { - "inputs": ["$TURBO_DEFAULT$"], - "outputs": ["./dist/**", "./block-pack/**", "./pkg-*.tgz"], + "inputs": [ + "$TURBO_DEFAULT$" + ], + "outputs": [ + "./dist/**", + "./block-pack/**", + "./pkg-*.tgz" + ], "env": [], - "dependsOn": ["^build", "types:check"], + "dependsOn": [ + "^build", + "types:check" + ], "passThroughEnv": [ "GENERATE_TAGS", "TAGS_ADDITIONAL_ARGS", @@ -36,14 +59,25 @@ "PL_DOCKER_BUILD", "PL_DOCKER_NO_BUILD", "PL_DOCKER_AUTOPUSH", - "PL_DOCKER_NO_AUTOPUSH" + "PL_DOCKER_NO_AUTOPUSH", + "PL_DOCKER_REGISTRY", + "PL_PKG_DEV" ] }, "test": { - "inputs": ["$TURBO_DEFAULT$"], - "env": ["TEST_CACHE_CRUTCH"], - "outputs": ["./coverage/**", "test-report.junit.xml"], - "dependsOn": ["build"], + "inputs": [ + "$TURBO_DEFAULT$" + ], + "env": [ + "TEST_CACHE_CRUTCH" + ], + "outputs": [ + "./coverage/**", + "test-report.junit.xml" + ], + "dependsOn": [ + "build" + ], "passThroughEnv": [ "PL_ADDRESS", "PL_TEST_PASSWORD", @@ -63,9 +97,15 @@ ] }, "do-pack": { - "inputs": ["$TURBO_DEFAULT$"], - "dependsOn": ["build"], - "outputs": ["package.tgz"] + "inputs": [ + "$TURBO_DEFAULT$" + ], + "dependsOn": [ + "build" + ], + "outputs": [ + "package.tgz" + ] } } } From 677907c6d121317d1e391440c78e058eee3ade3e Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Fri, 26 Jun 2026 19:48:06 +0200 Subject: [PATCH 29/33] MILAB-5933: keep k8s build in release mode (drop PL_PKG_DEV from build passThroughEnv; keep PL_DOCKER_REGISTRY so ptabler docker targets public ECR while run-envs/software keep docker descriptors) --- turbo.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/turbo.json b/turbo.json index abefe9388a..98d5919ba4 100644 --- a/turbo.json +++ b/turbo.json @@ -60,8 +60,7 @@ "PL_DOCKER_NO_BUILD", "PL_DOCKER_AUTOPUSH", "PL_DOCKER_NO_AUTOPUSH", - "PL_DOCKER_REGISTRY", - "PL_PKG_DEV" + "PL_DOCKER_REGISTRY" ] }, "test": { From e07c7f26c008536933826f9202f016607708b286 Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Sat, 27 Jun 2026 19:21:20 +0200 Subject: [PATCH 30/33] MILAB-5933: route imageless exec commands to the local executor (ui-tasks queue) so bare/binary-only commands run on k8s deploys; docker-software keeps its queue and still runs on k8s --- .../src/exec/exec-impl.tpl.tengo | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo index f0368f99da..9cf8fe5541 100644 --- a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo +++ b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo @@ -19,6 +19,7 @@ maps := import(":maps") runcmd := import(":exec.runcmd") feats := import(":feats") R := import(":exec.R") +execConstants := import(":exec.constants") delayedCompAlloc := import(":exec.delayed-compute-allocation") @@ -141,8 +142,22 @@ self.body(func(inputs) { // it has acquired the storage quota required for workdir creation, // which is a prerequisite for the computation itself. + // Imageless commands (bare shell commands, binary-only software, run-envs without a + // docker image) cannot run on the k8s/batch runners: those execute every command as a + // container and require a docker image (the k8s driver hard-fails with "docker is not + // set"). Route such commands to the always-available local executor by running them on + // the ui-tasks queue, which is forced to the local executor by default + // (uiQueueForceLocalExecutor). This keeps the compute allocation and the run command on + // the same (local) runner. Commands WITH a docker image keep their requested queue, so + // real workloads still run on the k8s runner. + execQueue := runOptions.queue + dockerImageTag := inputs.mainPlan.options.dockerImageTag + if is_undefined(dockerImageTag) || dockerImageTag == "" { + execQueue = execConstants.UI_TASKS_QUEUE + } + computeRequest := { - queue: runOptions.queue, + queue: execQueue, cpu: quota.cpu, ram: quota.ram } @@ -172,7 +187,7 @@ self.body(func(inputs) { } mainRunBuilder := runcmd.builder(wdBefore, mainPlanPreBuilder.state()). - inQueue(runOptions.queue). + inQueue(execQueue). allocation(computeAllocationRef) if !is_undefined(runOptions.name) && runOptions.name != "" { From b368acfa3d1e477c6a28f45242e0049d50ea251b Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Sat, 27 Jun 2026 20:33:11 +0200 Subject: [PATCH 31/33] Revert imageless->ui-tasks routing: driver is global per runner-type (DriverByRType[executor]), not per-queue, so queue routing is a no-op on k8s deploys --- .../src/exec/exec-impl.tpl.tengo | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo index 9cf8fe5541..f0368f99da 100644 --- a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo +++ b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo @@ -19,7 +19,6 @@ maps := import(":maps") runcmd := import(":exec.runcmd") feats := import(":feats") R := import(":exec.R") -execConstants := import(":exec.constants") delayedCompAlloc := import(":exec.delayed-compute-allocation") @@ -142,22 +141,8 @@ self.body(func(inputs) { // it has acquired the storage quota required for workdir creation, // which is a prerequisite for the computation itself. - // Imageless commands (bare shell commands, binary-only software, run-envs without a - // docker image) cannot run on the k8s/batch runners: those execute every command as a - // container and require a docker image (the k8s driver hard-fails with "docker is not - // set"). Route such commands to the always-available local executor by running them on - // the ui-tasks queue, which is forced to the local executor by default - // (uiQueueForceLocalExecutor). This keeps the compute allocation and the run command on - // the same (local) runner. Commands WITH a docker image keep their requested queue, so - // real workloads still run on the k8s runner. - execQueue := runOptions.queue - dockerImageTag := inputs.mainPlan.options.dockerImageTag - if is_undefined(dockerImageTag) || dockerImageTag == "" { - execQueue = execConstants.UI_TASKS_QUEUE - } - computeRequest := { - queue: execQueue, + queue: runOptions.queue, cpu: quota.cpu, ram: quota.ram } @@ -187,7 +172,7 @@ self.body(func(inputs) { } mainRunBuilder := runcmd.builder(wdBefore, mainPlanPreBuilder.state()). - inQueue(execQueue). + inQueue(runOptions.queue). allocation(computeAllocationRef) if !is_undefined(runOptions.name) && runOptions.name != "" { From 0deda818bb3188367cc6242e1f46a926cb9bb51a Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Sat, 27 Jun 2026 20:45:12 +0200 Subject: [PATCH 32/33] EXPERIMENT(MILAB-5933): default base image (ubuntu:22.04) for imageless commands so the e2e suite runs on the k8s runner; validates the default-image path --- sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo index f0368f99da..4940697335 100644 --- a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo +++ b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo @@ -155,6 +155,16 @@ self.body(func(inputs) { mainPlanPreBuilder := runcmd.createRunCommandPlan(inputs.mainPlan) + // EXPERIMENT (MILAB-5933): imageless commands (bare shell commands, run-envs/software + // without a docker image) can't run on the k8s runner, which requires a docker image per + // command (DriverByRType[executor] is global -> K8s on this deploy, the driver hard-fails + // with "docker is not set"). Give them a default base image so the suite can run on k8s. + // This validates the "default image" path; the real fix (per-command local fallback or a + // configurable default image) belongs in the backend. + if is_undefined(inputs.mainPlan.options.dockerImageTag) || inputs.mainPlan.options.dockerImageTag == "" { + mainPlanPreBuilder.dockerImageTag("public.ecr.aws/docker/library/ubuntu:22.04") + } + mnz := runOptions.monetization if !is_undefined(mnz) { result := monetization.run(mnz, wdBefore, inputs.mnzPlan, runOptions.queue, computeAllocationRef) From 49739bbe67f0fd78fca8222db426c0bf13661d13 Mon Sep 17 00:00:00 2001 From: mike-ainsel Date: Sun, 28 Jun 2026 11:36:07 +0200 Subject: [PATCH 33/33] Revert default-image experiment: validated (k8s docker-is-not-set 1623->0, 8->3 failed files) but it breaks localfs (docker disabled on the local runner) -> the fix must be backend-side, gated on the k8s runner type --- sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo index 4940697335..f0368f99da 100644 --- a/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo +++ b/sdk/workflow-tengo/src/exec/exec-impl.tpl.tengo @@ -155,16 +155,6 @@ self.body(func(inputs) { mainPlanPreBuilder := runcmd.createRunCommandPlan(inputs.mainPlan) - // EXPERIMENT (MILAB-5933): imageless commands (bare shell commands, run-envs/software - // without a docker image) can't run on the k8s runner, which requires a docker image per - // command (DriverByRType[executor] is global -> K8s on this deploy, the driver hard-fails - // with "docker is not set"). Give them a default base image so the suite can run on k8s. - // This validates the "default image" path; the real fix (per-command local fallback or a - // configurable default image) belongs in the backend. - if is_undefined(inputs.mainPlan.options.dockerImageTag) || inputs.mainPlan.options.dockerImageTag == "" { - mainPlanPreBuilder.dockerImageTag("public.ecr.aws/docker/library/ubuntu:22.04") - } - mnz := runOptions.monetization if !is_undefined(mnz) { result := monetization.run(mnz, wdBefore, inputs.mnzPlan, runOptions.queue, computeAllocationRef)