From 6b5d68b61ae44fea603c0140c3af976545335b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20V=C3=A9rin?= Date: Fri, 27 Mar 2026 13:59:57 +0100 Subject: [PATCH 1/2] PREQ-4933 Use plain poetry install to respect lock file Replace `jf poetry install` with `poetry install` in build-poetry. The JFrog CLI command internally runs `poetry update` which ignores the lock file and re-resolves all dependencies, breaking builds when pyproject.toml constraints reference versions absent from the CI indexes (e.g. syrupy 5.*). `jf poetry-config` is kept to configure the Repox registry; only the install step changes. --- build-poetry/build.sh | 6 +++++- spec/build-poetry_spec.sh | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/build-poetry/build.sh b/build-poetry/build.sh index c7488545..ac0e6f17 100755 --- a/build-poetry/build.sh +++ b/build-poetry/build.sh @@ -267,7 +267,11 @@ jfrog_poetry_install() { jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" jf config use repox jf poetry-config --server-id-resolve repox --repo-resolve "$ARTIFACTORY_PYPI_REPO" - jf poetry install --build-name="$PROJECT" --build-number="$BUILD_NUMBER" + # Use plain `poetry install` to respect the lock file. + # `jf poetry install` internally runs `poetry update`, which re-resolves all + # dependencies and can fail when pyproject.toml constraints don't match what + # is available on the configured indexes (PREQ-4933). + poetry install } jfrog_poetry_publish() { diff --git a/spec/build-poetry_spec.sh b/spec/build-poetry_spec.sh index 6eff1d7f..5d283dab 100755 --- a/spec/build-poetry_spec.sh +++ b/spec/build-poetry_spec.sh @@ -100,7 +100,7 @@ Describe 'build-poetry/build.sh' The line 28 should equal "jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token dummy access token" The line 29 should equal "jf config use repox" The line 30 should equal "jf poetry-config --server-id-resolve repox --repo-resolve " - The line 31 should equal "jf poetry install --build-name=my-repo --build-number=42" + The line 31 should equal "poetry install" The line 32 should equal "::endgroup::" The line 33 should equal "::group::Build project" The line 35 should equal "poetry build" @@ -302,12 +302,12 @@ End Describe 'jfrog_poetry_install()' export PROJECT="my-repo" - It 'installs Poetry dependencies using JFrog CLI' + It 'configures JFrog and installs with plain poetry install' When call jfrog_poetry_install The line 1 should include "jf config add repox" The line 2 should include "jf config use repox" The line 3 should include "jf poetry-config" - The line 4 should include "jf poetry install" + The line 4 should equal "poetry install" End End From 8b0c3c06aa4a79a7dbe0039b808bf1e711942329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20V=C3=A9rin?= Date: Fri, 27 Mar 2026 14:08:33 +0100 Subject: [PATCH 2/2] PREQ-4933 Configure Poetry credentials for Repox source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jf poetry-config adds the Repox source to pyproject.toml but does not configure Poetry's own authentication — that is handled internally by jf poetry install. Since we now use plain poetry install, we need to explicitly set POETRY_HTTP_BASIC_REPOX credentials. - Retrieve ARTIFACTORY_USERNAME from Vault alongside the access token - Export POETRY_HTTP_BASIC_REPOX_USERNAME and _PASSWORD before install --- build-poetry/action.yml | 2 ++ build-poetry/build.sh | 8 +++----- spec/build-poetry_spec.sh | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build-poetry/action.yml b/build-poetry/action.yml index 4ea580ff..b171f47a 100644 --- a/build-poetry/action.yml +++ b/build-poetry/action.yml @@ -132,6 +132,7 @@ runs: ${{ (inputs.sonar-platform != 'none' || inputs.run-shadow-scans == 'true') && 'development/kv/data/sonarcloud url | SQC_EU_URL;' || '' }} ${{ (inputs.sonar-platform != 'none' || inputs.run-shadow-scans == 'true') && 'development/kv/data/sonarcloud token | SQC_EU_TOKEN;' || '' }} development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN; + development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} username | ARTIFACTORY_USERNAME; ${{ inputs.deploy != 'false' && inputs.run-shadow-scans != 'true' && format('development/artifactory/token/{{REPO_OWNER_NAME_DASH}}-{0} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;', env.ARTIFACTORY_DEPLOYER_ROLE) || '' }} # yamllint enable rule:line-length - name: Build, Analyze and deploy @@ -152,6 +153,7 @@ runs: ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo != '' && inputs.artifactory-deploy-repo || github.event.repository.visibility == 'public' && 'sonarsource-pypi-public-qa' || 'sonarsource-pypi-private-qa' }} ARTIFACTORY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_ACCESS_TOKEN }} + ARTIFACTORY_USERNAME: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_USERNAME }} ARTIFACTORY_DEPLOY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_DEPLOY_ACCESS_TOKEN }} POETRY_VIRTUALENVS_PATH: ${{ github.workspace }}/${{ inputs.poetry-virtualenvs-path }} POETRY_CACHE_DIR: ${{ github.workspace }}/${{ inputs.poetry-cache-dir }} diff --git a/build-poetry/build.sh b/build-poetry/build.sh index ac0e6f17..c65e3e97 100755 --- a/build-poetry/build.sh +++ b/build-poetry/build.sh @@ -45,7 +45,7 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_PYPI_REPO:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" "${RUN_SHADOW_SCANS:?}" +: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_PYPI_REPO:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" "${ARTIFACTORY_USERNAME:?}" "${RUN_SHADOW_SCANS:?}" : "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY_PULL_REQUEST:=false}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_EVENT_PATH:?}" : "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" "${GITHUB_ENV:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_SHA:?}" "${GITHUB_RUN_ID:?}" @@ -267,10 +267,8 @@ jfrog_poetry_install() { jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" jf config use repox jf poetry-config --server-id-resolve repox --repo-resolve "$ARTIFACTORY_PYPI_REPO" - # Use plain `poetry install` to respect the lock file. - # `jf poetry install` internally runs `poetry update`, which re-resolves all - # dependencies and can fail when pyproject.toml constraints don't match what - # is available on the configured indexes (PREQ-4933). + export POETRY_HTTP_BASIC_REPOX_USERNAME="$ARTIFACTORY_USERNAME" + export POETRY_HTTP_BASIC_REPOX_PASSWORD="$ARTIFACTORY_ACCESS_TOKEN" poetry install } diff --git a/spec/build-poetry_spec.sh b/spec/build-poetry_spec.sh index 5d283dab..936d065f 100755 --- a/spec/build-poetry_spec.sh +++ b/spec/build-poetry_spec.sh @@ -16,6 +16,7 @@ export GITHUB_ENV=/dev/null export ARTIFACTORY_URL="https://dummy.repox" export ARTIFACTORY_PYPI_REPO="" export ARTIFACTORY_ACCESS_TOKEN="dummy access token" +export ARTIFACTORY_USERNAME="dummy-user" export ARTIFACTORY_DEPLOY_REPO="" export ARTIFACTORY_DEPLOY_ACCESS_TOKEN="" export GITHUB_REPOSITORY="my-org/my-repo"