Skip to content

feat(ENG-13680): add a NuGet credential provider - #458

Closed
cloudsmith-iduffy with Copilot wants to merge 1 commit into
iduffy/shared-credential-helper-codefrom
copilot/create-nuget-credential-provider
Closed

cloudsmith-iduffy with Copilot wants to merge 1 commit into
iduffy/shared-credential-helper-codefrom
copilot/create-nuget-credential-provider

Conversation

Copilot AI commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

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 into nuget.config.

$ cloudsmith credential-helper install nuget --workspace acme
$ dotnet restore

Install. credential-helper install nuget writes a nuget-plugin-cloudsmith launcher next to cloudsmith, as a .bat on Windows. NuGet 6.13 and later (.NET SDK 9.0.200+) finds any nuget-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 nuget speaks NuGet's cross-platform plugin protocol. NuGet asks every plugin about every feed:

  • An https feed on *.cloudsmith.io, *.cloudsmith.com or a NuGet domain of the Workspace → Basic token:<credential>.
  • Any other feed, or a failed domain lookup → NotFound, so NuGet tries its other credential sources.
  • A Cloudsmith feed with no credential → Error, with a message that says how to authenticate.
  • A retry after a 401 resolves the credential again, so a renewed SAML or OIDC token is used.

--domain <host> adds hosts that always match. --no-discover turns 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.py writes its --debug credential messages to stderr. One of them now says "SAML" instead of "SSO".
  • On Windows, launcher_arg() checks the standalone binary path with batch_value. This also applies to the docker, pnpm, cargo and terraform .cmd launchers.
  • resolve_credentials keeps its CredentialContext on opts for the retry. is_cloudsmith_domain passes configure_api through, so the domain lookup keeps the CLI's proxy and TLS settings.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Other (please describe)

Additional Notes

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 --debug on, and --domain --no-discover with 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 push and dotnet restore locally against a private repo with only a SAML session. Both worked with no API key.

Known limits.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Plaintext credential exposure, protocol deadline failures, and lost credential configuration remain unresolved.

Review effort: Balanced
Findings: 2 High severity · 4 Medium severity

Open (6)
What changed in this PR

Adds a NuGet credential provider that reuses CLI credentials without storing tokens in nuget.config.

Changes:

  • Implements plugin authentication and Cloudsmith feed matching.
  • Adds launcher installation, status, and removal.
  • Adds unit/live tests, CI setup, and documentation.
File Description
cloudsmith_cli/​credential_helpers/​nuget/​runtime.py Implements protocol and credential responses.
cloudsmith_cli/​credential_helpers/​nuget/​installer.py Manages launchers and trusted domains.
cloudsmith_cli/​credential_helpers/​nuget/​__init__.py Exports runtime entry point.
cloudsmith_cli/​credential_helpers/​launchers.py Supports configurable Windows extensions.
cloudsmith_cli/​cli/​tests/​test_credential_helper_nuget.py Tests runtime, command, and installer.
cloudsmith_cli/​cli/​tests/​commands/​test_credential_helper_nuget_integration.py Adds live restore and custom-domain checks.
cloudsmith_cli/​cli/​commands/​credential_helper/​nuget.py Connects CLI credentials to the protocol.
cloudsmith_cli/​cli/​commands/​credential_helper/​manage.py Registers NuGet installation management.
cloudsmith_cli/​cli/​commands/​credential_helper/​__init__.py Registers the NuGet command.
CHANGELOG.md Documents the new provider.
.github/​workflows/​test.yml Configures .NET for integration tests.
.env.example Documents optional NuGet test settings.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cloudsmith_cli/cli/commands/credential_helper/nuget.py Outdated
Comment thread cloudsmith_cli/credential_helpers/nuget/runtime.py Outdated
Comment thread cloudsmith_cli/credential_helpers/nuget/installer.py Outdated
Comment thread cloudsmith_cli/credential_helpers/nuget/installer.py Outdated
Comment thread cloudsmith_cli/credential_helpers/nuget/runtime.py
Comment thread cloudsmith_cli/credential_helpers/nuget/runtime.py
@cloudsmith-iduffy

Copy link
Copy Markdown
Collaborator

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply the suggestion exactly.

Do not make changes beyond what is described in the linked review thread.

Copilot AI commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested chang...

Addressed all six review threads in e398c8f.

@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch 2 times, most recently from c33f5a9 to c74e690 Compare October 4, 2026 21:51
@cloudsmith-iduffy
cloudsmith-iduffy requested a balanced review from Copilot October 4, 2026 21:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread cloudsmith_cli/credential_helpers/nuget/installer.py
Comment thread cloudsmith_cli/credential_helpers/nuget/runtime.py Outdated
Comment thread cloudsmith_cli/cli/tests/commands/test_credential_helper_nuget_integration.py Outdated
UsmanGhias

This comment was marked as spam.

@cloudsmith-iduffy
cloudsmith-iduffy changed the base branch from master to iduffy/v2-workspace-domains October 16, 2026 17:34
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch 6 times, most recently from 1b2f276 to 6a89ccf Compare October 16, 2026 17:59
@cloudsmith-iduffy cloudsmith-iduffy changed the title Add NuGet credential provider (credential-helper nuget) feat(ENG-13680): add a NuGet credential provider Oct 16, 2026
@cloudsmith-iduffy
cloudsmith-iduffy marked this pull request as ready for review October 16, 2026 18:13
@cloudsmith-iduffy
cloudsmith-iduffy requested a review from a team as a code owner October 16, 2026 18:13
@cloudsmith-iduffy
cloudsmith-iduffy marked this pull request as draft October 16, 2026 18:18
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the iduffy/v2-workspace-domains branch from d948a88 to 49dfad5 Compare October 16, 2026 19:06
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch 2 times, most recently from c86b2bc to e0477da Compare October 16, 2026 19:14
@cloudsmith-iduffy
cloudsmith-iduffy requested a balanced review from Copilot October 16, 2026 19:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Schemeless proxy credentials can leak into launchers, and a remaining debug diagnostic can corrupt the protocol stream.

2 open findings
3 resolved since last review

🧠 Review effort: Balanced

Comment thread cloudsmith_cli/credential_helpers/nuget/installer.py Outdated
Comment thread cloudsmith_cli/core/api/init.py
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch 3 times, most recently from 96771cd to 6649497 Compare October 16, 2026 19:40
@cloudsmith-iduffy
cloudsmith-iduffy requested a balanced review from Copilot October 16, 2026 19:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Authentication routing and cross-platform launchers warrant human review, with an unresolved TLS-setting precedence issue.

2 open findings
1 resolved since last review

🧠 Review effort: Balanced

Comment thread cloudsmith_cli/cli/commands/credential_helper/manage.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Security-sensitive credential handling and launcher configuration precedence warrant final human verification before approval.

2 open findings

🧠 Review effort: Balanced

@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch 5 times, most recently from 342d3b5 to 31f8df3 Compare October 16, 2026 21:09
`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>
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the copilot/create-nuget-credential-provider branch from 31f8df3 to 091ed1c Compare October 16, 2026 21:23
@cloudsmith-iduffy
cloudsmith-iduffy changed the base branch from iduffy/v2-workspace-domains to iduffy/shared-credential-helper-code October 16, 2026 21:23
@cloudsmith-iduffy
cloudsmith-iduffy marked this pull request as ready for review October 16, 2026 21:23
@cloudsmith-iduffy
cloudsmith-iduffy added this pull request to stack #493 October 16, 2026 21:23
@cloudsmith-iduffy
cloudsmith-iduffy removed this pull request from stack #493 October 16, 2026 21:36
@cloudsmith-iduffy

Copy link
Copy Markdown
Collaborator

Reopened as #494 so that I am the author. The code is the same commit (091ed1c). The review history stays here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants