tinglesoftware/dependabot-azure-devops

Can't auth with PAT to private feed in azure devops

devgibsonsp opened this issue ยท 28 comments

Looking to use this for my pipelines. I can't seem to auth with a PAT. I am using the classic editor and it isn't clear at all how you are supposed to use this. Are the fields available in the classic editor accurate?

The fields in the classic editor should be the same as when using YAML. Is there a particular field that seems to not be working? Is there an error output you are getting?

Hi @mburumaxwell

We'd also like to use the extension as it's very useful, so first of all thanks for putting in work and making it available for everyone to use.

I first tried the extension with a dummy repo and it worked well out of the box. However in our real environment we have several private feeds and so far I wasn't able to get it running.

Access wise it should be all good, the build service has access. However I also tried using my own PAT and also using the DEPENDABOT_EXTRA_CREDENTIALS variable. However the result was always the same:

docker run --rm -i -e AZURE_HOSTNAME=dev.azure.com -e AZURE_ACCESS_TOKEN=*** -e AZURE_ORGANIZATION=My-Org -e AZURE_PROJECT=MyProject -e AZURE_REPOSITORY=repo-e DEPENDABOT_PACKAGE_MANAGER=nuget -e DEPENDABOT_DIRECTORY=/Backend -e DEPENDABOT_TARGET_BRANCH=main -e DEPENDABOT_VERSIONING_STRATEGY=auto -e DEPENDABOT_OPEN_PULL_REQUESTS_LIMIT=5 -e DEPENDABOT_EXTRA_CREDENTIALS='[{\"type\":\"nuget_feed\",\"token\":\"***\",\"url\":\"https://pkgs.dev.azure.com/MyOrg/_packaging/PackageCache/nuget/v3/index.json\"}]' tingle/dependabot-azure-devops:0.2
/vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:119:in `check_repo_response': The following source could not be reached as it requires authentication (and any provided details were invalid or lacked the required permissions): https://pkgs.dev.azure.com/MyOrg/_packaging/PackageCache/nuget/v3/index.json (Dependabot::PrivateSourceAuthenticationFailure)
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:44:in `build_url_for_details'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:38:in `block in find_dependency_urls'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:31:in `each'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:31:in `flat_map'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:31:in `find_dependency_urls'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/repository_finder.rb:22:in `dependency_urls'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/version_finder.rb:279:in `dependency_urls'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/version_finder.rb:197:in `v3_nuget_listings'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/version_finder.rb:108:in `available_v3_versions'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/version_finder.rb:53:in `versions'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker/version_finder.rb:33:in `latest_version_details'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker.rb:87:in `latest_version_details'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker.rb:15:in `latest_version'
        from /vendor/ruby/2.6.0/gems/dependabot-common-0.133.5/lib/dependabot/update_checkers/base.rb:224:in `numeric_version_up_to_date?'
        from /vendor/ruby/2.6.0/gems/dependabot-common-0.133.5/lib/dependabot/update_checkers/base.rb:182:in `version_up_to_date?'
        from /vendor/ruby/2.6.0/gems/dependabot-common-0.133.5/lib/dependabot/update_checkers/base.rb:30:in `up_to_date?'
        from /vendor/ruby/2.6.0/gems/dependabot-nuget-0.133.5/lib/dependabot/nuget/update_checker.rb:55:in `up_to_date?'
        from ./update-script.rb:210:in `block in <main>'
        from ./update-script.rb:195:in `each'
        from ./update-script.rb:195:in `<main>'
Using 'dev.azure.com' as hostname
Fetching nuget dependency files for MyOrg/MyProject/_git/MyRepo
Targeting 'main' branch under '/Backend' directory
Using 'auto' versioning strategy
Parsing dependencies information
Checking if AutoMapper 10.1.1 needs updating

I have no experience in ruby at all, but with a bit of guidance I might be able to provide more info or do some debugging. What I can see however is that the ExtraCredentials are used in Line 150, but it appears the error happens before, when the source is fetched (line 135) - at least as far as I can tell from the logs.

Maybe that's a problem?

Or do you see any other obvious mistake I've made that could cause this problem?

Thanks for your help.

Hi @huserben , Ruby is also a bit foreign to me. Line 135 you have indicated only creates the Source object which is used in line 151. The methods/functions defined above that are only invoked when needed (Ruby things....).

To better help with this, I recommend running the docker container locally with the EXCON_DEBUG=1 environment variable so that the request resulting in PrivateSourceAuthenticationFailure can be logged. All HTTP requests and responses will be logged as a result but the last one will be the one failing so we can tell. When you have this output, please share it.

Example command:

docker run --rm -t \
           -e GITHUB_ACCESS_TOKEN=<your-github-token-here> \
           -e AZURE_HOSTNAME=<your-hostname> \
           -e AZURE_ACCESS_TOKEN=<your-devops-token-here> \
           -e AZURE_ORGANIZATION=<your-organization-here> \
           -e AZURE_PROJECT=<your-project-here> \
           -e AZURE_REPOSITORY=<your-repository-here> \
           -e DEPENDABOT_PACKAGE_MANAGER=<your-package-manager-here> \
           -e DEPENDABOT_DIRECTORY=/ \
           -e DEPENDABOT_TARGET_BRANCH=<your-target-branch> \
           -e DEPENDABOT_VERSIONING_STRATEGY=<your-versioning-strategy> \
           -e DEPENDABOT_OPEN_PULL_REQUESTS_LIMIT=10 \
           -e DEPENDABOT_EXTRA_CREDENTIALS=<your-extra-credentials> \
           -e DEPENDABOT_ALLOW=<your-allowed-packages> \
           -e DEPENDABOT_IGNORE=<your-ignore-packages> \
           -e EXCON_DEBUG=1 \
           tingle/dependabot-azure-devops:0.2.0

You can copy the command generated for you in the pipeline then replace the redacted parts.

We have been seeing this issue recently but did not know how to solve it, until recently. It turns out that giving the PAT access to Packages Read permission during creation or update is not sufficient. You also need to ensure that the user who owns the PAT has access to the particular feed. This can be done via the Feed Settings -> Permissions page. My URL has the format: https://dev.azure.com/{organization}/{project}/_packaging?_a=settings&feed={feed-name}&view=permissions replace the values and open in the browser. Adding Contributor permission to the user group named [{project_name}]\Contributors worked for us. Maybe this can help you?

Thanks for the feedback, I'll try running it with the EXCON_DEBUG=1 variable later today. Quick question, where did you get that from? As I was looking for some more info on how to enable more logging yesterday as I already ran it locally to see if I can get more info from it but got stuck at what envrionment variables are there to test it...

Regarding the feeds, it should not be a problem, as it's setup already like this (both with the group and me individiually as contributor). What I noticed though is that this feed we're using is a "Organization Level" feed and not on project level. Now I don't know if that matters or not, just wanted to point it out.

What I was also thinking, we're using the azure nuget feedback just to have a "cache" for our packages, in case they are not available on nuget anymore for some reason. So if there is a way to ignore feeds completely that would work for us as well, as for the update we can just work against nuget.org. So if it's possible to have a custom nuget.config passed to the bot it could help as well.

I'll update you here with more logs later today when I try it out with the additional environment variable.

@mburumaxwell
I now ran it with the debug flag and saw this:

:host          => "pkgs.dev.azure.com"
:local_address => "172.17.0.2"
:local_port    => 48896
:path          => "/MyOrg/_packaging/PackageCache/nuget/v3/index.json"
:port          => 443
:reason_phrase => "Unauthorized"
:remote_ip     => "13.107.42.20"
:status        => 401
:status_line   => "HTTP/1.1 401 Unauthorized\r\n"

And above the following:

:host                => "pkgs.dev.azure.com"
  :hostname            => "pkgs.dev.azure.com"
  :idempotent          => true
  :instrumentor        => Excon::StandardInstrumentor
  :instrumentor_name   => "excon"
  :method              => :get
  :middlewares         => [
    Excon::Middleware::ResponseParser
    Excon::Middleware::Expects
    Excon::Middleware::Idempotent
    Excon::Middleware::Instrumentor
    Excon::Middleware::Mock
    Excon::Middleware::Decompress
    Excon::Middleware::RedirectFollower
  ]
  :mock                => false
  :nonblock            => true
  :omit_default_port   => true
  :path                => "/MyOrg/_packaging/PackageCache/nuget/v3/index.json"
  :persistent          => false
  :port                => 443
  :query               => nil
  :read_timeout        => 20
  :retries_remaining   => 4
  :retry_errors        => [
    Excon::Error::Timeout
    Excon::Error::Socket
    Excon::Error::HTTPStatus
  ]
  :retry_limit         => 4
  :scheme              => "https"
  :ssl_uri_schemes     => [
    "https"
  ]
  :ssl_verify_peer     => true
  :stubs               => :global
  :tcp_nodelay         => false
  :thread_safe_sockets => true
  :uri_parser          => URI
  :versions            => "excon/0.79.0 (x86_64-linux-gnu) ruby/2.6.6"
  :write_timeout       => 5
excon.response
  :body          => "{\"$id\":\"1\",\"innerException\":null,\"message\":\"TF400813: The user '' is not authorized to access this resource.\",\"typeName\":\"Microsoft.TeamFoundation.Framework.Server.UnauthorizedRequestException, Microsoft.TeamFoundation.Framework.Server\",\"typeKey\":\"UnauthorizedRequestException\",\"errorCode\":0,\"eventId\":3000}"
  :cookies       => [

Does this help? There are more logs, if you think it helps to see them I maybe could send it to you via email (so I don't have to redact too much).

I can't seem to get it to work with the private nuget feeds. I've set a PAT and also used the System.AccessToken that I've used when executing the update script via pipeline directly. I end up with the same error as above.

I also had the same problem as above, I am using an Azure Pipeline yaml with private Nugets hosted in Azure Artifacts. I think I have finally found a "hack/work-around" and where the bug exists.

Basically in dependabot-core there is an IF statement where it switches between Bearer and Basic auth depending if it finds a ":" character in the token string (this is for when you have username and password auth). Azure Artifacts uses a single token for the user and password and requires "Basic" authentication, but the IF statement forces it to use Bearer. https://github.com/dependabot/dependabot-core/blob/93088743bfbbea4bf1d3357510e5d55f612f2cac/nuget/lib/dependabot/nuget/update_checker/repository_finder.rb#L261

To attempt to get it to follow the "Basic" auth path you can add a ':' character after your PAT and this appears to have worked for me. Below is the exact snippet I have used (replace the with your own details remember to keep the trailing ':' after the PAT).

-e DEPENDABOT_EXTRA_CREDENTIALS='[{"type":"nuget_feed","token":"<pat_token>:","url":"https://pkgs.dev.azure.com/..<full_uri>../nuget/v3/index.json"}]' \

Remember to check the user you have the PAT token has the necessary access to the feed as mentioned in the docs (I tested this by using a "full" access token temporarily and a Postman request to the package feed index.json uri).

Ill let the devs of this to work out how to resolve the bug / raise the issue with the Dependabot devs. Hope this helps someone!

@themightyjohn
Wow awesome, I've just tried it and it works. Thanks for figuring this out and sharing it!

Should this be put somewhere in the docs/readme/Task description or are we assuming it will soon be fixed by the Dependabot devs?

Iv added an issue to the dependabot-core github issue tracker. I'm not sure this will be fixed any time soon, so may be worth mentioning in the docs somewhere. Glad the work-around helped! #https://github.com/dependabot/dependabot-core/issues/3555

@themightyjohn
Thanks. I've got to add, I see the same problem not only with nuget feeds, but also with our npm feed that we host on Azure Artifacts. So I guess it's not a nuget problem and more a "Azure Artifact" problem? Shall I add this to your issue you created at dependabot/core?

PS: The link you've posted seems broken, at least clicking it resulted in an error for me, this should work:
Issue 3555

In the case this helps someone else, I had issues with the above option of using PAT token with the colon suffix still returning a 401. After going through the code at
https://github.com/dependabot/dependabot-core/blob/c3c87bb90042cf5b3d3af50d42b0e83fe3267041/nuget/lib/dependabot/nuget/update_checker/repository_finder.rb#L267

I was able to successfully authenticate to my Azure Artifacts feed by passing a base64 encoded version of my PAT with a colon prefix ":<PAT>" as the token in DEPENDABOT_EXTRA_CREDENTIALS for my custom package feed

I'll share what we do for reference purposes. This is a portion of the value stored in DEPENDABOT_EXTRA_CREDENTIALS. Hopefully, in due time, we can migrate to using the new registries node in the dependabot.yml file.

For NuGet:
[{"type":"nuget_feed","url":"https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/nuget/v3/index.json","token":":<raw-pat-value>"}]

For Maven/Gradle:
[{"type":"maven_repository","url":"https://pkgs.dev.azure.com/{organization}/_packaging/<feed>/maven/v1","username":"<organization>","password":"<raw-pat-value>"}]

For NPM (old URL):
[{"type":"npm_registry","registry":"<organization>.pkgs.visualstudio.com/_packaging/<feed>/npm/registry/","token":"<feed>:<raw-pat-value>"}]

For NPM (new url):
[{"type":"npm_registry","registry":"pkgs.dev.azure.com/<organization>/_packaging/<feed>/npm/registry/","token":"<feed>:<raw-pat-value>"}]

All combined:

[{"type":"nuget_feed","url":"https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/nuget/v3/index.json","token":":<raw-pat-value>"},{"type":"maven_repository","url":"https://pkgs.dev.azure.com/{organization}/_packaging/<feed>/maven/v1","username":"<organization>","password":"<raw-pat-value>"},{"type":"npm_registry","registry":"<organization>.pkgs.visualstudio.com/_packaging/<feed>/npm/registry/","token":"<feed>:<raw-pat-value>"},{"type":"npm_registry","registry":"pkgs.dev.azure.com/<organization>/_packaging/<feed>/npm/registry/","token":"<feed>:<raw-pat-value>"}]

Formatted (for readability purposes):

[
    {
        "type": "nuget_feed",
        "url": "https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/nuget/v3/index.json",
        "token": ":<raw-pat-value>"
    },
    {
        "type": "maven_repository",
        "url": "https://pkgs.dev.azure.com/{organization}/_packaging/<feed>/maven/v1",
        "username": "<organization>",
        "password": "<raw-pat-value>"
    },
    {
        "type": "npm_registry",
        "registry": "<organization>.pkgs.visualstudio.com/_packaging/<feed>/npm/registry/",
        "token": "<feed>:<raw-pat-value>"
    },
    {
        "type": "npm_registry",
        "registry": "pkgs.dev.azure.com/<organization>/_packaging/<feed>/npm/registry/",
        "token": "<feed>:<raw-pat-value>"
    }
]

I have some issue with the above mentioned walkaround and ended up this error in the PR submission request, any ideas?

image

Update:

After debugging the payload, it turns out the noreply@github.com is used in the update script for PR submission where my organization has policy that disallow any non-company emails in the git commit, with a custom fork of this repo, I am able to change it to our needs with more customization. Thank you for the AWESOME script, it is very useful for me to quickly understand the ruby so that I can put it to use.

Bertk commented

Hi @mburumaxwell,

thank you for this great Azure DevOps extension. I was waiting a long time for dependabot support with Azure DevOps pipelines.

I used already this azure-dependabot solution in the past and migrated now to the Azure DevOps dependabot extension.

I discovered one scenario which fails and here we are using a npm registry from another Azure DevOps organization.

warning: parser/current is loading parser/ruby26, which recognizes
warning: 2.6.7-compliant syntax, but you are running 2.6.6.
warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
/home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb:332:in `check_npm_response': The following source could not be reached as it requires authentication (and any provided details were invalid or lacked the required permissions): pkgs.dev.azure.com/XXXXXXXX/_packaging/XXXXXXXXX/npm/registry (Dependabot::PrivateSourceAuthenticationFailure)
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb:287:in `npm_details'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb:104:in `valid_npm_details?'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb:35:in `latest_version_from_registry'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker.rb:180:in `latest_released_version'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker.rb:205:in `latest_version_details'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-npm_and_yarn-0.149.5/lib/dependabot/npm_and_yarn/update_checker.rb:23:in `latest_version'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-common-0.149.5/lib/dependabot/update_checkers/base.rb:280:in `can_compare_requirements?'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-common-0.149.5/lib/dependabot/update_checkers/base.rb:270:in `requirements_up_to_date?'
	from /home/dependabot/dependabot-script/vendor/ruby/2.6.0/gems/dependabot-common-0.149.5/lib/dependabot/update_checkers/base.rb:35:in `up_to_date?'
	from ./update-script.rb:294:in `block in <main>'
	from ./update-script.rb:272:in `each'
	from ./update-script.rb:272:in `<main>'
GitHub access token has been provided.
Using hostname = 'dev.azure.com', protocol = 'https', port = '443'.

I was using the npmAuthenticate@0 task with customEndpoint in old solution which enabled access to the other organization private feed.

How does this task work?
This task searches the specified .npmrc file for registry entries, then appends authentication details for the discovered registries to the end of the file. For all registries in the current organization/collection, the build's credentials are used. For registries in a different organization or hosted by a third-party, the registry URIs will be compared to the URIs of the npm service connections specified by the customEndpoint input, and the corresponding credentials will be used. The .npmrc file will be reverted to its original state at the end of the pipeline execution.

Do you know a workaround?

@Bertk The authentication process to a private feed in dependabot is not scoped to the current repository. You can use GitHub packages feed in Azure DevOps repository. For cross organization feeds, ensure you use the PAT for that organization in the extra credentials which is different from the one use for the repository where dependabot would be checking for updates. Then ensure permissions are granted correctly to the users in each organization.

Note that project-scoped feeds may need to be handled differently.

It's been a few months since this issue was first reported and a number of workarounds have been posted. I have tried them all: :<PAT> <PAT:> :<B64ENCODEDPAT> <B64ENCODEDPAT>

I still received the (Dependabot::PrivateSourceAuthenticationFailure) error.

Are there any other workarounds?

si618 commented

@hokiepokedad2 I'm in the same boat; turned on EXCON_DEBUG=1 and confirmed basic auth was being sent, assuming it relates to this setting in the header:

"WWW-Authenticate" => "Basic realm="https://pkgsprodeus21.pkgs.visualstudio.com/"

Tried as many combinations as I could think of: prefix, suffix, both! even embedding : into a base64 encoded PAT with full access and still no dice, always with the 401.

I'm sure there's some secret sauce I'm missing, but it's frustrating as public feeds are working fine on the same pipeline in a different task.

Edit: Ended up moving to renovatebot using this extension.

I have a similar problem for Composer. We have a private registry which authenticates with a ssh key of the user.

is there a way to push this key to the container since right now it cant authenticate

For those, looking for a complete example for python/pip:

[
  {
    "type": "python_index",
    "index-url": "https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/pypi/simple/",
    "token": "<feed>:$(System.AccessToken)"
  }
]

I also had the same problem as above, I am using an Azure Pipeline yaml with private Nugets hosted in Azure Artifacts. I think I have finally found a "hack/work-around" and where the bug exists.

Basically in dependabot-core there is an IF statement where it switches between Bearer and Basic auth depending if it finds a ":" character in the token string (this is for when you have username and password auth). Azure Artifacts uses a single token for the user and password and requires "Basic" authentication, but the IF statement forces it to use Bearer. https://github.com/dependabot/dependabot-core/blob/93088743bfbbea4bf1d3357510e5d55f612f2cac/nuget/lib/dependabot/nuget/update_checker/repository_finder.rb#L261

To attempt to get it to follow the "Basic" auth path you can add a ':' character after your PAT and this appears to have worked for me. Below is the exact snippet I have used (replace the with your own details remember to keep the trailing ':' after the PAT).

-e DEPENDABOT_EXTRA_CREDENTIALS='[{"type":"nuget_feed","token":"<pat_token>:","url":"https://pkgs.dev.azure.com/..<full_uri>../nuget/v3/index.json"}]' \

Remember to check the user you have the PAT token has the necessary access to the feed as mentioned in the docs (I tested this by using a "full" access token temporarily and a Postman request to the package feed index.json uri).

Ill let the devs of this to work out how to resolve the bug / raise the issue with the Dependabot devs. Hope this helps someone!

You are awesome! This worked after hours of trying to fix the issue!

Anybody here had any success authenticating against private terraform registries hosted on terraform cloud. @mburumaxwell do you happen to have the syntax for that ?

Here is a way to use azure DevOps private feeds. Make sure that Project Collection Build Service Accounts group has contributor access on the feed.

trigger: none # Disable CI trigger
schedules:
  - cron: '0 7 * * 1' # on Mondays at 7am UTC
    always: true # run even when there are no code changes
    branches:
      include:
        - 'main'
    batch: true
    displayName: 'on Mondays'

variables:
  - name: Repository
    value: ${{ replace(variables['Build.DefinitionName'],'Dependabot - ','') }} 
    # Important: Pipeline name must be "Dependabot - repository_name".

stages:
  - stage: CheckDependencies
    displayName: 'Check Dependencies'
    jobs:
      - job: Dependabot
        displayName: 'Dependabot'
        pool:
          # Only works with MacOS and Linux
          vmImage: 'ubuntu-latest' 
        steps:
          - checkout: git://projec_name/${{ variables.Repository }}

          # Creates $(VSS_NUGET_ACCESSTOKEN) for Private feeds
          - task: NuGetAuthenticate@1
            displayName: 'NuGet Private Feed Authentication'

          - task: dependabot@1
            displayName: 'Run Dependabot'
            inputs:
              useConfigFile: $(Dependabot.UseConfigFile)
              packageManager: 'nuget'
              directory: '$(Dependabot.Directory)'
              openPullRequestsLimit: '$(Dependabot.OpenPullRequestsLimit)'
              milestone: $(Dependabot.Milestone)
              setAutoComplete: true
              mergeStrategy: '1'
              gitHubAccessToken: '$(Dependabot.GitHubAccessToken)'
              azureDevOpsAccessToken: '$(System.AccessToken)'
              targetRepositoryName: '${{ variables.Repository }}'
              extraEnvironmentVariables: DEPENDABOT_EXTRA_CREDENTIALS=[{"type":"nuget_feed","token":"$(VSS_NUGET_ACCESSTOKEN)","url":"https://pkgs.dev.azure.com/....../nuget/v3/index.json"}]

To prevent rate limit you need gitHubAccessToken. You can also use service connection instead.
Also, add $(Dependabot.var) variables to the pipeline from devops level for additional flexibility.

I've tried following what @jakubtrebacz-dev posted and keep getting a JSON parser error from ruby.

YAML steps:

steps:
  - task: NuGetAuthenticate@1
    displayName: 'NuGet Authenticate'
  
  - task: dependabot@1
    inputs:
      packageManager: 'nuget'
      setAutoComplete: false
      autoApprove: false
      extraEnvironmentVariables: DEPENDABOT_EXTRA_CREDENTIALS=[{"type":"nuget_feed","url":"REDACTED","token":""$(VSS_NUGET_ACCESSTOKEN)""}]

Screenshot of environment variable being passed in:
image

JSON error:

/usr/lib/ruby/2.7.0/json/common.rb:156:in `parse': 434: unexpected token at '{"type":"nuget_feed","url":"REDACTED","token":"***"}]' (JSON::ParserError)
	from /usr/lib/ruby/2.7.0/json/common.rb:156:in `parse'
	from ./update-script.rb:115:in `<main>'
##[error]The process '/usr/bin/docker' failed with exit code 1

It seems the like the [ at the start of the string is being removed but I'm not sure why.
Can anyone advise?

That is used to escape the quotes since pipelines strips them when inserting the variable for some reason. The final string being passed in (see screenshot) is formatted correctly AFAICT.

That is used to escape the quotes since pipelines strips them when inserting the variable for some reason. The final string being passed in (see screenshot) is formatted correctly AFAICT. ~ @rgrace-puck

I managed to replicate your error, and whiskeysierra had a good point.
This error happens when you add the escape for double quotes.
I believe that double quotes "disappear" within *** the secret value, they are still there but they are hidden.

If you worried about text "leaking out" you can put single quotes around the whole yaml value:

extraEnvironmentVariables: 'DEPENDABOT_EXTRA_CREDENTIALS=[{"type":"nuget_feed","url":"REDACTED","token":"$(VSS_NUGET_ACCESSTOKEN)"}]'

I always but ' around any string value in yaml pipelines.

Ah yes, that was it!
I wish that behavior of the "hidden" quotes was more obvious.

Thank you both.

This extension now supports the registries node in the dependabot.yml file which makes work much easier. Configuring DEPENDABOT_EXTRA_CREDENTIALS is no longer necessary or recommended. Should authentication with private feed fail, the task will also fail.

The required permissions are documented by Microsoft depending on the setup and are beyond the scope of this task/repository.

I will now mark this issue as resolved and close it but if there's something specific not working, open a new issue.