Snap license metadata

I don’t see how it being editable in the store makes those issues any harder to deal with. All of the issues you describe seem true despite it, as you can change the content of a license shipped inside the snap (or deb, or RPM, or …) at any point.

The reason it is a good idea to allow editing it in the store was discussed in a long session a while ago in the context of summaries and descriptions, and we probably have notes somewhere. I can go over it or try to find it if you don’t have memories of it, but without trying to do the topic proper justice, the problem is precisely that in a development cycle many snaps for different revisions will be pushed to the store. Without the ability to define what the correct up-to-date value is, it becomes a mess.

In what I wrote I tried to explain exactly what’s different and why it’s harder if the license can change at any time. The key point is that, if a license is for a revision of the software, things are simpler. And the simplest way of doing that is not making them editable in the UI but getting them from the yaml.

This is different from titles and descriptions, where we decided that it’s best to just have one, per snap, and not per revision. Licenses need to be the opposite of that.

You are explaining again what was said above, but didn’t address the main point I presented. In your concerns you presented a number of tricky cases, and proposed that we’d need to block updates, warn the user when there are changes, and so forth. All of these issues are true regardless of the fact we keep an up-to-date version of the license in the store, and they are also true in every other scenario about package managers, which today are not addressed in any special way.

We need to block updates and warn the user, if the license change is related to the revision and there is thus a thing to block: the revision they are on now has a license they agreed to, and if we were to update to the new revision they’d be on a license they haven’t agreed to yet. This is work we need to do.

If the license change is not connected to a revision change, then … how do we handle that? There is nothing to block; the user now has software with a license they haven’t agreed to. There is in this scenario no path that lets the user not be potentially in violation of that license, or having or using software with a license they don’t agree with.

That sounds bad for multiple reasons:

  • We don’t want to block updates of working software; it’s unexpected and will create problems.
  • We have no interface to ask for agreements on a license.
  • Most license changes on free/open source preserve the software as free/open source.
  • Many license changes will be trivial fixes (we lack good information today).
  • No other package manager does that.

And with all that said, this is all unrelated to the original point: that issue exists whether we keep an authoritative version in the store or not, so is not good motivation for doing it one way or the other.

The approach I would recommend is this: we keep the authoritative version in the store, because we need to display something to people that want to know what the license is, and because we don’t want to overwrite that license every time a snap is pushed (again, same problem of summaries and descriptions). Locally, we display the locally installed snap license. When the local snap is refreshed to something containing a different license, we issue a warning through the upcoming warnings framework. We also warn when the just installed snap holds a license that diverges from the authoritative one in the store, which they may have read.

so, to summarise:

  • snaps will have a license field
  • the store will have a per-snap (not per-revision) license. This is taken from a snap’s yaml but can be changed online, or via re-reading any later snap, at which point that license is the one that applies to that snap irrespective of revision
  • in other words, snap license changes retroactively apply to software previously released.
  • when a snap’s license is changed, the user isn’t notified. If and when the developer pushes a revision to the channel they’re tracking, they’ll get a warning. Meanwhile they’ll still be told the license of the software is the one in the snap, despite it not being that.

The two last points disagree with the proposal made.

We’re misunderstanding each other, I fear.

We’re now in agreement. :slight_smile:

We discussed this today in the call, and we now understand each other.

The suggestion from @chipaca is that instead of requiring manual fiddling with an editable label in the store, it’s much simpler to always take the license from the stable channel. That’s a good idea and simpler in all angles. The only bit I’d amend is that we should pick the license from the most stable channel, not just stable itself, because we need to show something if there’s no snap in stable.

So, the next steps are:

  1. Implement the described logic in the store
  2. Support custom licenses
  3. Change snapcraft to warn about missing licenses
  4. Change the store to reject new snaps without licenses

Step 4 needs to wait some grace period until everybody had a chance to update their snaps.

Trying to get some extra clarifications about the suggested plan.

  • Are you proposing the store should not allow to modify the license through the web UI, or via API, but only extract the license expression as provided by each uploaded revision?

  • There is still a snap-level license, given by the current most stable released revision. This means that depending on the channel map constraints (arch, validation, epochs, etc), the snap could expose a (dynamically calculated) different license?

  • Similarly, if I’m following the beta channel, and I got a snap installed under X license, and the developer releases a new revision to stable (not affecting the beta channel) with Y license, does the license for the snap change for me?

Given the channel map is calculated on the fly given a set of constraints, I’m not sure if tying the license around that will work as expected.

Yes, the license would not be editable outside of the snap, as the license is tightly bound to the snap content. Each released snap carries its own license information.

For the second question, by “snap-level” I assume you mean independent of any revisions. Yes, we need to present some kind of information that is “current”, usable in the web interface, etc. For that we pick the license of the most recently published snap in the most stable channel not closed (latest/stable itself, if available).

For the last question, no… once you install a snap, the license displayed locally through snapd is the one for the local snap. Once our warnings pipeline is developed, we will issue a warning on license changes.

Regarding the channel map, that’s exactly why we need a notion of “current license” that is bound to the whole snap. We already have the ability to display multiple licenses for an individual revision. Trying to provide details of all licenses that all revisions carry would be very confusing.

That seems a scary restriction. What if an upstream project is relicensed for future releases only (not past), e.g. a project transitioning from GPLv2 to GPLv3 … ? Or, alternatively, what if some revisions of a snap contain extra components (with their own license) that other revisions do not?

This is not a theoretical case, by the way. This happened to me, with the ldc2 snap, when the upstream project removed a dependency on libconfig (previously statically compiled into the snap):
https://github.com/ldc-developers/ldc2.snap/commit/80db8f3322d33f940ad0981783772ce1182b6774

@joseph.wakeling Per following discussion, the “irrespective of revision” means the license that is displayed by default in interfaces when you list the snap alone, and it will be extracted from the revisions themselves using some reasonable heuristics (latest stable, for instance).

The individual snaps will still hold their own license, which will be displayed if locally installed.

Right, my point in this case was that the channel map, in most cases, has multiple revisions released to stable at a given time (because of series or arch, or refresh control, for example), so when we say “the license from the revision in the most stable channel”, this could really be a list of (potentially) different licenses.

It changes depending on the point of view of the client, in the sense that we could have different “current licenses” for clients with different architectures (ie. 2 revisions, different arch, different license, both released to stable).

Do you have a suggestion of a polished way to implement that heuristic?

I think we should avoid a heuristic and leave it up to the snap author as it is now, which is also consistent with how we handle other metadata. Too many ways of doing things with snap-level data will be confusing. I’d suggest we add a license-last-modified date as well so there’s some indication in that top-level data of a change and then interested parties can dig into the README or License.txt to get further info.

We definitely can, but I see no good rationale for doing it considering everything we discussed above. It’s not simpler, or easier to support, or understand. Plus, it has the serious downside that makes people think that just having a license set in the store is enough to give their snaps a license. It’s not.

So how about this:

The general license when the operation at hand has no revision context is the one for the revision currently in the latest track, in the most stable risk available. That means latest/stable is the preferred choice. The architecture lookup order is: amd64, 386, arm64, arm, etc. If there are no revisions in latest, then the snap license is unknown unless there is a revision for the operation at hand (e.g. the snap is installed).

How is that list of criteria easier to understand or support than “The license shown when no revision context is available is the one the developer explicitly sets”?

1 Like