Repository navigation
feat(ENG-13680): add a NuGet credential provider - #494
Open
cloudsmith-iduffy wants to merge 1 commit into
Open
cloudsmith-iduffy wants to merge 1 commit into
cloudsmith-iduffy wants to merge 1 commit into
Conversation
`cloudsmith credential-helper install nuget` writes a `nuget-plugin-cloudsmith` launcher (`.bat` on Windows) on PATH. NuGet 6.13+ finds it and speaks the cross-platform plugin protocol to `cloudsmith credential-helper nuget`. The plugin answers for Cloudsmith hosts and the NuGet domains of the Workspace that is written into the launcher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Blocking credential operations can exceed NuGet protocol deadlines, and status detection can miss default installations.
3 open issues
What changed in this PR
Adds a NuGet credential provider that authenticates Cloudsmith feeds using the CLI’s existing credentials.
Changes:
- Implements the NuGet plugin protocol and feed matching.
- Adds installation, registration, and saved launcher settings.
- Adds tests and protects protocol output from debug messages.
| File | Description |
|---|---|
| cloudsmith_cli/credential_helpers/nuget/runtime.py | Implements plugin messages and authentication. |
| cloudsmith_cli/credential_helpers/nuget/installer.py | Manages NuGet launcher installation. |
| cloudsmith_cli/credential_helpers/nuget/__init__.py | Exports the runtime entry point. |
| cloudsmith_cli/credential_helpers/launchers.py | Supports saved settings and Windows batch launchers. |
| cloudsmith_cli/credential_helpers/common.py | Allows discovery using existing API configuration. |
| cloudsmith_cli/core/api/init.py | Sends authentication debug output to stderr. |
| cloudsmith_cli/cli/tests/test_credential_helper_nuget.py | Tests protocol, command, and installation behavior. |
| cloudsmith_cli/cli/tests/commands/test_credential_helper_install.py | Tests launcher settings and escaping. |
| cloudsmith_cli/cli/decorators.py | Exposes credential context for renewal. |
| cloudsmith_cli/cli/commands/credential_helper/nuget.py | Adds the NuGet command. |
| cloudsmith_cli/cli/commands/credential_helper/manage.py | Registers installation and captures settings. |
| cloudsmith_cli/cli/commands/credential_helper/__init__.py | Registers the NuGet subcommand. |
| CHANGELOG.md | Documents provider usage and requirements. |
Review effort: Balanced
| ) | ||
| @click.argument("nuget_args", nargs=-1, type=click.UNPROCESSED) | ||
| @common_api_auth_options | ||
| @initialise_api |
Comment on lines
+141
to
+143
| launcher_path = self._launcher_path(resolve_bin_dir()) | ||
| if not launcher_path.exists(): | ||
| return {"launcher": None, "hosts": []} |
| if method == "Close": | ||
| return False | ||
|
|
||
| response = self.handle_request(method, message.get("Payload")) |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
Adds a NuGet credential provider (ENG-13680). After a one-off install,
dotnet restore, MSBuild and Visual Studio authenticate to Cloudsmith feeds with the CLI's own credentials: an API key, a SAML session from the keyring, or OIDC. No token goes intonuget.config.Install.
credential-helper install nugetwrites anuget-plugin-cloudsmithlauncher next tocloudsmith, as a.baton Windows. NuGet 6.13 and later (.NET SDK 9.0.200+) finds anynuget-plugin-*executable on PATH, so no NuGet config changes.NuGet often runs the plugin from an IDE or a build agent that does not have your shell's environment. So the launcher keeps the
CLOUDSMITH_*settings that you gave at install time as a flag or an environment variable: the Workspace, profile, config and credentials files, API host, TLS verification, OIDC and keyring settings. These values win over the runtime environment (ENG-15016). Secrets and the proxy URL are never written, because the launcher is world-readable. On Windows, the installer refuses a value that a batch file cannot hold safely.Runtime.
credential-helper nugetspeaks NuGet's cross-platform plugin protocol. NuGet asks every plugin about every feed:httpsfeed on*.cloudsmith.io,*.cloudsmith.comor a NuGet domain of the Workspace → Basictoken:<credential>.NotFound, so NuGet tries its other credential sources.Error, with a message that says how to authenticate.--domain <host>adds hosts that always match.--no-discoverturns off the domain lookup, so only those hosts and the Cloudsmith hosts match. Stdout carries only protocol messages, also under--debug.Changes outside NuGet.
core/api/init.pywrites its--debugcredential messages to stderr. One of them now says "SAML" instead of "SSO".launcher_arg()checks the standalone binary path withbatch_value. This also applies to the docker, pnpm, cargo and terraform.cmdlaunchers.resolve_credentialskeeps itsCredentialContextonoptsfor the retry.is_cloudsmith_domainpassesconfigure_apithrough, so the domain lookup keeps the CLI's proxy and TLS settings.Type of Change
Additional Notes
This replaces #458, which has the earlier review history.
Testing. A temporary workflow ran a real
dotnet restore(SDK 10) on Linux, macOS and Windows, from both a pip install and the PyInstaller binary. It covered a standard feed, a custom domain found by the live lookup with--debugon, and--domain --no-discoverwith an unreachable API host. Each job checks that the restore fails with 401 without the plugin and succeeds with it. All 18 jobs passed: run 38967385354.I also ran
dotnet nuget pushanddotnet restorelocally against a private repo with only a SAML session. Both worked with no API key.Known limits.
credential-helper listcan say "not installed" after a default install. This affects every helper, and fix(ENG-15090): find default-installed launchers in credential-helper list #491 fixes it.NuGet's plugin timeouts are 30 seconds in
ProtocolConstants, not the 5 seconds in the Microsoft docs. Credentials resolve before the handshake, so the plugin needs no threads or progress messages.🤖 Generated with Claude Code