From 0c55653f82d55f366eb4346ea49e1c5bf9288aea Mon Sep 17 00:00:00 2001 From: Dmytro Smirnov Date: Wed, 22 Jul 2026 14:56:52 +0300 Subject: [PATCH 1/4] fix: upgrade npm bundled tar --- .../workflows/docker-dependency-updater.yml | 23 ++++++++++++++++--- Dockerfile | 5 +++- ci/prompts/docker-dependency-nonapt.md | 1 + src/tests/10_validate_environment.sh | 14 +++++++++-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker-dependency-updater.yml b/.github/workflows/docker-dependency-updater.yml index a8a19c5..e7a3a55 100644 --- a/.github/workflows/docker-dependency-updater.yml +++ b/.github/workflows/docker-dependency-updater.yml @@ -3,7 +3,7 @@ name: udx-automation / worker-nodejs dependency upgrade "on": schedule: - - cron: "0 5 * * 1" + - cron: "0 5 * * *" workflow_dispatch: concurrency: @@ -152,6 +152,7 @@ jobs: base_image: ${{ steps.probe.outputs.base_image }} changed: ${{ steps.changes.outputs.changed }} node_version: ${{ steps.probe.outputs.node_version }} + npm_version: ${{ steps.probe.outputs.npm_version }} pr_url: ${{ steps.create-pr.outputs.pull-request-url }} permissions: @@ -204,6 +205,10 @@ jobs: '[.[] | select(.lts != false) | .version | ltrimstr("v") | select(startswith($major + "."))][0]')" test -n "${node_version}" + npm_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ + https://registry.npmjs.org/npm/latest | jq -r '.version')" + test -n "${npm_version}" + base_image="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ @@ -218,6 +223,9 @@ jobs: perl -0pi -e \ "s/^ARG NODE_VERSION=.*/ARG NODE_VERSION=${node_version}/m" \ "${PROBE_DOCKERFILE}" + perl -0pi -e \ + "s/^ARG NPM_VERSION=.*/ARG NPM_VERSION=${npm_version}/m" \ + "${PROBE_DOCKERFILE}" apt_packages=(xz-utils) @@ -239,8 +247,8 @@ jobs: dpkg-query -W -f='${binary:Package}\t${Version}\n' "$@" EOF strategy_summary="Use the latest udx-worker release, latest Node.js " - strategy_summary="${strategy_summary}LTS release within the current major, and a no-pin apt " - strategy_summary="${strategy_summary}probe for xz-utils." + strategy_summary="${strategy_summary}LTS release within the current major, latest npm " + strategy_summary="${strategy_summary}release, and a no-pin apt probe for xz-utils." non_apt_path="${probe_dir}/non-apt.json" node <<'NODE' > "${non_apt_path}" @@ -276,6 +284,7 @@ jobs: --arg base_image "${base_image}" \ --arg dockerfile "${DOCKERFILE}" \ --arg node_version "${node_version}" \ + --arg npm_version "${npm_version}" \ --arg probe_dockerfile "${PROBE_DOCKERFILE}" \ --arg strategy_summary "${strategy_summary}" \ --slurpfile non_apt "${non_apt_path}" \ @@ -285,6 +294,7 @@ jobs: method: "worker-nodejs dependency probe", base_image: "usabilitydynamics/udx-worker:" + $base_image, node_version: $node_version, + npm_version: $npm_version, strategy: { summary: $strategy_summary, dockerfile: $dockerfile, @@ -306,6 +316,7 @@ jobs: echo "apt_count=${apt_count}" >> "${GITHUB_OUTPUT}" echo "base_image=${base_image}" >> "${GITHUB_OUTPUT}" echo "node_version=${node_version}" >> "${GITHUB_OUTPUT}" + echo "npm_version=${npm_version}" >> "${GITHUB_OUTPUT}" echo "Upgrade probe: wrote ${PROBE_REPORT}." - name: Upload dependency report uses: actions/upload-artifact@v6 @@ -339,12 +350,14 @@ jobs: base_image="$(jq -r '.base_image' "${REPORT_PATH}")" node_version="$(jq -r '.node_version' "${REPORT_PATH}")" + npm_version="$(jq -r '.npm_version' "${REPORT_PATH}")" xz_version="$(jq -r \ '.dependencies.apt[] | select(.name == "xz-utils") | .installed' \ "${REPORT_PATH}")" test -n "${base_image}" test -n "${node_version}" + test -n "${npm_version}" test -n "${xz_version}" perl -0pi -e \ @@ -353,6 +366,9 @@ jobs: perl -0pi -e \ "s/^ARG NODE_VERSION=.*/ARG NODE_VERSION=${node_version}/m" \ "${DOCKERFILE}" + perl -0pi -e \ + "s/^ARG NPM_VERSION=.*/ARG NPM_VERSION=${npm_version}/m" \ + "${DOCKERFILE}" perl -0pi -e \ "s/xz-utils=[^[:space:]\\]+/xz-utils=${xz_version}/" \ "${DOCKERFILE}" @@ -360,6 +376,7 @@ jobs: echo "Upgrade pins:" echo "- Base image: ${base_image}" echo "- Node.js: ${node_version}" + echo "- npm: ${npm_version}" echo "- xz-utils: ${xz_version}" env: DOCKERFILE: ${{ needs.config.outputs.dockerfile }} diff --git a/Dockerfile b/Dockerfile index c30e3f2..1041087 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,9 @@ FROM usabilitydynamics/udx-worker:0.47.0 # Add metadata labels LABEL version="0.32.0" -# Set build arguments for Node.js version and application port +# Set build arguments for Node.js, npm, and application port ARG NODE_VERSION=24.18.0 +ARG NPM_VERSION=12.0.1 ARG APP_PORT=8080 # Add Node.js to PATH @@ -48,6 +49,8 @@ RUN set -ex && \ # Verify installation and resolution path node --version && \ command -v npm && head -n 1 "$(command -v npm)" && npm --version && \ + npm install --global "npm@${NPM_VERSION}" && \ + npm --version && \ rm -rf /tmp/* # Remove xz-utils as it's no longer needed diff --git a/ci/prompts/docker-dependency-nonapt.md b/ci/prompts/docker-dependency-nonapt.md index f7c355c..f34576e 100644 --- a/ci/prompts/docker-dependency-nonapt.md +++ b/ci/prompts/docker-dependency-nonapt.md @@ -1,6 +1,7 @@ Non-apt dependency rules: - Use `dependencies.non_apt.pins` and `dependencies.non_apt.urls` from the dependency report as the starting inventory of Dockerfile-owned non-apt candidates. - For `NODE_VERSION`, check the official Node.js release index and keep the latest stable LTS release from the same active LTS line unless the Dockerfile or repo docs explicitly require a different major version. +- For `NPM_VERSION`, use the latest npm release only when its Node.js engine range supports the Dockerfile `NODE_VERSION`; retain the current npm version when compatibility is not explicit. - Preserve the UDX Worker base image tag already selected by the deterministic updater unless clear upstream evidence shows a newer stable `udx/worker` release. - Include the upstream source URL for every non-apt update in the changelog. - Leave pins unchanged when the upstream source cannot be identified, cannot be checked, is ambiguous, or does not clearly show a newer stable release/version. diff --git a/src/tests/10_validate_environment.sh b/src/tests/10_validate_environment.sh index e2f462e..a7f8cae 100644 --- a/src/tests/10_validate_environment.sh +++ b/src/tests/10_validate_environment.sh @@ -25,5 +25,15 @@ if ! command -v worker >/dev/null 2>&1; then exit 3 fi -echo "Node.js version is correct and Worker PM is available." -exit 0 \ No newline at end of file +# Verify that npm's bundled tar includes the security fix. +TAR_VERSION=$(node -p 'require("/usr/local/node/lib/node_modules/npm/node_modules/tar/package.json").version') +if ! node -e ' + const [major, minor, patch] = process.argv[1].split(".").map(Number); + process.exit(major > 7 || (major === 7 && (minor > 5 || (minor === 5 && patch >= 19))) ? 0 : 1); +' "$TAR_VERSION"; then + echo "Error: npm bundled tar must be at least 7.5.19. Current: $TAR_VERSION" + exit 4 +fi + +echo "Node.js version is correct, npm bundled tar is patched, and Worker PM is available." +exit 0 From a751b8b49cb8ec36be56d4ff02c526b260d7994d Mon Sep 17 00:00:00 2001 From: Dmytro Smirnov Date: Wed, 22 Jul 2026 15:10:35 +0300 Subject: [PATCH 2/4] fix: harden npm dependency updates --- .../workflows/docker-dependency-updater.yml | 27 ++++++++++++++++--- Dockerfile | 2 ++ src/tests/10_validate_environment.sh | 14 ++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker-dependency-updater.yml b/.github/workflows/docker-dependency-updater.yml index e7a3a55..86b3656 100644 --- a/.github/workflows/docker-dependency-updater.yml +++ b/.github/workflows/docker-dependency-updater.yml @@ -198,16 +198,35 @@ jobs: current_node_version="$(awk -F= '/^ARG NODE_VERSION=/ { print $2; exit }' "${DOCKERFILE}")" current_node_major="${current_node_version%%.*}" + current_npm_version="$(awk -F= '/^ARG NPM_VERSION=/ { print $2; exit }' "${DOCKERFILE}")" test -n "${current_node_major}" + test -n "${current_npm_version}" node_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL https://nodejs.org/dist/index.json \ | jq -r --arg major "${current_node_major}" \ '[.[] | select(.lts != false) | .version | ltrimstr("v") | select(startswith($major + "."))][0]')" test -n "${node_version}" - npm_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ + latest_npm_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ https://registry.npmjs.org/npm/latest | jq -r '.version')" - test -n "${npm_version}" + test -n "${latest_npm_version}" + + npm_engines="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ + "https://registry.npmjs.org/npm/${latest_npm_version}" | jq -r '.engines.node // empty')" + npm_version="${current_npm_version}" + if [ -n "${npm_engines}" ] && node - "${node_version}" "${npm_engines}" <<'NODE' + const { execFileSync } = require("node:child_process"); + const path = require("node:path"); + const [nodeVersion, range] = process.argv.slice(2); + const npmRoot = execFileSync("npm", ["root", "--global"], { encoding: "utf8" }).trim(); + const semver = require(path.join(npmRoot, "npm/node_modules/semver")); + process.exit(semver.satisfies(nodeVersion, range) ? 0 : 1); + NODE + then + npm_version="${latest_npm_version}" + else + echo "Keeping npm ${current_npm_version}: ${latest_npm_version} does not explicitly support Node.js ${node_version}." + fi base_image="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ @@ -247,8 +266,8 @@ jobs: dpkg-query -W -f='${binary:Package}\t${Version}\n' "$@" EOF strategy_summary="Use the latest udx-worker release, latest Node.js " - strategy_summary="${strategy_summary}LTS release within the current major, latest npm " - strategy_summary="${strategy_summary}release, and a no-pin apt probe for xz-utils." + strategy_summary="${strategy_summary}LTS release within the current major, the latest npm " + strategy_summary="${strategy_summary}release compatible with that Node.js version, and a no-pin apt probe for xz-utils." non_apt_path="${probe_dir}/non-apt.json" node <<'NODE' > "${non_apt_path}" diff --git a/Dockerfile b/Dockerfile index 1041087..1204fe6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,6 +51,8 @@ RUN set -ex && \ command -v npm && head -n 1 "$(command -v npm)" && npm --version && \ npm install --global "npm@${NPM_VERSION}" && \ npm --version && \ + npm cache clean --force && \ + rm -rf /root/.npm && \ rm -rf /tmp/* # Remove xz-utils as it's no longer needed diff --git a/src/tests/10_validate_environment.sh b/src/tests/10_validate_environment.sh index a7f8cae..98884ef 100644 --- a/src/tests/10_validate_environment.sh +++ b/src/tests/10_validate_environment.sh @@ -25,8 +25,18 @@ if ! command -v worker >/dev/null 2>&1; then exit 3 fi -# Verify that npm's bundled tar includes the security fix. -TAR_VERSION=$(node -p 'require("/usr/local/node/lib/node_modules/npm/node_modules/tar/package.json").version') +# Verify that npm's bundled tar includes the security fix. Resolve npm's global +# installation dynamically so the test follows the installed Node.js layout. +if ! TAR_VERSION=$(node -e ' + const { execFileSync } = require("node:child_process"); + const path = require("node:path"); + const npmRoot = execFileSync("npm", ["root", "--global"], { encoding: "utf8" }).trim(); + process.stdout.write(require(path.join(npmRoot, "npm/node_modules/tar/package.json")).version); +'); then + echo "Error: unable to determine npm bundled tar version." + exit 4 +fi + if ! node -e ' const [major, minor, patch] = process.argv[1].split(".").map(Number); process.exit(major > 7 || (major === 7 && (minor > 5 || (minor === 5 && patch >= 19))) ? 0 : 1); From f03eb59c540b8b104de765b1f3c71a180ccd7c50 Mon Sep 17 00:00:00 2001 From: Dmytro Smirnov Date: Wed, 22 Jul 2026 15:14:51 +0300 Subject: [PATCH 3/4] fix(ci): delegate non-apt upgrades to Copilot --- .../workflows/docker-dependency-updater.yml | 149 ++---------------- 1 file changed, 13 insertions(+), 136 deletions(-) diff --git a/.github/workflows/docker-dependency-updater.yml b/.github/workflows/docker-dependency-updater.yml index 86b3656..bc61f2d 100644 --- a/.github/workflows/docker-dependency-updater.yml +++ b/.github/workflows/docker-dependency-updater.yml @@ -149,10 +149,7 @@ jobs: outputs: apt_count: ${{ steps.probe.outputs.apt_count }} - base_image: ${{ steps.probe.outputs.base_image }} changed: ${{ steps.changes.outputs.changed }} - node_version: ${{ steps.probe.outputs.node_version }} - npm_version: ${{ steps.probe.outputs.npm_version }} pr_url: ${{ steps.create-pr.outputs.pull-request-url }} permissions: @@ -170,7 +167,6 @@ jobs: timeout-minutes: 8 env: DOCKERFILE: ${{ needs.config.outputs.dockerfile }} - GITHUB_TOKEN: ${{ github.token }} PROBE_DOCKERFILE: ${{ needs.config.outputs.probe_dockerfile }} PROBE_IMAGE: ${{ needs.config.outputs.image }} PROBE_REPORT: ${{ needs.config.outputs.report_path }} @@ -196,56 +192,6 @@ jobs: } ' "${DOCKERFILE}" > "${PROBE_DOCKERFILE}" - current_node_version="$(awk -F= '/^ARG NODE_VERSION=/ { print $2; exit }' "${DOCKERFILE}")" - current_node_major="${current_node_version%%.*}" - current_npm_version="$(awk -F= '/^ARG NPM_VERSION=/ { print $2; exit }' "${DOCKERFILE}")" - test -n "${current_node_major}" - test -n "${current_npm_version}" - - node_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL https://nodejs.org/dist/index.json \ - | jq -r --arg major "${current_node_major}" \ - '[.[] | select(.lts != false) | .version | ltrimstr("v") | select(startswith($major + "."))][0]')" - test -n "${node_version}" - - latest_npm_version="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ - https://registry.npmjs.org/npm/latest | jq -r '.version')" - test -n "${latest_npm_version}" - - npm_engines="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ - "https://registry.npmjs.org/npm/${latest_npm_version}" | jq -r '.engines.node // empty')" - npm_version="${current_npm_version}" - if [ -n "${npm_engines}" ] && node - "${node_version}" "${npm_engines}" <<'NODE' - const { execFileSync } = require("node:child_process"); - const path = require("node:path"); - const [nodeVersion, range] = process.argv.slice(2); - const npmRoot = execFileSync("npm", ["root", "--global"], { encoding: "utf8" }).trim(); - const semver = require(path.join(npmRoot, "npm/node_modules/semver")); - process.exit(semver.satisfies(nodeVersion, range) ? 0 : 1); - NODE - then - npm_version="${latest_npm_version}" - else - echo "Keeping npm ${current_npm_version}: ${latest_npm_version} does not explicitly support Node.js ${node_version}." - fi - - base_image="$(curl --retry 5 --retry-all-errors --retry-delay 2 -fsSL \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/udx/worker/releases/latest" \ - | jq -r '.tag_name | ltrimstr("v")')" - test -n "${base_image}" - base_image_ref="usabilitydynamics/udx-worker:${base_image}" - - perl -0pi -e \ - "s#^FROM usabilitydynamics/udx-worker:.*#FROM ${base_image_ref}#m" \ - "${PROBE_DOCKERFILE}" - perl -0pi -e \ - "s/^ARG NODE_VERSION=.*/ARG NODE_VERSION=${node_version}/m" \ - "${PROBE_DOCKERFILE}" - perl -0pi -e \ - "s/^ARG NPM_VERSION=.*/ARG NPM_VERSION=${npm_version}/m" \ - "${PROBE_DOCKERFILE}" - apt_packages=(xz-utils) { @@ -265,9 +211,8 @@ jobs: dpkg-query -W -f='${binary:Package}\t${Version}\n' "$@" EOF - strategy_summary="Use the latest udx-worker release, latest Node.js " - strategy_summary="${strategy_summary}LTS release within the current major, the latest npm " - strategy_summary="${strategy_summary}release compatible with that Node.js version, and a no-pin apt probe for xz-utils." + base_image="$(awk '$1 == "FROM" { print $2; exit }' "${DOCKERFILE}")" + strategy_summary="Render a temporary Dockerfile with apt package pins removed, build it against the configured base image, then read installed versions with dpkg-query." non_apt_path="${probe_dir}/non-apt.json" node <<'NODE' > "${non_apt_path}" @@ -302,18 +247,14 @@ jobs: --arg generated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --arg base_image "${base_image}" \ --arg dockerfile "${DOCKERFILE}" \ - --arg node_version "${node_version}" \ - --arg npm_version "${npm_version}" \ --arg probe_dockerfile "${PROBE_DOCKERFILE}" \ --arg strategy_summary "${strategy_summary}" \ --slurpfile non_apt "${non_apt_path}" \ --rawfile apt_versions "${apt_versions_path}" \ '{ generated_at: $generated_at, - method: "worker-nodejs dependency probe", - base_image: "usabilitydynamics/udx-worker:" + $base_image, - node_version: $node_version, - npm_version: $npm_version, + method: "no-pin apt probe", + base_image: $base_image, strategy: { summary: $strategy_summary, dockerfile: $dockerfile, @@ -333,9 +274,6 @@ jobs: apt_count="$(jq '.dependencies.apt | length' "${PROBE_REPORT}")" echo "apt_count=${apt_count}" >> "${GITHUB_OUTPUT}" - echo "base_image=${base_image}" >> "${GITHUB_OUTPUT}" - echo "node_version=${node_version}" >> "${GITHUB_OUTPUT}" - echo "npm_version=${npm_version}" >> "${GITHUB_OUTPUT}" echo "Upgrade probe: wrote ${PROBE_REPORT}." - name: Upload dependency report uses: actions/upload-artifact@v6 @@ -346,70 +284,13 @@ jobs: ${{ needs.config.outputs.report_path }} ${{ needs.config.outputs.probe_dockerfile }} - - name: Check Copilot availability - id: copilot-availability - timeout-minutes: 1 - run: | - set -euo pipefail - - if [ -n "${COPILOT_GITHUB_TOKEN:-}" ]; then - echo "available=true" >> "${GITHUB_OUTPUT}" - echo "Copilot CLI review is available." - else - echo "available=false" >> "${GITHUB_OUTPUT}" - echo "Copilot CLI review skipped; COPILOT_GITHUB_TOKEN is not set." - fi - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - - - name: Update Dockerfile pins - timeout-minutes: 3 - run: | - set -euo pipefail - - base_image="$(jq -r '.base_image' "${REPORT_PATH}")" - node_version="$(jq -r '.node_version' "${REPORT_PATH}")" - npm_version="$(jq -r '.npm_version' "${REPORT_PATH}")" - xz_version="$(jq -r \ - '.dependencies.apt[] | select(.name == "xz-utils") | .installed' \ - "${REPORT_PATH}")" - - test -n "${base_image}" - test -n "${node_version}" - test -n "${npm_version}" - test -n "${xz_version}" - - perl -0pi -e \ - "s#^FROM usabilitydynamics/udx-worker:.*#FROM ${base_image}#m" \ - "${DOCKERFILE}" - perl -0pi -e \ - "s/^ARG NODE_VERSION=.*/ARG NODE_VERSION=${node_version}/m" \ - "${DOCKERFILE}" - perl -0pi -e \ - "s/^ARG NPM_VERSION=.*/ARG NPM_VERSION=${npm_version}/m" \ - "${DOCKERFILE}" - perl -0pi -e \ - "s/xz-utils=[^[:space:]\\]+/xz-utils=${xz_version}/" \ - "${DOCKERFILE}" - - echo "Upgrade pins:" - echo "- Base image: ${base_image}" - echo "- Node.js: ${node_version}" - echo "- npm: ${npm_version}" - echo "- xz-utils: ${xz_version}" - env: - DOCKERFILE: ${{ needs.config.outputs.dockerfile }} - REPORT_PATH: ${{ needs.config.outputs.report_path }} - - name: Set up Node.js for Copilot CLI - if: steps.copilot-availability.outputs.available == 'true' uses: actions/setup-node@v6 timeout-minutes: 3 with: node-version: "22" - name: Install Copilot CLI - if: steps.copilot-availability.outputs.available == 'true' timeout-minutes: 3 run: | npm install -g "@github/copilot@${COPILOT_CLI_VERSION}" @@ -417,8 +298,7 @@ jobs: env: COPILOT_CLI_VERSION: ${{ needs.config.outputs.copilot_cli_version }} - - name: Review Dockerfile with Copilot CLI - if: steps.copilot-availability.outputs.available == 'true' + - name: Update Dockerfile with Copilot CLI timeout-minutes: 8 run: | set -euo pipefail @@ -431,6 +311,11 @@ jobs: jq -e '.dependencies.apt and .dependencies.non_apt' \ "${REPORT_PATH}" >/dev/null + if [ -z "${COPILOT_GITHUB_TOKEN:-}" ]; then + echo "COPILOT_GITHUB_TOKEN secret is required for non-apt dependency updates." >&2 + exit 1 + fi + prompt_path=".tmp/dependency-upgrade/copilot-prompt.md" mkdir -p "$(dirname "${prompt_path}")" : > "${prompt_path}" @@ -445,8 +330,7 @@ jobs: copilot_args=( --prompt "$(cat "${prompt_path}")" - --allow-tool=write - --deny-tool=shell + --allow-all-tools --allow-all-urls --no-ask-user --no-auto-update @@ -511,13 +395,8 @@ jobs: echo "## Evidence" echo echo "- Probe report artifact: \`${REPORT_PATH}\`" - if [ "${COPILOT_AVAILABLE}" = "true" ]; then - echo "- Copilot CLI review: enabled" - else - echo "- Copilot CLI review: skipped; token not configured" - fi - if [ "${COPILOT_AVAILABLE}" = "true" ] && - [ "${UPLOAD_COPILOT_SESSION}" = "true" ]; then + echo "- Copilot CLI: updated non-apt dependencies" + if [ "${UPLOAD_COPILOT_SESSION}" = "true" ]; then echo "- Copilot session artifact: \`copilot-docker-dependency-session.md\`" fi echo "## Diff" @@ -528,7 +407,6 @@ jobs: } > docker-dependency-pr-body.md echo "Upgrade PR body: prepared docker-dependency-pr-body.md" env: - COPILOT_AVAILABLE: ${{ steps.copilot-availability.outputs.available }} REPORT_PATH: ${{ needs.config.outputs.report_path }} UPLOAD_COPILOT_SESSION: ${{ needs.config.outputs.upload_copilot_session }} @@ -544,7 +422,6 @@ jobs: - name: Upload Copilot session if: >- always() && - steps.copilot-availability.outputs.available == 'true' && needs.config.outputs.upload_copilot_session == 'true' uses: actions/upload-artifact@v6 timeout-minutes: 3 From 0341bfa4aeddd154bae255904438af1a99745643 Mon Sep 17 00:00:00 2001 From: Dmytro Smirnov Date: Wed, 22 Jul 2026 15:24:49 +0300 Subject: [PATCH 4/4] test: parse bundled tar version as semver --- src/tests/10_validate_environment.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tests/10_validate_environment.sh b/src/tests/10_validate_environment.sh index 98884ef..4792c7b 100644 --- a/src/tests/10_validate_environment.sh +++ b/src/tests/10_validate_environment.sh @@ -38,8 +38,13 @@ if ! TAR_VERSION=$(node -e ' fi if ! node -e ' - const [major, minor, patch] = process.argv[1].split(".").map(Number); - process.exit(major > 7 || (major === 7 && (minor > 5 || (minor === 5 && patch >= 19))) ? 0 : 1); + const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(process.argv[1]); + if (!match) process.exit(1); + const version = match.slice(1, 4).map(Number); + const minimum = [7, 5, 19]; + const comparison = version.findIndex((part, index) => part !== minimum[index]); + const hasPrerelease = process.argv[1].includes("-"); + process.exit(comparison === -1 ? (hasPrerelease ? 1 : 0) : (version[comparison] > minimum[comparison] ? 0 : 1)); ' "$TAR_VERSION"; then echo "Error: npm bundled tar must be at least 7.5.19. Current: $TAR_VERSION" exit 4