TEST - fix uv/repox 401 in serializer-runner (do not merge, port to sonar-python-enterprise) - #2301
TEST - fix uv/repox 401 in serializer-runner (do not merge, port to sonar-python-enterprise)#2301mary-georgiou wants to merge 1 commit into
Conversation
The serializer-runner exec step invokes uv, which authenticates named indexes via UV_INDEX_<NAME>_USERNAME/PASSWORD env vars rather than pip.conf. Since the tox-to-uv migration, this index has had no credentials wired up, so every cache-cold package install 401s against the sonarsource-pypi repox index. Re-expose the Artifactory reader credentials that config-maven already exports for the job under the names uv expects for the 'repox' index. CI-verified fix; requires the equivalent change to be merged via sonar-python-enterprise.
| <!-- | ||
| uv authenticates the "repox" index declared in typeshed_serializer/pyproject.toml via | ||
| UV_INDEX_REPOX_USERNAME/PASSWORD. It does not read pip.conf, so the Artifactory reader | ||
| credentials that config-maven already exports for the job must be re-exposed under the | ||
| names uv expects, or every cache-cold package install 401s against sonarsource-pypi. | ||
| --> | ||
| <environmentVariables> | ||
| <UV_INDEX_REPOX_USERNAME>${env.ARTIFACTORY_USERNAME}</UV_INDEX_REPOX_USERNAME> | ||
| <UV_INDEX_REPOX_PASSWORD>${env.ARTIFACTORY_ACCESS_TOKEN}</UV_INDEX_REPOX_PASSWORD> | ||
| </environmentVariables> |
There was a problem hiding this comment.
⚠️ Bug: Unset ARTIFACTORY_* env vars clobber local uv credentials
${env.ARTIFACTORY_USERNAME} / ${env.ARTIFACTORY_ACCESS_TOKEN} only resolve inside the CI job. On a developer machine (or any run outside build-maven), those env vars are absent, so Maven passes the parameter through unresolved — the child process gets UV_INDEX_REPOX_USERNAME=${env.ARTIFACTORY_USERNAME} (literal) or an empty value. Because the vars are now always present in the environment of the uv run children spawned by runners/serializer_runner.py, uv treats them as explicit credentials for the default repox index and sends them as Basic auth, so it no longer falls back to .netrc/keyring, and it also overrides any real UV_INDEX_REPOX_USERNAME/_PASSWORD the developer exported in their shell (exec-maven-plugin's <environmentVariables> are merged on top of the inherited environment). Result: mvn -DgenerateTypeshedStubs ... starts 401'ing locally for exactly the developers who previously had working repox auth. Gate the env vars so they are only set when the credentials actually exist.
Fix 1: Only inject the uv index credentials when ARTIFACTORY_ACCESS_TOKEN is present in the environment (CI), leaving local runs untouched.
<!-- python-frontend/pom.xml: drop <environmentVariables> from the execution and
add a second profile that only contributes them when the CI credentials exist.
Maven merges executions with the same id across active profiles. -->
<profile>
<id>uv-repox-credentials</id>
<activation>
<property><name>env.ARTIFACTORY_ACCESS_TOKEN</name></property>
</activation>
<properties>
<uv.index.repox.username>${env.ARTIFACTORY_USERNAME}</uv.index.repox.username>
<uv.index.repox.password>${env.ARTIFACTORY_ACCESS_TOKEN}</uv.index.repox.password>
</properties>
<!-- ... exec-maven-plugin/serializer-runner execution carrying only
<environmentVariables> that reference the two properties above ... -->
</profile>
- Apply fix
Fix 2: Map the Artifactory credentials to uv's index env vars in the runner itself, only when both are set, so local runs keep their own auth.
# python-frontend/typeshed_serializer/runners/serializer_runner.py
def _uv_env() -> dict:
env = os.environ.copy()
user, token = env.get('ARTIFACTORY_USERNAME'), env.get('ARTIFACTORY_ACCESS_TOKEN')
if user and token:
env.setdefault('UV_INDEX_REPOX_USERNAME', user)
env.setdefault('UV_INDEX_REPOX_PASSWORD', token)
return env
# then pass env=_uv_env() to every subprocess.run([...'uv'...]) call
# (in _run_serialize and _run_tests) and revert the pom.xml change.
- Apply fix
Check a box to apply a fix or reply for a change | Was this helpful? React with 👍 / 👎
| <environmentVariables> | ||
| <UV_INDEX_REPOX_USERNAME>${env.ARTIFACTORY_USERNAME}</UV_INDEX_REPOX_USERNAME> | ||
| <UV_INDEX_REPOX_PASSWORD>${env.ARTIFACTORY_ACCESS_TOKEN}</UV_INDEX_REPOX_PASSWORD> | ||
| </environmentVariables> |
There was a problem hiding this comment.
💡 Quality: uv repox auth wired only at the Maven exec call site
The credentials are injected solely into the serializer-runner exec goal, but the same repox default index is also consumed by docker/cmd.sh (uv sync + uv run ..., launched via docker/docker-compose.yml, which forwards only USER_ID/GROUP_ID) and by the repo-root pyproject.toml, which declares the identical [[tool.uv.index]] block. Anyone regenerating stubs through the documented container path still gets the 401 this PR fixes for the Maven path. Wiring the mapping where uv is invoked (see the runner-side fix above) plus passing ARTIFACTORY_USERNAME/ARTIFACTORY_ACCESS_TOKEN through docker-compose's environment: would cover all call sites.
Forward the repox credentials to the container so uv sync in cmd.sh authenticates too (compose's :- default keeps them empty/unset when absent).:
# python-frontend/typeshed_serializer/docker/docker-compose.yml
services:
typeshed-serializer:
# ...
environment:
UV_INDEX_REPOX_USERNAME: ${ARTIFACTORY_USERNAME:-}
UV_INDEX_REPOX_PASSWORD: ${ARTIFACTORY_ACCESS_TOKEN:-}
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
What
The
Buildworkflow has been failing on all three matrix legs (sqc-eu,sqc-us,next) at theexec-maven-plugin:exec (serializer-runner)goal onpython-frontend, on every run since 2026-09-02T07:33. Example: https://github.com/SonarSource/sonar-python/actions/runs/33827965343/job/100884577646Root cause
Commit 9e20e9e ("SONARPY-4604 Moved from tox to uv") replaced the
tox/pip-driven install oftypeshed_serializer's dependencies withuv. The newpyproject.tomldeclares:uvauthenticates a named index viaUV_INDEX_<NAME>_USERNAME/UV_INDEX_<NAME>_PASSWORDenv vars. It does not readpip.confor any other pip-style config, unlike plainpip(whichtoxused, and which was presumably authenticated through machine-level config on the runner image). Since the migration, no credentials are wired up foruv's "repox" index, so every install of a package that isn't already warm in the local cache fails withHTTP status client error (401)againstsonarsource-pypi. Because it's whichever package is cold, the specific package name in the error differs run to run (first==2.0.2,mypy-extensions==1.1.0, ...) while the underlying cause is identical.Fix
config-maven(fromSonarSource/ci-github-actions) already exportsARTIFACTORY_USERNAME/ARTIFACTORY_ACCESS_TOKEN(Vault-issued Artifactory reader-role credentials) to the job environment for every step, including the Mavenexecgoal that shells out touv. This PR re-exposes those same credentials under the env var namesuvlooks for on therepoxindex, scoped to just theserializer-runnerexecution via theexec-maven-plugin's<environmentVariables>:No changes to the shared CI action or to secrets are needed - this only rewires credentials that are already present in the job.
This PR is for CI verification only
This repo appears to be a downstream mirror/export of
sonar-python-enterprise- please confirm whether the actual fix needs to be authored and merged there instead, with this PR closed once the workflow run confirms the fix works. Do not merge this PR as-is.Test plan
Buildworkflow (all 3 matrix legs) passes on this branch, specifically thatexec:3.6.3:exec (serializer-runner) @ python-frontendno longer 401ssonar-python-enterpriseand merge there