Skip to content

nuget-plugin-forge: NuGet authentication plugin written in Rust #164

Open

Description

@schmitch

Part of #44. Builds on the shared client crate (#162). Depends on #39's device-flow endpoints. One binary, nuget-plugin-forge, serves dotnet, nuget.exe, MSBuild and Visual Studio.

Rust works

  • PATH discovery. Since NuGet 6.13 (.NET SDK 9.0.200, Visual Studio 17.13), NuGet searches PATH for files named nuget-plugin-*. The prefix must be lowercase. On Linux and macOS the file must be executable; on Windows it must end in .exe or .bat. The implementation language doesn't matter (docs, spec).
  • Overrides. PATH is only searched when none of the NUGET_*PLUGIN_PATHS variables is set. CI can also point NUGET_PLUGIN_PATHS straight at the file.
  • Signing. Plugins don't need an Authenticode signature on Windows any more (6.12 and earlier required one).
  • Older clients. NuGet before 6.13 only loads plugins from ~/.nuget/plugins/netcore/<name>/<name>.dll (a .NET assembly) or netfx/<name>/<name>.exe. NuGet 6.13 is therefore the minimum supported version.
  • Startup time. The handshake times out after 5 seconds, and a native binary starts well within that.

Protocol (v2.0.0)

NuGet launches the plugin with -Plugin and exchanges UTF-8 JSON messages over stdin/stdout, one per line, each with a RequestId/Type/Method/Payload envelope. Without -Plugin, the binary prints usage instead of waiting for a handshake.

Messages

  • NuGet → plugin: Initialize, SetLogLevel, GetOperationClaims, SetCredentials, GetAuthenticationCredentials, MonitorNuGetProcessExit, Close.
  • Handshake: goes both ways.
  • Plugin → NuGet: Log. NuGet ignores log messages sent before SetLogLevel.
  • While a request runs longer than the 5-second request timeout, as the device flow does, the plugin sends Progress messages. It also honours cancellation.

GetOperationClaims

The plugin claims Authentication. NuGet caches claims per plugin path for 30 days, so sources are filtered in GetAuthenticationCredentials, not here.

GetAuthenticationCredentials

  • Forge URIs: for a URI on a Forge host the user signed in to or configured, return a username plus the token as the password, auth type basic. Forge accepts a token as the Basic password (Client login for every format: Nexus-style logins, UI-minted tokens, browser/OAuth login #39).
  • Other URIs: answer NotFound so other providers, such as Azure Artifacts, still get their turn.
  • IsRetry: the cached token was rejected. Drop it and authenticate again.
  • IsNonInteractive: never block. Return the cached or renewed token, or nothing.
  • Interactive, CanShowDialog=false: run the device flow and send the instructions as a Log message at a level that dotnet restore --interactive prints.
  • Interactive, CanShowDialog=true: this covers Visual Studio, MSBuild and every client from NuGet 7.0. The plugin may open the browser, but only if a display really is available.

Acceptance criteria

  • Protocol tests against recorded NuGet message transcripts, including progress, timeouts and cancellation.
  • e2e: dotnet restore --interactive against an authenticated Forge feed, with the device flow approved through the mock IdP harness.
  • A second, non-interactive dotnet restore reuses the cached token.
  • A non-interactive restore without a cached token fails fast with a message that names forge login or --interactive.
  • A restore that also uses nuget.org and a third-party authenticated feed is unaffected.
  • Smoke tests on Linux, macOS and Windows.
  • Docs on the NuGet "connect your client" page (Client login for every format: Nexus-style logins, UI-minted tokens, browser/OAuth login #39).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions