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

.NET 8: Enable private NuGet dependencies for alternative licensing #26286

Open
richlander opened this issue Jun 27, 2022 · 20 comments
Open

.NET 8: Enable private NuGet dependencies for alternative licensing #26286

richlander opened this issue Jun 27, 2022 · 20 comments
Assignees
Labels
Area-NetSDK untriaged Request triage from a team member

Comments

@richlander
Copy link
Member

The ImageSharp project is considering a new licensing scheme. The license language discusses a bunch about the nature of dependencies. It seems like private NuGet dependencies (for implementation-only dependencies (no API exposure) could be an important tool for enabling projects to establish alternate licensing approaches. At present, that's difficult.

It would be good to validate the assumption that private NuGet dependencies would help. It seems like they would.

After that, it would be good to consider this feature for .NET 8. It has other benefits as well. It is a subset of the functionality proposed in: dotnet/designs#242.

@clairernovotny @mhutch @JimBobSquarePants

@Sergio0694
Copy link
Contributor

This looks very promising! I wonder if it's essentially the same as NuGet/Home#10375, or whether it at least overlaps with that? We've wanted something like this for years in the Windows Community Toolkit, and I could use this on my own as well 😄

@richlander
Copy link
Member Author

Yes, same (or same enough). Let's leave them both open for a bit. We can close this one once the team goes through planning. Mine is pushing (quite obviously) on one specific scenario to help motivate the experience.

@KalleOlaviNiemitalo
Copy link
Contributor

I wonder whether specifying the version of such a package by central package versioning would be considered a direct dependency for the purposes of the license.

@richlander
Copy link
Member Author

I would say "no" or "it depends". Also, all my opinion:

  • Fair use: changing the version of a private dependency via CPVM to bump to a secure version.
  • Fair use: changing the version of multiple private dependencies via CPVM to ensure a common version.
  • Not: changing the version of direct dependency and a private dependencies via CPVM to ensure a common version.

The last one is a red herring. The private dependency and CPVM are inconsequential.

You shouldn't adopt software that doesn't allow you to bump versions via CPVM. CPVM is a great security tool.

There's a separate question on how private dependencies should work with CPVM in the general case. That's a separate topic.

@JimBobSquarePants
Copy link

In my proposed license change I'm not treating a direct dependency as "You call this API", rather, "You explicitly installed the package or included the source" it so I'm not sure of the relevance here. However I see the relevance in more traditional direct vs transitive dependency definition.

@richlander
Copy link
Member Author

I think we're talking about the same thing, @JimBobSquarePants.

Private NuGet dependencies are an answer to the problem you are mentioning. They make it so that you have to explicitly install the package to use it. If another package is using ImageSharp as an implementation-only dependency, the app user doesn't see it.

If you don't care about this topic, then that means the more popular ImageSharp gets, the less your test passes "you explicitly installed the package". For example, Json.NET is pretty much everywhere. You can install tons of other packages, and you can end up being able to call JSON.NET APIs w/o explicitly installing the package. Is that a fine outcome from your point of view?

@JimBobSquarePants
Copy link

Ah riiiight.... OK Yeah. Private NuGet dependencies solve the transitive bad actor problem really well!

Is that a fine outcome from your point of view?

Well.... fine is subjective. The way the proposed license works is that if the party that took the direct dependency qualifies for the Apache License then transitive consumption falls under that license. My Commercial License would grant similar freedoms so in real terms I wouldn't have means to stop consumption due to the non-virility of the Split License.

I'm stuck with the problem in that, because this is an established library with a massive OSS userbase with permissive licenses, I have to avoid license virility. I simply can't cut people off so I have to work with loopholes.

For others starting fresh this is an awesome tool to have.

@richlander
Copy link
Member Author

It's possibly slightly better than that. Imagine there were n very popular packages on NuGet that used ImageSharp. You could talk to them and ask them to use this feature. Meaning, you can do some repair on past usage, too.

@zivkan
Copy link
Member

zivkan commented Jul 15, 2022

What does "private dependency" actually mean? I've only skimmed over this issue, so I'm sorry if I missed it.

Does the existing NuGet feature PrivateAssets="compile" already meet the objective? https://github.com/dotnet/roslyn-sdk/blob/df51b014fcb8c9e667a0b09a000f2050615f7afb/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.csproj?q=PrivateAssets%3D%22compile%22#L58-L65

@richlander
Copy link
Member Author

Great question, but I believe that feature does something different. AFAIK, that's a consumption-based feature. It is declaring whether you want the NuGet asset copied to your bin folder or used for a more exclusive purpose. The private dependency suggestion discussed in this issue is a production-based feature. It specifies whether a given dependency should be publicly available within the NuGet graph.

Did I get that right @mhutch @clairernovotny?

@zivkan
Copy link
Member

zivkan commented Jul 15, 2022

https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets

My summary for only the relevant parts:

metadata in current project flow via PackageReference
IncludeAssets ✔️ ✔️
PrivateAssets ✔️
ExcludeAssets
Asset type description
compile lib/<tfm>/*.dll or ref/<tfm>/*.dll passed to compiler
runtime lib/<tfm>/*dll or runtimes/<it's complicated>/*.dll copied to bin
(others) not relevant to this discussion, just want to make it clear this is not a complete list

Therefore:

scenario what to use
Prevent NuGet assets being copied into bin folder ExcludeAssets="all" or ExcludeAssets="runtime" if you want to keep non-dll assets, and exclude only the dlls
Don't allow consumers of my package to use my dependencies, unless they directly reference those packages themselves PrivateAssets="compile"

@richlander
Copy link
Member Author

Interesting. I didn't know that. I'm interested to hear if there is nay nuance from the NuGet PMs. If we have the feature already, that's great.

@zivkan
Copy link
Member

zivkan commented Jul 15, 2022

I just remembered that I documented this a while ago: https://docs.microsoft.com/en-us/nuget/create-packages/select-assemblies-referenced-by-projects#recommended-one-assembly-per-package

@richlander
Copy link
Member Author

Cool. I just looked at https://www.nuget.org/packages/Microsoft.ServiceHub.Client/3.0.3078 in NPE.

I also added that library as PackageReference. I can still see this ns in IntelliSense: Microsoft.VisualStudio.Threading. Is that expected?

@zivkan
Copy link
Member

zivkan commented Jul 15, 2022

There are multiple packages in the transitive graph that list Microsoft.VisualStudio.Threading as a dependency, and at least one of them does not have compile in the exclude list in the nuspec (NPE does not display the exclude metadata, so you have to download the nupkg, or look at your global packages folder, and then open the nuspec file in your favorite XML editor).

On the other hand, Microsoft.VisualStudio.Telemetry appears to be brought in with exclude="compile", so if you look at your obj/project.assets.json file and find "Microsoft.VisualStudio.Telemetry/, within that object you'll see:

        "compile": {
          "lib/netstandard2.0/_._": {}
        },
        "runtime": {
          "lib/netstandard2.0/Microsoft.VisualStudio.Telemetry.dll": {}
        }

which means that no assemblies for this package will provided to the compiler, but will be copied to the bin folder for runtime.

@richlander
Copy link
Member Author

You can look at the nuspec in NPE. I did.

@richlander
Copy link
Member Author

That behavior seems a bit brittle. If there a way to make it less so?

@inoa-pmattos
Copy link

Is there any news on this feature?

@JimBobSquarePants
Copy link

I've reread this conversion a few times now after a long break and I'm struggling to understand parts.

The requirement is thus:

We need a way for a package (A) to reference another package (B) without exposing the public API of the referenced package (B). The user should be able to simply install package (A), write some code using the API for that package and be able to run the code without issue. Ideally there should be a single compiled binary within package (A) containing the code from (A) and (B).

Are we saying @zivkan that this is already possible because I have not found this to be so using combinations of (Private|Exclude|Include)Assets

This feature is not only important for licensing, but also critical for security. Currently libraries will embed ImageSharp in their own libraries by using the source directly and changing public members to internal. This removes the ability to track CVEs and exposes users to risks that they have no way to be aware of.

@richlander
Copy link
Member Author

@JonDouglas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-NetSDK untriaged Request triage from a team member
Projects
None yet
Development

No branches or pull requests

7 participants