Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use dotnet credential provider #8927

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion nuget/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ RUN cd /tmp \
&& chmod +x dotnet-install.sh \
&& mkdir -p "${DOTNET_INSTALL_DIR}" \
&& ./dotnet-install.sh --version "${DOTNET_SDK_VERSION}" --install-dir "${DOTNET_INSTALL_DIR}" \
&& rm dotnet-install.sh
&& rm dotnet-install.sh \
&& sh -c "$(curl -fsSL https://aka.ms/install-artifacts-credprovider.sh)"

ENV PATH="${PATH}:${DOTNET_INSTALL_DIR}"
RUN dotnet --list-runtimes
Expand Down
6 changes: 5 additions & 1 deletion nuget/lib/dependabot/nuget/native_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,14 @@ def self.run_nuget_updater_tool(repo_root:, proj_path:, dependency:, is_transiti
(command, fingerprint) = get_nuget_updater_tool_command(repo_root: repo_root, proj_path: proj_path,
dependency: dependency, is_transitive: is_transitive)

env = NuGetConfigCredentialHelpers.get_credentials_to_credential_helper_env(credentials)

puts "running NuGet updater:\n" + command

NuGetConfigCredentialHelpers.patch_nuget_config_for_action(credentials) do
output = SharedHelpers.run_shell_command(command, allow_unsafe_shell_command: true, fingerprint: fingerprint)
output = SharedHelpers.run_shell_command(command,
allow_unsafe_shell_command: true, fingerprint: fingerprint,
env: env)
puts output
end
end
Expand Down
32 changes: 32 additions & 0 deletions nuget/lib/dependabot/nuget/nuget_config_credential_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
module Dependabot
module Nuget
module NuGetConfigCredentialHelpers
extend T::Sig

def self.user_nuget_config_path
home_directory = Dir.home
File.join(home_directory, ".nuget", "NuGet", "NuGet.Config")
Expand Down Expand Up @@ -48,6 +50,36 @@ def self.add_credentials_to_nuget_config(credentials)
File.write(user_nuget_config_path, nuget_config)
end

sig { params(credentials: T::Array[Dependabot::Credential]).returns(T::Hash[String, String]) }
def self.get_credentials_to_credential_helper_env(credentials)
env = {}

nuget_credentials = credentials.select { |cred| cred["type"] == "nuget_feed" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature only works with NuGet feeds from Azure DevOps, right? If that's the case it would be a good idea to filter credentials to only those feeds so you don't accidentally expose feeds/tokens that aren't ADO to the ADO service.

If I recall, all Azure DevOps NuGet feeds look like https://pkgs.dev.azure.com/... or https://SOME-ORGANIZATION.pkgs.visualstudio.com/....


if nuget_credentials.any?
endpoint_credentials = []

nuget_credentials.each do |c|
next unless c["token"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Azure DevOps feeds aren't necessarily private and authentication isn't always specified via a token field, it could also come in via username/password, so that'll have to be accounted for.


exploded_token = T.must(c["token"]).split(":", 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to the above comment, this shouldn't assume a token will be of the form abc:123; it should be able to handle a token without a colon and/or it should handle separate username/password fields.


next unless exploded_token.length == 2

username = exploded_token[0]
password = exploded_token[1]

endpoint_credentials << <<~NUGET_ENDPOINT_CREDENTIAL
{"endpoint":"#{c['url']}", "username":"#{username}", "password":"#{password}"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and a few lines below, use the .to_json method so we don't have to worry about any escaping. I'm not 100% certain on the syntax, but it's something like this:

endpoint_credentials << {
  "endpoint" => c['url'],
  "username" => username,
  "password" => password,
}

Then later on:

env["VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"] = {
 "endpointCredentials" => endpoint_credentials
}.to_json

NUGET_ENDPOINT_CREDENTIAL
end

env["VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"] = "{\"endpointCredentials\": [#{endpoint_credentials.join(',')}]}"
end

env
end

def self.restore_user_nuget_config
return unless File.exist?(temporary_nuget_config_path)

Expand Down
Loading