skip to Main Content

I am trying to use the Azure pipeline to publish a Python package to Artifact’s feed.
I could do it from my local machine and upload the package using Twine, but I have an authentication issue in the pipeline.

trigger:
- main

pool:
  vmImage: ubuntu-22.04
variables:
  pip_cache_dir: '$(Pipeline.Workspace)/.pip_cache'

steps:
- task: UsePythonVersion@0
  inputs:
    versionSpec: '3.10'
    addToPath: true

- bash: |
    python -m venv worker_venv
    source worker_venv/bin/activate
    pip install --upgrade pip
    pip install pipenv
    pipenv requirements > requirements.txt
    pipenv requirements --dev > requirements-dev.txt
    pip install --cache-dir $(pip_cache_dir) -r ./requirements.txt
    pip install --target="./.python_packages/lib/site-packages" --cache-dir $(pip_cache_dir) -r ./requirements.txt
  displayName: 'Install tools'

- script: |
    source worker_venv/bin/activate
    python setup.py sdist bdist_wheel
  displayName: 'Build package'

- task: TwineAuthenticate@1
  inputs:
    artifactFeed: sample-feed-01

- script: |
    source worker_venv/bin/activate
    python -m twine upload --verbose --config-file $(PYPIRC_PATH) --repository-url https://pkgs.dev.azure.com/**company**/Platform/_packaging/sample-feed-01/pypi/upload/ dist/*
  env:
    TWINE_USERNAME: "azure"
    TWINE_PASSWORD: $(PYPI_TOKEN)
  displayName: 'Upload package to Azure Artifacts'

I tried everything, including GPT-4, but the solutions seem wrong or outdated.
this is the error:

/usr/bin/bash --noprofile --norc /home/vsts/work/_temp/75d0c60b-0c2a-44e9-be0f-29d838a3b86e.sh
Uploading distributions to 
https://pkgs.dev.azure.com/**company**/Platform/_packaging/sample-feed-01/pypi/up
load/
INFO     dist/**package**.whl (2.6 KB)                 
INFO     dist/**package**.tar.gz (2.6 KB)                           
INFO     username set by command options                                        
INFO     password set by command options                                        
INFO     username: azure                                                        
INFO     password: <hidden>                                                     
Uploading **package**.whl
25l
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/5.7 kB • --:-- • ?
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.7/5.7 kB • 00:00 • ?
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.7/5.7 kB • 00:00 • ?
25hINFO     Response from                                                          
         https://pkgs.dev.azure.com/**company**/Platform/_packaging/sample-feed-0
         1/pypi/upload/:                                                        
         401 Unauthorized                                                       
INFO     {"$id":"1","innerException":null,"message":"TF400813: The user        
         'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' is not authorized to access this
         resource.","typeName":"Microsoft.TeamFoundation.Framework.Server.Unauth
         orizedRequestException,                                                
         Microsoft.TeamFoundation.Framework.Server","typeKey":"UnauthorizedReque
         stException","errorCode":0,"eventId":3000}                             
ERROR    HTTPError: 401 Unauthorized from                                       
         https://pkgs.dev.azure.com/**company**/Platform/_packaging/sample-feed-0
         1/pypi/upload/                                                         
         Unauthorized                                       

I have some doubts about 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' as user name, which I did not obfuscate, and that is what I see in the pipeline.
any help would be appreciated

2

Answers


  1. You can use the publishArtifact job from Azure: https://learn.microsoft.com/nl-nl/azure/devops/pipelines/tasks/reference/publish-build-artifacts-v1?view=azure-pipelines.

    We do this with Poetry. Therefore you need Azure’s TwineAuthenticate step: https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/twine-authenticate-v1?view=azure-pipelines. It will look something like this:

    jobs:
    - job: publishArtifact
      displayName: 'Publish package to Artifacts feed'
    
      steps:
      - task: UsePythonVersion@0
        displayName: 'Determine Python version'
        inputs:
          versionSpec: <python version>
          architecture: 'x64'
    
      steps:
      - task: TwineAuthenticate@1
        displayName: "Twine Authenticate to artifact feed"
        inputs:
          artifactFeed: <feed>
    
      - script: |
          python3 -m pip install poetry==1.5.1
          python -m pip install twine
          poetry build
          python -m twine upload -r <feed>
        displayName: 'Build and publish package with Poetry'
    
    
    Login or Signup to reply.
  2. Go the Azure Artifacts feed you want to publish the Python package to, then navigate to Feed Settings > Permissions page to check and ensure the following identities have been assigned with Contributor role at least.

    • Project Collection Build Service ({OrgName})
    • {ProjectName} Build Service ({OrgName})

    enter image description here

    For more details, see "Job access tokens".


    After configuring the permission role, in the pipeline, you can build and publish the Python package like as below.

    steps:
    - Some steps to install dependences and build the package.
    
    - task: TwineAuthenticate@1
      displayName: 'Twine Authenticate '
      inputs:
        artifactFeed: {feed_name}
    
    - bash: 'twine upload -r {feed_name} --config-file "$(PYPIRC_PATH)" dist/*.whl'
      displayName: 'Publish to Artifacts feed'
    

    With this way, you do not need to provide your PAT/password to authenticate.

    For more details, see "Publish Python packages with Azure Pipelines".


    EDIT:

    By default, the pipeline will use one of the following build identities (also as mentioned above) to access the Azure Artifacts feeds and other resources within current organization:

    • Project Collection Build Service ({OrgName}): Can access resources with full/partial permissions across projects within current organization by default.

    • {ProjectName} Build Service ({OrgName}): Can access resources with full/partial permissions only within the current project by default.

    On the Organization Settings (and Project Settings), there are two options:

    • Limit job authorization scope to current project for non-release pipelines
    • Limit job authorization scope to current project for release pipelines

    enter image description here

    If the options are enabled, the pipelines use the identity "{ProjectName} Build Service ({OrgName})". If the options are disabled, the identity "Project Collection Build Service ({OrgName})" is used.

    The TwineAuthenticate@1 task will use one of above build identities to generate the twine credentials and set the credentials to the environment variable PYPIRC_PATH.

    Since the identities might not have the full access to the feed by default, to assign the required permission role to the identities, you need to click the "Add users/groups" button, then on the pop-up window, search for and add the identities with the required roles.

    enter image description here


    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search