From 0bebc39a570764cb461cfab8ace4ff0087e28bdc Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 13:41:06 -0700 Subject: [PATCH 01/12] feat: @cucumber/cucumber 13 (0.1.6) Cucumber 13 runs --parallel workers as worker threads, which don't get the tsx loader cucumber.mjs registers, so every test script sets NODE_OPTIONS='--import tsx'. engines node >=22 (cucumber 13 dropped Node 20). Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 8 + package-lock.json | 702 ++++++++++------------------------------------ package.json | 19 +- 3 files changed, 172 insertions(+), 557 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5473b7e..941aaf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Changed + +- **`@cucumber/cucumber` 13** (peer `^13.2.1`, was `^12.2.0`). Its `--parallel` + workers are worker threads now, which don't get the `tsx` loader that + `cucumber.mjs` registers: every `test*` script sets + `NODE_OPTIONS='--import tsx'` (consumers running in parallel need the same). + `engines` is `node >=22`, as cucumber 13 dropped Node 20. + ### Added - **Every `assertCondition` failure now points at the current scenario's diff --git a/package-lock.json b/package-lock.json index 4078efd..11309d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "thomas", - "version": "0.1.4", + "version": "0.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "thomas", - "version": "0.1.4", + "version": "0.1.6", "license": "MIT", "dependencies": { "jmespath": "^0.16.0", @@ -14,7 +14,7 @@ "undici": "7.29.1" }, "devDependencies": { - "@cucumber/cucumber": "^12.2.0", + "@cucumber/cucumber": "^13.2.1", "@cucumber/pretty-formatter": "^4.0.2", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", @@ -22,8 +22,11 @@ "tsx": "^4.19.0", "typescript": "^5.6.0" }, + "engines": { + "node": ">=22" + }, "peerDependencies": { - "@cucumber/cucumber": "^12.2.0", + "@cucumber/cucumber": "^13.2.1", "tsx": "^4.19.0" } }, @@ -64,55 +67,48 @@ } }, "node_modules/@cucumber/ci-environment": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-13.0.0.tgz", - "integrity": "sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-15.0.0.tgz", + "integrity": "sha512-9zIy0YIn7Tkws4pNJElf/kOnPy/6yxWZPWH6eMNW8s/BsV3d10+Xs1yjp2HwEMPElnrFEVHQlUs4XGQ1M3q2Nw==", "dev": true, "license": "MIT" }, "node_modules/@cucumber/cucumber": { - "version": "12.9.0", - "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-12.9.0.tgz", - "integrity": "sha512-QbgEo/DcKFMRGL+yULh8Kw6peEfdPJjhYjpKp0dYc+6Dv1Bmp6hvxIdTi2CIinYBCXhvCZzNO1Ct/n6Dk1yAtA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-13.3.0.tgz", + "integrity": "sha512-6OSoj/SQogJwEjoNrPZ5gtyTDwbmtCDuzJ/hc81nOVhwEBAO6ypgdWd+qCScOdyZxgtQvUWG534LBWb5h9/Y8Q==", "dev": true, "license": "MIT", "dependencies": { - "@cucumber/ci-environment": "13.0.0", - "@cucumber/cucumber-expressions": "19.0.0", - "@cucumber/gherkin": "38.0.0", - "@cucumber/gherkin-streams": "6.0.0", - "@cucumber/gherkin-utils": "11.0.0", - "@cucumber/html-formatter": "23.1.0", - "@cucumber/junit-xml-formatter": "0.13.3", - "@cucumber/message-streams": "4.1.1", - "@cucumber/messages": "32.3.1", - "@cucumber/pretty-formatter": "1.0.1", - "@cucumber/tag-expressions": "9.1.0", + "@cucumber/ci-environment": "15.0.0", + "@cucumber/cucumber-expressions": "20.1.0", + "@cucumber/gherkin": "42.0.1", + "@cucumber/gherkin-streams": "7.0.1", + "@cucumber/gherkin-utils": "12.0.2", + "@cucumber/html-formatter": "24.2.0", + "@cucumber/junit-xml-formatter": "0.15.0", + "@cucumber/message-streams": "5.0.1", + "@cucumber/messages": "34.2.1", + "@cucumber/pretty-formatter": "4.1.0", + "@cucumber/tag-expressions": "11.0.1", "assertion-error-formatter": "^3.0.0", - "capital-case": "^1.0.4", - "chalk": "^4.1.2", "cli-table3": "0.6.5", - "commander": "^14.0.0", + "commander": "^15.0.0", "debug": "^4.3.4", "error-stack-parser": "^2.1.4", - "figures": "^3.2.0", - "glob": "^13.0.0", - "has-ansi": "^4.0.1", - "indent-string": "^4.0.0", - "is-installed-globally": "^0.4.0", - "is-stream": "^2.0.0", + "figures": "^6.0.0", + "has-ansi": "^6.0.0", + "indent-string": "^5.0.0", + "is-installed-globally": "^1.0.0", "knuth-shuffle-seeded": "^1.0.6", "lodash.merge": "^4.6.2", "lodash.mergewith": "^4.6.2", "luxon": "3.7.2", - "mkdirp": "^3.0.0", - "mz": "^2.7.0", - "progress": "^2.0.3", "read-package-up": "^12.0.0", - "semver": "7.7.4", - "string-argv": "0.3.1", - "supports-color": "^8.1.1", - "type-fest": "^4.41.0", + "semver": "7.8.5", + "string-argv": "0.3.2", + "supports-color": "^11.0.0", + "type-fest": "^5.0.0", "util-arity": "^1.1.0", "yaml": "^2.2.2", "yup": "1.7.1" @@ -121,81 +117,56 @@ "cucumber-js": "bin/cucumber.js" }, "engines": { - "node": "20 || 22 || >=24" + "node": "22 || 24 || >=26" }, "funding": { "url": "https://opencollective.com/cucumber" } }, "node_modules/@cucumber/cucumber-expressions": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-19.0.0.tgz", - "integrity": "sha512-4FKoOQh2Uf6F6/Ln+1OxuK8LkTg6PyAqekhf2Ix8zqV2M54sH+m7XNJNLhOFOAW/t9nxzRbw2CcvXbCLjcvHZg==", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-20.1.0.tgz", + "integrity": "sha512-KXQJChHTyHdg6HI7fHy3zpjfoS205vV1B/aJQKB82VFgMGbdVdiaSy7sTtap/5Q787anLmZt25Tg0FqQ2n4fqw==", "dev": true, "license": "MIT", "dependencies": { "regexp-match-indices": "1.0.2" } }, - "node_modules/@cucumber/cucumber/node_modules/@cucumber/messages": { - "version": "32.3.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-32.3.1.tgz", - "integrity": "sha512-yNQq1KoXRYaEKrWMFmpUQX7TdeQuU9jeGgJAZ3dArTsC/T4NpJ6DnqaJIIgwPnz/wtQIQTNX7/h0rOuF5xY4qQ==", + "node_modules/@cucumber/cucumber/node_modules/type-fest": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.10.0.tgz", + "integrity": "sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==", "dev": true, - "license": "MIT", - "dependencies": { - "class-transformer": "0.5.1", - "reflect-metadata": "0.2.2" - } - }, - "node_modules/@cucumber/cucumber/node_modules/@cucumber/pretty-formatter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz", - "integrity": "sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==", - "dev": true, - "license": "MIT", + "license": "(MIT OR CC0-1.0)", "dependencies": { - "ansi-styles": "^5.0.0", - "cli-table3": "^0.6.0", - "figures": "^3.2.0", - "ts-dedent": "^2.0.0" + "tagged-tag": "^1.0.0" }, - "peerDependencies": { - "@cucumber/cucumber": ">=7.0.0", - "@cucumber/messages": "*" - } - }, - "node_modules/@cucumber/cucumber/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=10" + "node": ">=20" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@cucumber/gherkin": { - "version": "38.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-38.0.0.tgz", - "integrity": "sha512-duEXK+KDfQUzu3vsSzXjkxQ2tirF5PRsc1Xrts6THKHJO6mjw4RjM8RV+vliuDasmhhrmdLcOcM7d9nurNTJKw==", + "version": "42.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-42.0.1.tgz", + "integrity": "sha512-Kqg0ULhWqbXp/a1c04ND4sS4KTlIL831tQ0NhZLXWdEhT6LiNsZ5LFRzy/lBy7QQpcKhroKp/i3C2WdEnRBKNg==", "dev": true, "license": "MIT", "dependencies": { - "@cucumber/messages": ">=31.0.0 <33" + "@cucumber/messages": ">=34.0.0 <35" } }, "node_modules/@cucumber/gherkin-streams": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-6.0.0.tgz", - "integrity": "sha512-HLSHMmdDH0vCr7vsVEURcDA4WwnRLdjkhqr6a4HQ3i4RFK1wiDGPjBGVdGJLyuXuRdJpJbFc6QxHvT8pU4t6jw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-7.0.1.tgz", + "integrity": "sha512-8W1lmof0hbQ1HgOEpPCkz1KCFaM6MfA7n7rr6vX/7ffgUQ0saOAwapKSVj7P68Aht0K9XqHaw8BDLtqaK/jRIg==", "dev": true, "license": "MIT", "dependencies": { - "commander": "14.0.0", + "commander": "15.0.0", "source-map-support": "0.5.21" }, "bin": { @@ -207,69 +178,27 @@ "@cucumber/messages": ">=17.1.1" } }, - "node_modules/@cucumber/gherkin-streams/node_modules/commander": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", - "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, "node_modules/@cucumber/gherkin-utils": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-11.0.0.tgz", - "integrity": "sha512-LJ+s4+TepHTgdKWDR4zbPyT7rQjmYIcukTwNbwNwgqr6i8Gjcmzf6NmtbYDA19m1ZFg6kWbFsmHnj37ZuX+kZA==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-12.0.2.tgz", + "integrity": "sha512-e678WQqU3zJnZ3GW4D7O4/mrD3vku0iUYJPz7cuLNw3jcK81dvbt5iYa5l3tfT9z2rxE5ObFPUbTkDN7zFwqjw==", "dev": true, "license": "MIT", "dependencies": { - "@cucumber/gherkin": "^38.0.0", - "@cucumber/messages": "^32.0.0", + "@cucumber/gherkin": "^42.0.0", + "@cucumber/messages": "^34.0.0", "@teppeis/multimaps": "3.0.0", - "commander": "14.0.2", + "commander": "15.0.0", "source-map-support": "^0.5.21" }, "bin": { "gherkin-utils": "bin/gherkin-utils" } }, - "node_modules/@cucumber/gherkin-utils/node_modules/@cucumber/messages": { - "version": "32.3.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-32.3.1.tgz", - "integrity": "sha512-yNQq1KoXRYaEKrWMFmpUQX7TdeQuU9jeGgJAZ3dArTsC/T4NpJ6DnqaJIIgwPnz/wtQIQTNX7/h0rOuF5xY4qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "class-transformer": "0.5.1", - "reflect-metadata": "0.2.2" - } - }, - "node_modules/@cucumber/gherkin-utils/node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/@cucumber/gherkin/node_modules/@cucumber/messages": { - "version": "32.3.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-32.3.1.tgz", - "integrity": "sha512-yNQq1KoXRYaEKrWMFmpUQX7TdeQuU9jeGgJAZ3dArTsC/T4NpJ6DnqaJIIgwPnz/wtQIQTNX7/h0rOuF5xY4qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "class-transformer": "0.5.1", - "reflect-metadata": "0.2.2" - } - }, "node_modules/@cucumber/html-formatter": { - "version": "23.1.0", - "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-23.1.0.tgz", - "integrity": "sha512-DcCSFoGs6jbwzXPgX1CwgJKEE+ZMcIEzq/0Memg0o24maNn9NJizBFHmoFWG4iv/OxHza+mvc+56cTHetfHndw==", + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-24.2.0.tgz", + "integrity": "sha512-6Y5ijKyFeNiaMdcYna/fo1Bluzebm8L+vSAyuymIt7Dxu5Fq1sDYMGqR1rYeuNdJmXyu/YRtGLOsrZdCJCQGIg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -277,13 +206,13 @@ } }, "node_modules/@cucumber/junit-xml-formatter": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.13.3.tgz", - "integrity": "sha512-w9ujOxiuKDtU6fLzJz+wp4Sgp5Xu6ba7ls00LHJccVmQU0Ba7zs+AHnv3iIgPjKZAQe1w8x93dr8Gaubh7Vqkg==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.15.0.tgz", + "integrity": "sha512-371k/g1p+UVkxCtRmqPFiVNosV7noV93qH6BbUtN9lXrF22QEbb+YoV0gphhWol0fggVHzfObuk4qJ3YQvDsrg==", "dev": true, "license": "MIT", "dependencies": { - "@cucumber/query": "^15.0.1", + "@cucumber/query": "^16.0.0", "@teppeis/multimaps": "^3.0.0", "luxon": "^3.5.0", "xmlbuilder": "^15.1.1" @@ -293,13 +222,13 @@ } }, "node_modules/@cucumber/message-streams": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-4.1.1.tgz", - "integrity": "sha512-QCAntLajesWMyX+mZKrj63YghVAts7yKFlZe46XprLbdJZN0ddB+f/Mr9OnyWKC2DHhJ18jzCfKIFCaqpAmUxg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-5.0.1.tgz", + "integrity": "sha512-MXsD7ZAWWAiWMrn3Lzq2nwu9DJpPbbvdqXj2ot1BSM2gXnoSvg8d0pc6PzS9pI02swMSn/KN11mTdF5ScE7X0Q==", "dev": true, "license": "MIT", "dependencies": { - "mime": "^3.0.0" + "mime": "^4.0.0" }, "peerDependencies": { "@cucumber/messages": ">=17.1.1" @@ -310,13 +239,12 @@ "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-34.2.1.tgz", "integrity": "sha512-aj2iCAG9ZOpMVcMxcgShifv5fbR96b7SMgdWcPXXh2QbFp7OEcAnQ5MC5YfWUDSDasmw7FU5NJEsOrXdTQOU1A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@cucumber/pretty-formatter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-4.0.2.tgz", - "integrity": "sha512-c33wUL5h8zDvTIng9GCJcaHjhx51EGTOlze3K1CxSaNE36hHQZxSPSlIQ3jQYChEmcV1T3U2LYQAKc8rT7pZmw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-4.1.0.tgz", + "integrity": "sha512-cbdb494+X3nHxvP34sbyia7CeVIkqs0K3+LWpsF8szCSUVYOxhmbP66H/Yd7f6yr2BhKLmkDokyEX24VAyOstA==", "dev": true, "license": "MIT", "dependencies": { @@ -327,7 +255,7 @@ "@cucumber/messages": "*" } }, - "node_modules/@cucumber/pretty-formatter/node_modules/@cucumber/query": { + "node_modules/@cucumber/query": { "version": "16.1.1", "resolved": "https://registry.npmjs.org/@cucumber/query/-/query-16.1.1.tgz", "integrity": "sha512-SBaP4Lc7xv55jY78Q8raoxvbBIPGhQKrui/Tq+l6jYBl1alV0TG1sW8TRtk9W7RQl27nVJo9DyyvASp374L9Tg==", @@ -341,24 +269,10 @@ "@cucumber/messages": "*" } }, - "node_modules/@cucumber/query": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/query/-/query-15.0.1.tgz", - "integrity": "sha512-FMfT3orJblRsOxvU2doECBvQmauizYlj+5JsM8atAKKPbnQTj7v2/OrnuykvQpfZNBf19DYbRq1e832vllRP/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@teppeis/multimaps": "3.0.0", - "lodash.sortby": "^4.7.0" - }, - "peerDependencies": { - "@cucumber/messages": "*" - } - }, "node_modules/@cucumber/tag-expressions": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-9.1.0.tgz", - "integrity": "sha512-bvHjcRFZ+J1TqIa9eFNO1wGHqwx4V9ZKV3hYgkuK/VahHx73uiP4rKV3JVrvWSMrwrFvJG6C8aEwnCWSvbyFdQ==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-11.0.1.tgz", + "integrity": "sha512-x0AssM2HKLoxw8gSeAsYo0QK9wImODYBNDO423/K1Pfk2vwA/MdecRS1ky5i3Rl84kohaG0uUXhIBR+HTu/Qjg==", "dev": true, "license": "MIT" }, @@ -846,38 +760,18 @@ "license": "MIT" }, "node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -896,29 +790,6 @@ "repeat-string": "^1.6.1" } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -926,55 +797,6 @@ "dev": true, "license": "MIT" }, - "node_modules/capital-case": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/class-transformer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "dev": true, - "license": "MIT" - }, "node_modules/cli-table3": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", @@ -991,34 +813,14 @@ "@colors/colors": "1.5.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=22.12.0" } }, "node_modules/debug": { @@ -1108,27 +910,17 @@ "@esbuild/win32-x64": "0.28.2" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", "dev": true, "license": "MIT", "dependencies": { - "escape-string-regexp": "^1.0.5" + "is-unicode-supported": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1162,61 +954,36 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, "license": "MIT", "dependencies": { - "ini": "2.0.0" + "ini": "4.1.1" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/has-ansi": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz", - "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-6.0.2.tgz", + "integrity": "sha512-vAyM+6+jAYwSwz0/M0jYKfU9AvAMCz0kH791RsUhvMKGUHXled/3FjcQB3YiQ4Astj5srHdb6B2FHGIfZkOQNg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/has-ansi?sponsor=1" } }, "node_modules/hosted-git-info": { @@ -1233,13 +1000,16 @@ } }, "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/index-to-position": { @@ -1256,13 +1026,13 @@ } }, "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, "license": "ISC", "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/is-fullwidth-code-point": { @@ -1276,40 +1046,43 @@ } }, "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.1.tgz", + "integrity": "sha512-li88H4QGRoNMX27jEmY8nR515oJVspAgC/WFMlhHfFV8RJ4QyGpHhXnwAe9gH5RIgKmdYRUmrOhQobcgEjIdSw==", "dev": true, "license": "MIT", "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1384,16 +1157,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, "node_modules/lru-cache": { "version": "11.5.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", @@ -1415,58 +1178,19 @@ } }, "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], "license": "MIT", "bin": { - "mkdirp": "dist/cjs/src/bin.js" + "mime": "bin/cli.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/ms": { @@ -1476,29 +1200,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, "node_modules/normalize-package-data": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", @@ -1514,16 +1215,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pad-right": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", @@ -1555,23 +1246,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1579,16 +1253,6 @@ "dev": true, "license": "ISC" }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", @@ -1666,13 +1330,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/regexp-match-indices": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", @@ -1711,9 +1368,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -1788,9 +1445,9 @@ "license": "MIT" }, "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "license": "MIT", "engines": { @@ -1836,16 +1493,13 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-11.0.0.tgz", + "integrity": "sha512-/zyImLdxhdygBIaVX0xTlQhKaCDLCrm665aqHk8xqK/Pa6k61fL6gwQGQq1k31yNyz6x55PppQgF2DMyPQa5xw==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=22" }, "funding": { "url": "https://github.com/chalk/supports-color?sponsor=1" @@ -1864,29 +1518,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", @@ -1901,23 +1532,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ts-dedent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", - "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.10" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, "node_modules/tsx": { "version": "4.23.13", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.13.tgz", @@ -1993,16 +1607,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/upper-case-first": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", - "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, "node_modules/util-arity": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", diff --git a/package.json b/package.json index 5647d93..779df7f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "thomas", - "version": "0.1.5", + "version": "0.1.6", "description": "Real (no-mocks) BDD step implementations for Helm, kubectl, and HTTP testing of k8s-native applications.", "license": "MIT", "type": "module", @@ -14,21 +14,21 @@ "./support/*": "./features/support/*.ts" }, "scripts": { - "test": "cucumber-js", - "test:ff": "cucumber-js --fail-fast", - "test:verbose": "cucumber-js --format @cucumber/pretty-formatter", - "test:usage": "cucumber-js --format usage", - "test:junit": "cucumber-js --format junit:report.xml", + "test": "NODE_OPTIONS='--import tsx' cucumber-js", + "test:ff": "NODE_OPTIONS='--import tsx' cucumber-js --fail-fast", + "test:verbose": "NODE_OPTIONS='--import tsx' cucumber-js --format @cucumber/pretty-formatter", + "test:usage": "NODE_OPTIONS='--import tsx' cucumber-js --format usage", + "test:junit": "NODE_OPTIONS='--import tsx' cucumber-js --format junit:report.xml", "docs:serve": "mkdocs serve", "docs:build": "mkdocs build --strict", "install:tools": "bash scripts/tools.sh" }, "peerDependencies": { - "@cucumber/cucumber": "^12.2.0", + "@cucumber/cucumber": "^13.2.1", "tsx": "^4.19.0" }, "devDependencies": { - "@cucumber/cucumber": "^12.2.0", + "@cucumber/cucumber": "^13.2.1", "@cucumber/pretty-formatter": "^4.0.2", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", @@ -40,5 +40,8 @@ "jmespath": "^0.16.0", "js-yaml": "^4.1.0", "undici": "7.29.1" + }, + "engines": { + "node": ">=22" } } From f406b4a8cd89df6c5c79f131c98bef0b4df963ea Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 21:23:08 +0000 Subject: [PATCH 02/12] Bootstrap Dev Container. --- .devcontainer/devcontainer.json | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..746a512 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,35 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node +{ + "name": "Node.js & TypeScript", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/typescript-node:26-trixie", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": { + "installDirectlyFromGitHubRelease": true, + "version": "latest" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "anthropic.claude-code" + ] + } + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} From 9274f88d5e35b9ffc0261e12ee4ad0cdd444fd6f Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 21:29:49 +0000 Subject: [PATCH 03/12] ci: run workflows on Node 22 (cucumber 13 dropped Node 20) Co-Authored-By: Claude Opus 5.5 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/ci.yaml | 2 +- .github/workflows/real-tests.yml | 2 +- .github/workflows/release-prepare.yaml | 2 +- .github/workflows/release-publish.yaml | 2 +- .github/workflows/version-bump.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bdec793..2201b8c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -48,5 +48,5 @@ body: placeholder: | helm version: v3.x kubectl version: v1.x - node version: v20.x + node version: v22.x cluster: kind / EKS / GKE / ... diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5da55f2..a27e83d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22" - run: npm install - run: npx tsc --noEmit - run: npx cucumber-js --dry-run diff --git a/.github/workflows/real-tests.yml b/.github/workflows/real-tests.yml index ca5b9f9..3a5d863 100644 --- a/.github/workflows/real-tests.yml +++ b/.github/workflows/real-tests.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22" # scripts/tools.sh is the single source of truth for tool # versions - the same script a contributor runs locally via `npm diff --git a/.github/workflows/release-prepare.yaml b/.github/workflows/release-prepare.yaml index 34078be..50602a0 100644 --- a/.github/workflows/release-prepare.yaml +++ b/.github/workflows/release-prepare.yaml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22" - name: Compute release version id: version diff --git a/.github/workflows/release-publish.yaml b/.github/workflows/release-publish.yaml index 73389c2..3548167 100644 --- a/.github/workflows/release-publish.yaml +++ b/.github/workflows/release-publish.yaml @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22" - name: Determine expected version from the branch name id: expected diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml index eb213cc..657407c 100644 --- a/.github/workflows/version-bump.yaml +++ b/.github/workflows/version-bump.yaml @@ -35,7 +35,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "22" - name: Bump patch version if needed id: bump From b851e7409d635dbaf5a95e5fa6de87163c41bcd3 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 22:23:30 +0000 Subject: [PATCH 04/12] fix: use cucumber 13's built-in pretty formatter @cucumber/pretty-formatter 4.x no longer exports a class-based formatter, so --format @cucumber/pretty-formatter fails under cucumber 13. Use the built-in 'pretty' formatter and drop the redundant devDependency. Co-Authored-By: Claude Opus 5.5 --- package-lock.json | 1 - package.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 11309d0..08f6260 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ }, "devDependencies": { "@cucumber/cucumber": "^13.2.1", - "@cucumber/pretty-formatter": "^4.0.2", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", "@types/node": "^20.19.43", diff --git a/package.json b/package.json index 779df7f..361cc4d 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "test": "NODE_OPTIONS='--import tsx' cucumber-js", "test:ff": "NODE_OPTIONS='--import tsx' cucumber-js --fail-fast", - "test:verbose": "NODE_OPTIONS='--import tsx' cucumber-js --format @cucumber/pretty-formatter", + "test:verbose": "NODE_OPTIONS='--import tsx' cucumber-js --format pretty", "test:usage": "NODE_OPTIONS='--import tsx' cucumber-js --format usage", "test:junit": "NODE_OPTIONS='--import tsx' cucumber-js --format junit:report.xml", "docs:serve": "mkdocs serve", @@ -29,7 +29,6 @@ }, "devDependencies": { "@cucumber/cucumber": "^13.2.1", - "@cucumber/pretty-formatter": "^4.0.2", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", "@types/node": "^20.19.43", From 42835e99059c88a0596223952ed34f5b7da98067 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 22:33:18 +0000 Subject: [PATCH 05/12] Install helm and kubectl in devcontainer --- .devcontainer/devcontainer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 746a512..f6fc458 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,6 +8,11 @@ "ghcr.io/devcontainers/features/github-cli:1": { "installDirectlyFromGitHubRelease": true, "version": "latest" + }, + "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": { + "version": "latest", + "helm": "latest", + "minikube": "none" } }, "customizations": { From ddc6dc378ec215a8c46c9843e43125b9609cd8ff Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 22:51:36 +0000 Subject: [PATCH 06/12] fix: match Helm v4's 'cannot reuse a name' duplicate-install error Helm v4.3 spells it 'reuse' (v3: 're-use'), so assert only the shared tail 'name that is still in use'. Co-Authored-By: Claude Opus 5.5 --- docs/reference/HELM.md | 7 ++++--- features/helm/release-full.feature | 4 ++-- features/helm/release-short.feature | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/reference/HELM.md b/docs/reference/HELM.md index 214dd13..47ad625 100644 --- a/docs/reference/HELM.md +++ b/docs/reference/HELM.md @@ -587,8 +587,9 @@ else. !!! note "`helm install` is genuinely not idempotent" A second install of the same release name errors - (`cannot re-use a name that is still in use`) — that's real, correct - Helm behavior, not a framework limitation. The rerun-safe idiom used + (`cannot reuse a name that is still in use` — Helm v3 spelled it + `re-use`, so the scenarios match only the shared tail) — that's real, + correct Helm behavior, not a framework limitation. The rerun-safe idiom used throughout this suite is `upgrade` with `--install`/`--atomic` set (see the "upgrade" tab below). @@ -634,7 +635,7 @@ registered Release first. When I install Helm Release "" with --create-namespace Then the command exited with 0 When I install Helm Release known as "" - Then the command exited with 1 STDERR contains "cannot re-use a name" + Then the command exited with 1 STDERR contains "name that is still in use" ``` === "Full" diff --git a/features/helm/release-full.feature b/features/helm/release-full.feature index a3266ff..6ba8958 100644 --- a/features/helm/release-full.feature +++ b/features/helm/release-full.feature @@ -130,7 +130,7 @@ Feature: BDD Framework for Helm Releases (full table syntax) Then the command exited with 0 When I install Helm Release known as "" Then the command exited with 1: - | SOURCE | CONDITION | VALUE | - | STDERR | contains | cannot re-use a name | + | SOURCE | CONDITION | VALUE | + | STDERR | contains | name that is still in use | When I uninstall Helm Release known as "" Then the command exited with 0 diff --git a/features/helm/release-short.feature b/features/helm/release-short.feature index 161b2b1..52e8a0a 100644 --- a/features/helm/release-short.feature +++ b/features/helm/release-short.feature @@ -56,6 +56,6 @@ Feature: BDD Framework for Helm Releases (short syntax) When I install Helm Release "" with --create-namespace Then the command exited with 0 When I install Helm Release known as "" - Then the command exited with 1 STDERR contains "cannot re-use a name" + Then the command exited with 1 STDERR contains "name that is still in use" When I uninstall Helm Release known as "" Then the command exited with 0 From 0f0c2a4330907610e911d0727709fa7b9fe29789 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 22:56:40 +0000 Subject: [PATCH 07/12] fix: Docker scenarios label thomas-helm-test privileged themselves BuildKit needs a privileged pod, which the cluster's default baseline PodSecurity level rejects. The namespace label was a manual one-time step and was lost when thomas-helm-test got recreated. Each Docker scenario now sets pod-security.kubernetes.io/enforce=privileged before installing BuildKit and removes it after uninstalling. CI needs a ClusterRole to patch that one namespace (documented in docs/project/ci.md). Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 9 +++-- docs/project/ci.md | 38 +++++++++++++++++++ docs/reference/DOCKER.md | 15 +++++--- .../docker/docker-buildx-builder-full.feature | 12 +++++- .../docker-buildx-builder-short.feature | 6 ++- 5 files changed, 69 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ac0b224..8cf7f8c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -246,10 +246,11 @@ with MkDocs + Material). real image, scoped `--registry-credentials` via a `runCommand` `env` option) — shipped, verified. Resources: 20/20 scenarios passing. Docker: 12/12 scenarios passing against a real, disposable BuildKit + - registry pair in `thomas-helm-test` (which required labeling that - namespace `pod-security.kubernetes.io/enforce: privileged` — BuildKit - needs privileged/rootless-unconfined execution the default `baseline` - level blocks), run twice in a row, cluster confirmed clean both times + registry pair in `thomas-helm-test` (the scenarios themselves label + that namespace `pod-security.kubernetes.io/enforce=privileged` before + installing BuildKit and remove it after — BuildKit needs + privileged/rootless-unconfined execution the default `baseline` level + blocks; CI's grant for this is in `docs/project/ci.md`), run twice in a row, cluster confirmed clean both times (allowing a few seconds for normal terminating-Pod GC lag after `helm uninstall --wait` — a transient "Error" status during container shutdown, not a real leftover, see `docker-buildx-builder-full.feature`'s diff --git a/docs/project/ci.md b/docs/project/ci.md index d0e9090..a9423af 100644 --- a/docs/project/ci.md +++ b/docs/project/ci.md @@ -107,6 +107,44 @@ Assumes `thomas-helm-test` already exists — this scoped `ServiceAccount` can't create namespaces itself. +The one cluster-scoped exception: the Docker scenarios label +`thomas-helm-test` itself `pod-security.kubernetes.io/enforce=privileged` +for BuildKit (and remove it afterwards — see +[DOCKER.md](../reference/DOCKER.md)). A `Namespace` is a cluster-scoped +object, which a namespaced `Role` can't grant anything on, so this +needs a `ClusterRole` — pinned by `resourceNames` to that one namespace, +not namespaces in general: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: thomas-ci-namespace-label +rules: + - apiGroups: [""] + resources: ["namespaces"] + resourceNames: ["thomas-helm-test"] + verbs: ["get", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: thomas-ci-namespace-label +subjects: + - kind: ServiceAccount + name: thomas-ci + namespace: thomas-helm-test +roleRef: + kind: ClusterRole + name: thomas-ci-namespace-label + apiGroup: rbac.authorization.k8s.io +``` + +This does let CI raise its own namespace to `privileged` — the +namespace is meant to allow that for BuildKit anyway; the grant just +moves the label from a manual setup step into the scenarios that need +it. + ### `@requires-broad-rbac`: scenarios that deliberately can't run here `real-tests.yml` runs with `--tags "not @requires-broad-rbac"`. diff --git a/docs/reference/DOCKER.md b/docs/reference/DOCKER.md index 4aa6871..fbb896b 100644 --- a/docs/reference/DOCKER.md +++ b/docs/reference/DOCKER.md @@ -146,9 +146,14 @@ via `fixtures/docker/buildkitd.toml` to trust that registry as plain HTTP) into `thomas-helm-test`, then build and push a real image (`fixtures/docker/Dockerfile`) end to end. -**Prerequisite**: a real BuildKit pod needs privileged (or +**PodSecurity**: a real BuildKit pod needs privileged (or rootless-but-unconfined) execution, which the cluster's default -`baseline` PodSecurity level blocks. `thomas-helm-test` is labeled -`pod-security.kubernetes.io/enforce: privileged` to allow this — a -one-time, namespace-scoped setup step, not something these feature -files do themselves. +`baseline` PodSecurity level blocks. Each scenario labels +`thomas-helm-test` `pod-security.kubernetes.io/enforce=privileged` +([`I label namespace`](KUBECTL.md)) right before installing BuildKit, +and removes the label again right after uninstalling it — so a +recreated namespace needs no manual setup, and it only stays privileged +for as long as BuildKit runs (unless a scenario fails mid-way, in which +case the label is left behind until the next successful run). In CI +this needs a cluster-scoped grant to patch that one namespace — see +[CI: Cluster access](../project/ci.md#cluster-access-the-runner-pods-own-in-cluster-identity). diff --git a/features/docker/docker-buildx-builder-full.feature b/features/docker/docker-buildx-builder-full.feature index b8b308f..7526948 100644 --- a/features/docker/docker-buildx-builder-full.feature +++ b/features/docker/docker-buildx-builder-full.feature @@ -33,7 +33,13 @@ Feature: BDD Framework for Docker Buildx Builders (full table syntax) # test registry as plain HTTP - no mocks, and no dependency on any # BuildKit instance outside Thomas's own control. Needs a namespace # whose PodSecurity level allows a privileged (or rootless-unconfined) - # pod - see docs/reference/DOCKER.md. + # pod, so the scenario raises it here and drops it back after + # uninstalling BuildKit - see docs/reference/DOCKER.md. + When I label namespace "thomas-helm-test" with: + | OPTION | VALUE | + | | pod-security.kubernetes.io/enforce=privileged | + | --overwrite | True | + Then the command exited with 0 Given Helm Chart known as "": | PROPERTY | VALUE | | chart | buildkit-service | @@ -67,6 +73,10 @@ Feature: BDD Framework for Docker Buildx Builders (full table syntax) | OPTION | VALUE | | --wait | True | Then the command exited with 0 + When I label namespace "thomas-helm-test" with: + | OPTION | VALUE | + | | pod-security.kubernetes.io/enforce- | + Then the command exited with 0 When I uninstall Helm Release known as "" with: | OPTION | VALUE | | --wait | True | diff --git a/features/docker/docker-buildx-builder-short.feature b/features/docker/docker-buildx-builder-short.feature index 39666a4..a77e5ad 100644 --- a/features/docker/docker-buildx-builder-short.feature +++ b/features/docker/docker-buildx-builder-short.feature @@ -17,7 +17,9 @@ Feature: BDD Framework for Docker Buildx Builders (short syntax) # A real, disposable BuildKit instance trusting our real, disposable # test registry as plain HTTP - see docker-buildx-builder-full.feature's # Background for why, and docs/reference/DOCKER.md for the namespace - # PodSecurity prerequisite. + # PodSecurity label raised here and dropped after uninstalling BuildKit. + When I label namespace "thomas-helm-test" with --overwrite pod-security.kubernetes.io/enforce=privileged + Then the command exited with 0 Given Helm Chart known as "": | PROPERTY | VALUE | | chart | buildkit-service | @@ -36,5 +38,7 @@ Feature: BDD Framework for Docker Buildx Builders (short syntax) Then the command exited with 0 When I uninstall Helm Release "" with --wait Then the command exited with 0 + When I label namespace "thomas-helm-test" with pod-security.kubernetes.io/enforce- + Then the command exited with 0 When I uninstall Helm Release "" with --wait Then the command exited with 0 From 4dd7af6411b55db4a212c7669ce7f2c52ad4a797 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 22:57:11 +0000 Subject: [PATCH 08/12] docs: bind the namespace-label ClusterRole to arc-runners:thomas-ci Co-Authored-By: Claude Opus 5.5 --- docs/project/ci.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/project/ci.md b/docs/project/ci.md index a9423af..068166b 100644 --- a/docs/project/ci.md +++ b/docs/project/ci.md @@ -133,7 +133,7 @@ metadata: subjects: - kind: ServiceAccount name: thomas-ci - namespace: thomas-helm-test + namespace: arc-runners # where the runner's ServiceAccount really lives roleRef: kind: ClusterRole name: thomas-ci-namespace-label From 0a3a087b36caa4ac245a1a85271170ee0e3cbca2 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 23:00:47 +0000 Subject: [PATCH 09/12] test: skip Docker scenarios in CI via @requires-broad-rbac Labeling thomas-helm-test needs cluster-scoped access the CI ServiceAccount doesn't have; skip them in CI instead of adding a ClusterRole for now. They still run for anyone with broader access. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 3 +- docs/project/ci.md | 47 ++++--------------- docs/reference/DOCKER.md | 7 +-- .../docker/docker-buildx-builder-full.feature | 4 ++ .../docker-buildx-builder-short.feature | 4 ++ 5 files changed, 23 insertions(+), 42 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8cf7f8c..5f1e874 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -250,7 +250,8 @@ with MkDocs + Material). that namespace `pod-security.kubernetes.io/enforce=privileged` before installing BuildKit and remove it after — BuildKit needs privileged/rootless-unconfined execution the default `baseline` level - blocks; CI's grant for this is in `docs/project/ci.md`), run twice in a row, cluster confirmed clean both times + blocks; tagged `@requires-broad-rbac`, so skipped in CI — see + `docs/project/ci.md`), run twice in a row, cluster confirmed clean both times (allowing a few seconds for normal terminating-Pod GC lag after `helm uninstall --wait` — a transient "Error" status during container shutdown, not a real leftover, see `docker-buildx-builder-full.feature`'s diff --git a/docs/project/ci.md b/docs/project/ci.md index 068166b..83d4ed1 100644 --- a/docs/project/ci.md +++ b/docs/project/ci.md @@ -107,44 +107,6 @@ Assumes `thomas-helm-test` already exists — this scoped `ServiceAccount` can't create namespaces itself. -The one cluster-scoped exception: the Docker scenarios label -`thomas-helm-test` itself `pod-security.kubernetes.io/enforce=privileged` -for BuildKit (and remove it afterwards — see -[DOCKER.md](../reference/DOCKER.md)). A `Namespace` is a cluster-scoped -object, which a namespaced `Role` can't grant anything on, so this -needs a `ClusterRole` — pinned by `resourceNames` to that one namespace, -not namespaces in general: - -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: thomas-ci-namespace-label -rules: - - apiGroups: [""] - resources: ["namespaces"] - resourceNames: ["thomas-helm-test"] - verbs: ["get", "patch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: thomas-ci-namespace-label -subjects: - - kind: ServiceAccount - name: thomas-ci - namespace: arc-runners # where the runner's ServiceAccount really lives -roleRef: - kind: ClusterRole - name: thomas-ci-namespace-label - apiGroup: rbac.authorization.k8s.io -``` - -This does let CI raise its own namespace to `privileged` — the -namespace is meant to allow that for BuildKit anyway; the grant just -moves the label from a manual setup step into the scenarios that need -it. - ### `@requires-broad-rbac`: scenarios that deliberately can't run here `real-tests.yml` runs with `--tags "not @requires-broad-rbac"`. @@ -163,6 +125,15 @@ namespace just for one demo scenario isn't worth trading away the narrow-RBAC guarantee above for — this scenario still runs for anyone with broader cluster access, same as before. +Both `features/docker/` features carry it too: they label +`thomas-helm-test` itself `pod-security.kubernetes.io/enforce=privileged` +for BuildKit's privileged pod (see [DOCKER.md](../reference/DOCKER.md)). +A `Namespace` is a cluster-scoped object, which the namespaced `Role` +above can't grant anything on — running them in CI would need an extra +`ClusterRole`/`ClusterRoleBinding` (`get`/`patch` on `namespaces`, +`resourceNames: ["thomas-helm-test"]`, bound to +`arc-runners:thomas-ci`), deliberately not set up for now. + ## Tool versions: `scripts/tools.sh` (`npm run install:tools`) Both workflows install `helm`/`kubectl` via `npm run install:tools` diff --git a/docs/reference/DOCKER.md b/docs/reference/DOCKER.md index fbb896b..c147711 100644 --- a/docs/reference/DOCKER.md +++ b/docs/reference/DOCKER.md @@ -154,6 +154,7 @@ rootless-but-unconfined) execution, which the cluster's default and removes the label again right after uninstalling it — so a recreated namespace needs no manual setup, and it only stays privileged for as long as BuildKit runs (unless a scenario fails mid-way, in which -case the label is left behind until the next successful run). In CI -this needs a cluster-scoped grant to patch that one namespace — see -[CI: Cluster access](../project/ci.md#cluster-access-the-runner-pods-own-in-cluster-identity). +case the label is left behind until the next successful run). Labeling +a namespace needs cluster-scoped access CI's `ServiceAccount` doesn't +have, so both features are tagged `@requires-broad-rbac` and skipped in +CI — see [CI](../project/ci.md#requires-broad-rbac-scenarios-that-deliberately-cant-run-here). diff --git a/features/docker/docker-buildx-builder-full.feature b/features/docker/docker-buildx-builder-full.feature index 7526948..03a4d03 100644 --- a/features/docker/docker-buildx-builder-full.feature +++ b/features/docker/docker-buildx-builder-full.feature @@ -1,3 +1,7 @@ +# Labels thomas-helm-test itself (a cluster-scoped Namespace object) for +# BuildKit's privileged pod, which the narrowly-scoped CI ServiceAccount +# can't do - see docs/project/ci.md. +@requires-broad-rbac Feature: BDD Framework for Docker Buildx Builders (full table syntax) As a platform engineer I want to create, use, and remove a real `docker buildx` builder backed diff --git a/features/docker/docker-buildx-builder-short.feature b/features/docker/docker-buildx-builder-short.feature index a77e5ad..11cb1b8 100644 --- a/features/docker/docker-buildx-builder-short.feature +++ b/features/docker/docker-buildx-builder-short.feature @@ -1,3 +1,7 @@ +# Labels thomas-helm-test itself (a cluster-scoped Namespace object) for +# BuildKit's privileged pod, which the narrowly-scoped CI ServiceAccount +# can't do - see docs/project/ci.md. +@requires-broad-rbac Feature: BDD Framework for Docker Buildx Builders (short syntax) As a platform engineer I want to create, use, and remove a real `docker buildx` builder backed From 19abebcce15f6fd81ca3609ebfd09447c3f8a3a8 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 23:02:24 +0000 Subject: [PATCH 10/12] ci: cancel a PR's superseded real-tests run on new pushes Keep the global real-tests group on the test job (one shared namespace) but add a per-ref workflow group that cancels a PR's older run, so a stale commit no longer holds the only slot. main is never cancelled. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/real-tests.yml | 22 ++++++++++++++++------ docs/project/ci.md | 9 +++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/.github/workflows/real-tests.yml b/.github/workflows/real-tests.yml index 3a5d863..c1ab5ab 100644 --- a/.github/workflows/real-tests.yml +++ b/.github/workflows/real-tests.yml @@ -14,9 +14,16 @@ on: branches: [main] pull_request: +# Two levels: +# - per ref (this block): a newer push to the same PR cancels that PR's +# older run, running or still queued, so a stale commit never holds +# the one shared slot below. Pushes to main are never cancelled. +# - global (the test job's own `concurrency`): thomas-helm-test is one +# shared, fixed namespace - never run two suites against it at once. +# A cancel is graceful, so the `if: always()` uninstall step still runs. concurrency: - group: real-tests - cancel-in-progress: false # thomas-helm-test is one shared, fixed namespace — never run two suites against it at once + group: real-tests-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: test: @@ -26,6 +33,9 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository runs-on: thomas timeout-minutes: 30 + concurrency: + group: real-tests + cancel-in-progress: false steps: - uses: actions/checkout@v4 @@ -44,11 +54,11 @@ jobs: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - run: npm install - # Excludes @requires-broad-rbac (currently just quickstart.feature) + # Excludes @requires-broad-rbac (quickstart.feature, features/docker/) # - the CI ServiceAccount is intentionally scoped to - # thomas-helm-test only (see docs/project/ci.md), and that - # scenario deliberately deploys into a different namespace on - # purpose. Still runs locally for anyone with broader access. + # thomas-helm-test only (see docs/project/ci.md), and those + # scenarios need access outside it. Still run locally for anyone + # with broader access. - run: npm run test:verbose -- --tags "not @requires-broad-rbac" # TODO: I think namespace should be unique per run, not a fixed thomas-helm-test, diff --git a/docs/project/ci.md b/docs/project/ci.md index 83d4ed1..e4515ca 100644 --- a/docs/project/ci.md +++ b/docs/project/ci.md @@ -32,8 +32,13 @@ open one, and the runner pod's own in-cluster identity has real write access to the cluster (see below) — not something a fork PR's workflow run is trusted with. -`concurrency: {group: real-tests, cancel-in-progress: false}` — -serializes every run. `thomas-helm-test` is one fixed, shared +The `test` job's `concurrency: {group: real-tests, cancel-in-progress: +false}` serializes every run. A second, workflow-level group per ref +(`real-tests-${{ github.ref }}`, `cancel-in-progress` on pull requests +only) cancels a PR's older run — running or still queued — when a newer +commit is pushed, so a stale commit never holds that one slot; the +graceful cancel still runs the `if: always()` uninstall step. Pushes to +`main` are never cancelled. `thomas-helm-test` is one fixed, shared namespace (not one per run), and this cluster has already shown real fragility under concurrent/shared use elsewhere on it — see `rts-turbo`'s own `ci.yml` for the same tradeoff made the same way. From eca7b4cd2aa6795ebdd4902478cdaf8a05ee59a8 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 23:07:44 +0000 Subject: [PATCH 11/12] build: move to Node 26 everywhere engines node >=26 and @types/node ^26 to match the dev container's Node 26; every workflow reads the version from a new .nvmrc instead of hard-coding "22". Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yaml | 2 +- .github/workflows/real-tests.yml | 2 +- .github/workflows/release-prepare.yaml | 2 +- .github/workflows/release-publish.yaml | 2 +- .github/workflows/version-bump.yaml | 2 +- .nvmrc | 1 + CHANGELOG.md | 3 ++- package-lock.json | 18 +++++++++--------- package.json | 4 ++-- 9 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 .nvmrc diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a27e83d..e6dcb55 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "22" + node-version-file: .nvmrc - run: npm install - run: npx tsc --noEmit - run: npx cucumber-js --dry-run diff --git a/.github/workflows/real-tests.yml b/.github/workflows/real-tests.yml index c1ab5ab..b5a0f14 100644 --- a/.github/workflows/real-tests.yml +++ b/.github/workflows/real-tests.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "22" + node-version-file: .nvmrc # scripts/tools.sh is the single source of truth for tool # versions - the same script a contributor runs locally via `npm diff --git a/.github/workflows/release-prepare.yaml b/.github/workflows/release-prepare.yaml index 50602a0..0629089 100644 --- a/.github/workflows/release-prepare.yaml +++ b/.github/workflows/release-prepare.yaml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "22" + node-version-file: .nvmrc - name: Compute release version id: version diff --git a/.github/workflows/release-publish.yaml b/.github/workflows/release-publish.yaml index 3548167..597598e 100644 --- a/.github/workflows/release-publish.yaml +++ b/.github/workflows/release-publish.yaml @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "22" + node-version-file: .nvmrc - name: Determine expected version from the branch name id: expected diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml index 657407c..a83ad59 100644 --- a/.github/workflows/version-bump.yaml +++ b/.github/workflows/version-bump.yaml @@ -35,7 +35,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "22" + node-version-file: .nvmrc - name: Bump patch version if needed id: bump diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..6f4247a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +26 diff --git a/CHANGELOG.md b/CHANGELOG.md index 941aaf0..766c01f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/). workers are worker threads now, which don't get the `tsx` loader that `cucumber.mjs` registers: every `test*` script sets `NODE_OPTIONS='--import tsx'` (consumers running in parallel need the same). - `engines` is `node >=22`, as cucumber 13 dropped Node 20. + `engines` is `node >=26` (cucumber 13 dropped Node 20); CI, the dev + container and `@types/node` all track Node 26, via `.nvmrc` in CI. ### Added diff --git a/package-lock.json b/package-lock.json index 08f6260..55bd108 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,12 +17,12 @@ "@cucumber/cucumber": "^13.2.1", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.19.43", + "@types/node": "^26.6.4", "tsx": "^4.19.0", "typescript": "^5.6.0" }, "engines": { - "node": ">=22" + "node": ">=26" }, "peerDependencies": { "@cucumber/cucumber": "^13.2.1", @@ -742,13 +742,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", - "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "version": "26.6.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", + "integrity": "sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~8.9.0" } }, "node_modules/@types/normalize-package-data": { @@ -1587,9 +1587,9 @@ } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 361cc4d..21ee502 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@cucumber/cucumber": "^13.2.1", "@types/jmespath": "^0.15.2", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.19.43", + "@types/node": "^26.6.4", "tsx": "^4.19.0", "typescript": "^5.6.0" }, @@ -41,6 +41,6 @@ "undici": "7.29.1" }, "engines": { - "node": ">=22" + "node": ">=26" } } From afc9b751829428c0518f408b1cd60c212ad53592 Mon Sep 17 00:00:00 2001 From: Aleksandr Ilin Date: Wed, 7 Oct 2026 23:10:11 +0000 Subject: [PATCH 12/12] ci: install libatomic1 on the self-hosted runner for Node 26 Node 26's Linux binary needs libatomic.so.1, which the ARC runner image lacks, so real-tests died before running any scenario. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/real-tests.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/real-tests.yml b/.github/workflows/real-tests.yml index b5a0f14..5147f01 100644 --- a/.github/workflows/real-tests.yml +++ b/.github/workflows/real-tests.yml @@ -39,6 +39,15 @@ jobs: steps: - uses: actions/checkout@v4 + # Node 26's official Linux build links libatomic.so.1, which the + # self-hosted runner image doesn't ship (GitHub-hosted runners do). + - name: Install libatomic1 for Node 26 + run: | + if ! ldconfig -p | grep -q 'libatomic\.so\.1'; then + sudo apt-get update -qq + sudo apt-get install -y -qq libatomic1 + fi + - uses: actions/setup-node@v4 with: node-version-file: .nvmrc