<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tieg Zaharia</title>
    <description>The latest articles on Forem by Tieg Zaharia (@tiegz).</description>
    <link>https://forem.com/tiegz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94203%2Fe7abede8-4766-4147-85d1-bd0f24028e0d.jpeg</url>
      <title>Forem: Tieg Zaharia</title>
      <link>https://forem.com/tiegz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tiegz"/>
    <language>en</language>
    <item>
      <title>The current state of package invalidation support across package managers</title>
      <dc:creator>Tieg Zaharia</dc:creator>
      <pubDate>Thu, 01 Apr 2021 16:27:52 +0000</pubDate>
      <link>https://forem.com/tidelift/the-current-state-of-package-invalidation-support-across-package-managers-3p59</link>
      <guid>https://forem.com/tidelift/the-current-state-of-package-invalidation-support-across-package-managers-3p59</guid>
      <description>&lt;h3&gt;Deprecate, retract, unpublish, abandon, yank, orphan, archive...&lt;/h3&gt;

&lt;p&gt;What do all these have in common? Well, they’re different terms for what I’ll call “package invalidation.” Here’s what I mean by package invalidation: &lt;/p&gt;

&lt;p&gt;&lt;span&gt;Package invalidation (n): the indication that an open source maintainer doesn’t want you to use their package or release(s). &lt;/span&gt;&lt;/p&gt;

&lt;h3&gt;Do all package managers support invalidation?&lt;/h3&gt;

&lt;p&gt;Some programming language ecosystems have built-in tooling for invalidation, and some purposely don’t allow it, but one thing certainly holds true: none are the same. &lt;/p&gt;

&lt;p&gt; You can view package invalidation support in two dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Package-level&lt;/strong&gt; vs. r&lt;strong&gt;elease-level&lt;/strong&gt;: either the full package is invalidated, or just specific releases (i.e. versions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deletion&lt;/strong&gt; vs. &lt;strong&gt;deprecation&lt;/strong&gt;: either the package is totally unavailable/gone/404’ed, or it is just marked as deprecated (i.e. a soft warning to not use the package).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that “code deprecation” is a separate topic. &lt;/p&gt;

&lt;h3&gt;Why would you invalidate a package?&lt;/h3&gt;

&lt;p&gt;Maintainers will invalidate their packages for a range of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the maintainers are &lt;a href="https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm" rel="noopener noreferrer"&gt;stepping away&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;it’s vulnerable to a bug or &lt;a href="https://github.com/rubygems/rubygems.org/wiki/Gems-yanked-and-accounts-locked" rel="noopener noreferrer"&gt;has malicious code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;it’s being &lt;a href="https://packagist.org/packages/guzzle/guzzle" rel="noopener noreferrer"&gt;renamed or moved&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;there’s a &lt;a href="https://hackage.haskell.org/package/http-enumerator" rel="noopener noreferrer"&gt;better/faster alternative &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;secrets were &lt;a href="https://github.com/clojars/clojars-web/issues/742" rel="noopener noreferrer"&gt;accidentally published&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;it has a &lt;a href="https://github.com/mimemagicrb/mimemagic/issues/98" rel="noopener noreferrer"&gt;licensing issue&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Are there problems with package invalidation support?&lt;/h3&gt;

&lt;p&gt;Yes 😬 ... package invalidation is a thorny and overlooked topic:&lt;/p&gt;

&lt;p&gt;Firstly, &lt;b&gt;every ecosystem implements invalidation differently&lt;/b&gt;. For example, the Maven package ecosystem for Java doesn’t allow removal of packages because it considers its package index immutable. Clojure, though—a language on the Java platform—follows suit but &lt;a href="https://github.com/clojars/clojars-web/wiki/About#how-do-i-delete-a-jar" rel="noopener noreferrer"&gt;will make exceptions for security’s sake&lt;/a&gt; and is &lt;a href="https://github.com/clojars/clojars-web/issues/766" rel="noopener noreferrer"&gt;considering a more nuanced approach&lt;/a&gt;. When you’re in a polyglot environment, recalling the differences among ecosystems will be arduous.&lt;/p&gt;

&lt;p&gt;Another problem is that &lt;b&gt;it’s often difficult to know when a package/release that you use is invalidated&lt;/b&gt;, unless it’s outright deleted (which might be too late for your CI builds). For example, even though RubyGems allows the removal of a specific release by the maintainer, you may never know if you are using cached versions of that release.&lt;/p&gt;

&lt;p&gt;Lastly, a big problem we found is that &lt;span&gt;maintainers often don’t use the built-in tooling&lt;/span&gt;. Sometimes package invalidation is just a note in the README (maybe a “DEPRECATED” note or a badge from &lt;a href="http://unmaintained.tech/" rel="noopener noreferrer"&gt;unmaintained.tech&lt;/a&gt;). This makes it even trickier to be warned against using a package.&lt;/p&gt;

&lt;h3&gt;Matrix of support&lt;/h3&gt;

&lt;p&gt;Because this subject can be so complex and confusing, we have compiled a matrix of invalidation support for you to use as reference. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;&lt;b&gt;Language&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Package&lt;br&gt;index&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Package&lt;br&gt;deletion&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Release&lt;br&gt;deletion&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Package&lt;br&gt;deprecation&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Release&lt;br&gt;deprecation&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
 &lt;p&gt;&lt;b&gt;Terminology&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Haskell  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://hackage.haskell.org/" rel="noopener noreferrer"&gt;hackage.
&lt;br&gt;haskell.org&lt;/a&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“deprecate”&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Rust&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://crates.io/" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“yank”&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Clojure&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://clojars.org/" rel="noopener noreferrer"&gt;clojars.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete”&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Objective-C&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://cocoapods.org/" rel="noopener noreferrer"&gt;cocoapods.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete” &amp;amp; “deprecate”&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;PHP&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://packagist.org/" rel="noopener noreferrer"&gt;packagist.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete“ &amp;amp; “abandon” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Python  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://anaconda.org/" rel="noopener noreferrer"&gt;anaconda.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Perl  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://www.cpan.org/" rel="noopener noreferrer"&gt;www.cpan.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete” &amp;amp;  &lt;/p&gt;
&lt;p&gt;“deprecate” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Go  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://pkg.go.dev/" rel="noopener noreferrer"&gt;pkg.go.dev&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“retract” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Java  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://search.maven.org/" rel="noopener noreferrer"&gt;search.&lt;br&gt;maven.org&lt;/a&gt;, etc &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Erlang  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://hex.pm/" rel="noopener noreferrer"&gt;hex.pm&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“retire” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;JS  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;www.npmjs.com&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“unpublish” &amp;amp; “deprecate” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;.NET  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://nuget.org/" rel="noopener noreferrer"&gt;nuget.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“deprecate” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Python  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://pypi.org/" rel="noopener noreferrer"&gt;pypi.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“delete” &amp;amp; “yank” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;R  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://cran.r-project.org/" rel="noopener noreferrer"&gt;cran.r-project.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“archive” &amp;amp; “orphan” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Ruby &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://rubygems.org/" rel="noopener noreferrer"&gt;rubygems.org&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;✅  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;“yank” &lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Swift &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href="http://swiftpackageregistry.com/" rel="noopener noreferrer"&gt;swiftpackage&lt;br&gt;
registry.com&lt;/a&gt; &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️  &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;⛔️ &lt;/p&gt;
&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;Other questions to consider&lt;/h3&gt;

&lt;p&gt;There are some other details that will determine how invalidation works, too. Can an invalidated package be aliased or redirected to another package? How are name handoffs or disputes handled? Can deleted releases be re-published?&lt;/p&gt;

&lt;h3&gt;How the Tidelift Subscription can help&lt;/h3&gt;

&lt;p&gt;It can be very tricky to learn about deprecated packages and to navigate each ecosystem’s support, even if you’re paying attention. So how would you be alerted to and/or act upon an invalidated package?&lt;/p&gt;

&lt;p&gt;Tidelift catalogs can help: &lt;a href="https://tidelift.com/catalogs" rel="noopener noreferrer"&gt;catalogs&lt;/a&gt; &lt;span&gt;provide a birds-eye view of all the open source packages that your organization is using&lt;/span&gt;. Catalogs have a “Releases are actively maintained” standard that you can enable and enforce. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fmaintenance-release-actively-maintained.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fmaintenance-release-actively-maintained.png" alt="maintenance-release-actively-maintained" width="516" height="158"&gt;&lt;/a&gt;When enabled, it will let you know when a deprecated package is in use and lets you block it from all your projects. We pull this data via the official tooling from each ecosystem as best we can, so you don’t have to worry about all these details.&lt;/p&gt;

&lt;p&gt;And by paying for the Tidelift Subscription, you’re also &lt;a href="https://blog.tidelift.com/pay-the-maintainers" rel="noopener noreferrer"&gt;paying the maintainers&lt;/a&gt;. The maintainers know best whether a package has been invalidated, and we work closely with the maintainers to bring that information directly to you via the Tidelift Subscription. Curious how that works? You can &lt;a href="https://tidelift.com/subscription/watch-demo" rel="noopener noreferrer"&gt;watch a short demo&lt;/a&gt;, or, better yet, &lt;a href="https://tidelift.com/solutions/schedule-demo" rel="noopener noreferrer"&gt;schedule a custom demo&lt;/a&gt; and one of our team members will show you how Tidelift catalogs work.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>The state of package signing across package managers</title>
      <dc:creator>Tieg Zaharia</dc:creator>
      <pubDate>Thu, 11 Jun 2020 14:49:58 +0000</pubDate>
      <link>https://forem.com/tidelift/the-state-of-package-signing-across-package-managers-328i</link>
      <guid>https://forem.com/tidelift/the-state-of-package-signing-across-package-managers-328i</guid>
      <description>&lt;p&gt;Recently I looked at &lt;a href="https://blog.tidelift.com/the-current-state-of-two-factor-authentication-across-package-managers" rel="noopener noreferrer"&gt;the state of 2FA support across package managers&lt;/a&gt;. 2FA adds a layer of security by requiring two sources of authentication from maintainers when publishing packages. This helps open source communities avoid supply-chain attacks by protecting packages from their author to their repository. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fpkg-signing-pic-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fpkg-signing-pic-1.png" alt="pkg-signing-pic-1" width="381" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2FA is great, but hinges upon the package repository being secure, and isn’t an end-to-end verification that a package came from its maintainer. &lt;/p&gt;

&lt;p&gt;But there’s another way that isn’t as dependent upon the package repository: cryptographic signing of packages. Let’s take a look at which platforms support package signing.&lt;/p&gt;

&lt;h2&gt;But first, what is package signing?&lt;/h2&gt;

&lt;p&gt;Package signing is the act of an open source package (repo, binary, recipe, etc.) being cryptographically signed with a private key so that downstream users can verify the package with a public key.&lt;/p&gt;

&lt;p&gt;Across language ecosystems, there are generally two types of package signing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Signed-by-repository&lt;/strong&gt;: the repository signs uploaded packages, and users verify them after downloading. &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fpackage-signing-ic-2.png" alt="package-signing-ic-2" width="381" height="126"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signed-by-author&lt;/strong&gt;: the author signs packages before uploading them to a repository, and users verify them after downloading from the repository. This is an end-to-end guard to ensure the package was uploaded by its maintainers.&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ff.hubspotusercontent30.net%2Fhubfs%2F4008838%2Fpck-signing-pic-3.png" alt="pck-signing-pic-3" width="381" height="126"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Why is package signing useful?&lt;/h2&gt;

&lt;p&gt;Whether you’re setting up a new codebase on your developer machine or deploying a webapp to your servers, you’re probably downloading dozens—or hundreds—of open source packages. It’s impractical to comb through every line of code to make sure the package you received was not tampered with. Package signing offers a way to say I trust this maintainer and I am guaranteed that this code was uploaded by them.&lt;/p&gt;

&lt;h2&gt;Which programming language package managers support package signing?&lt;/h2&gt;

&lt;p&gt;Let’s try to classify what each package manager does currently:&lt;/p&gt;

&lt;h3&gt;Author-signing:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/nuget/create-packages/sign-a-package" rel="noopener noreferrer"&gt;&lt;strong&gt;Nuget&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: &lt;/strong&gt;as of nuget cli 4.6.0 (March 2018), packages can be &lt;a href="https://docs.microsoft.com/en-us/nuget/create-packages/sign-a-package" rel="noopener noreferrer"&gt;signed&lt;/a&gt; with certificates from a list of &lt;a href="https://docs.microsoft.com/en-us/security/trusted-root/participants-list" rel="noopener noreferrer"&gt;trusted Certificate Authorities&lt;/a&gt;, and &lt;a href="https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-verify" rel="noopener noreferrer"&gt;verified&lt;/a&gt; against those CAs or a specific set of key fingerprints. Nuget also supports &lt;a href="https://docs.microsoft.com/en-us/nuget/api/repository-signatures-resource" rel="noopener noreferrer"&gt;repository-signing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://maven.apache.org/plugins/maven-jarsigner-plugin/index.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Maven&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;a href="https://docs.gradle.org/current/userguide/signing_plugin.html#signing_plugin" rel="noopener noreferrer"&gt;&lt;strong&gt;Gradle&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;a href="https://ant.apache.org/manual/Tasks/signjar.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Ant&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: &lt;/strong&gt;all packages uploaded to Maven Central &lt;a href="https://central.sonatype.org/pages/requirements.html#sign-files-with-gpgpgp" rel="noopener noreferrer"&gt;are required to be PGP-signed&lt;/a&gt;, and all three package managers have tooling to sign and verify.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.ruby-lang.org/en/2.7.0/Gem/Security.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Rubygems&lt;/strong&gt;&lt;/a&gt;: authors can sign packages using SSL certificates based on RSA keys. Verification offers &lt;a href="https://docs.ruby-lang.org/en/2.7.0/Gem/Security.html#module-Gem::Security-label-Signed+gems+and+security+policies" rel="noopener noreferrer"&gt;several levels&lt;/a&gt; of signature checks. &lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Caveat: supports Certificate Authorities but &lt;a href="https://docs.ruby-lang.org/en/2.7.0/Gem/Security.html#module-Gem::Security-label-Certificate+chains" rel="noopener noreferrer"&gt;doesn’t make any CA recommendations for the ecosystem&lt;/a&gt;, so there’s no central CA. &lt;/li&gt;
&lt;li&gt;Usage: we found that, as of March 2020, only 1.4% (2,216 of 157,640 gems) of latest-version gems on Rubygems.org were signed.&lt;/li&gt;
&lt;/ul&gt;




&lt;/ul&gt;

&lt;h3&gt;Repository-signing:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.npmjs.com/about-pgp-signatures-for-packages-in-the-public-registry" rel="noopener noreferrer"&gt;&lt;strong&gt;npm&lt;/strong&gt;&lt;/a&gt;&lt;span&gt;: npm signs packages with its own PGP key, which is publicized on &lt;/span&gt;&lt;a href="https://keybase.io/npmregistry" rel="noopener noreferrer"&gt;Keybase&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;Caveat: although npm doesn’t have native author-signing, there is some 3rd-party tooling available via the &lt;a href="https://medium.com/redpoint/introducing-pkgsign-package-signing-and-verification-for-npm-5b833e0ec2d4" rel="noopener noreferrer"&gt;pkgsign&lt;/a&gt; library&lt;strong&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;More: some interesting discussions about signing have happened on &lt;a href="https://github.com/node-forward/discussions/issues/29" rel="noopener noreferrer"&gt;node-forward&lt;/a&gt;, and &lt;a href="https://github.com/npm/npm/pull/4016" rel="noopener noreferrer"&gt;npm&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;


&lt;/ul&gt;

&lt;h3&gt;In progress:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.python.org/3/whatsnew/2.5.html?highlight=gpg#pep-314-metadata-for-python-software-packages-v1-1" rel="noopener noreferrer"&gt;&lt;strong&gt;Pypi&lt;/strong&gt;&lt;/a&gt;: Python 2.5 added support for author-signing with GPG (via &lt;span&gt;python setup.py --sign upload&lt;/span&gt;), but there is no built-in support to verify those signatures yet.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Caveat: there are &lt;a href="https://discuss.python.org/t/which-cryptographic-signing-approach/2241" rel="noopener noreferrer"&gt;active discussions&lt;/a&gt; and PEPs around signing packages—&lt;a href="https://www.python.org/dev/peps/pep-0458/" rel="noopener noreferrer"&gt;PEP 458&lt;/a&gt; for repository-signing and &lt;a href="https://www.python.org/dev/peps/pep-0480/" rel="noopener noreferrer"&gt;PEP 480&lt;/a&gt; for author-signing—using &lt;a href="https://theupdateframework.io/" rel="noopener noreferrer"&gt;The Update Framework&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;li&gt;

&lt;a href="https://make.wordpress.org/core/2019/05/17/security-in-5-2/" rel="noopener noreferrer"&gt;&lt;strong&gt;Wordpress&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: &lt;/strong&gt;discussion of signing happened &lt;a href="https://core.trac.wordpress.org/ticket/25052" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and signing of Wordpress itself was added &lt;a href="https://core.trac.wordpress.org/ticket/39309" rel="noopener noreferrer"&gt;here&lt;/a&gt;. As of 5.2, WordPress updates are now signed, but plugins and themes are still unsigned.&lt;/li&gt;

&lt;ul&gt;
&lt;li&gt;Caveat: there’s an open &lt;a href="https://core.trac.wordpress.org/ticket/49200" rel="noopener noreferrer"&gt;discussion&lt;/a&gt; about implementing author-signing via a PKI called &lt;a href="https://github.com/paragonie/libgossamer/tree/master/docs" rel="noopener noreferrer"&gt;Gossamer&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;/ul&gt;

&lt;h3&gt;Partial or no signing:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://blog.golang.org/module-mirror-launch#TOC_3." rel="noopener noreferrer"&gt;&lt;strong&gt;Go Modules (Go)&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: &lt;/strong&gt;&lt;span&gt;as of Go 1.13, Go Modules verifies downloaded packages (which are usually git repos) against a &lt;/span&gt;&lt;a href="https://sum.golang.org/" rel="noopener noreferrer"&gt;checksum database&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://getcomposer.org/doc/02-libraries.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Composer&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (PHP): &lt;/strong&gt;there have been discussions of built in signing/verification &lt;a href="https://github.com/composer/composer/issues/4022" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cargo (Rust): &lt;/strong&gt;crates are hosted on GitHub*, and the Rust community has discussed package signing &lt;a href="https://internals.rust-lang.org/t/pre-pre-rfc-solving-crate-trust/6495" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;a href="https://github.com/rust-lang/rfcs/pull/2474" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/rust-lang/crates.io/issues/75" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPAN (Perl): &lt;/strong&gt;no built-in support, but author-signing is available via 3rd party package manager &lt;a href="https://metacpan.org/pod/pp" rel="noopener noreferrer"&gt;pp&lt;/a&gt; (or the underlying &lt;a href="https://metacpan.org/pod/Module::Signature" rel="noopener noreferrer"&gt;cpansign&lt;/a&gt; cli)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Carthage (Cocoa): &lt;/strong&gt;packages are hosted on GitHub*, GitLab**, Bitbucket***, etc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Julia Pkg (Julia): &lt;/strong&gt;packages are hosted on GitHub*, GitLab**, Bitbucket***, and registered with the &lt;a href="https://github.com/JuliaRegistries/General" rel="noopener noreferrer"&gt;Julia Package Registry&lt;/a&gt; on github.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bower (JS): &lt;/strong&gt;packages are hosted on GitHub*, GitLab**, Bitbucket***, etc&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://puppet.com/docs/puppet/latest/modules_publishing.html" rel="noopener noreferrer"&gt;&lt;strong&gt;PDK&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (Puppet)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://atmospherejs.com/i/publishing" rel="noopener noreferrer"&gt;&lt;strong&gt;Meteor&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (Meteor)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cabal.readthedocs.io/en/latest/developing-packages.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Cabal&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (Haskell)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hex.pm/docs/publish" rel="noopener noreferrer"&gt;&lt;strong&gt;Mix&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (Erlang)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cran.r-project.org/doc/manuals/r-release/R-exts.html" rel="noopener noreferrer"&gt;&lt;strong&gt;R&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (R)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Does package signing matter?&lt;/h2&gt;

&lt;p&gt;If you read through the discussions linked to above, package signing is indeed a lofty goal and challenging to get right. So is it worth it, and could it prevent any classes of exploits? You can find some examples of supply chain attacks from the past decade documented &lt;a href="https://github.com/theupdateframework/pip/wiki/Attacks-on-software-repositories" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/in-toto/supply-chain-compromises" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Those lists contain some examples of repository account takeovers and other exploits that could be mitigated using package signing. &lt;/p&gt;

&lt;h2&gt;More reading&lt;/h2&gt;

&lt;p&gt;Here are some more writeups on package signing that are useful or that we found interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://theupdateframework.io/" rel="noopener noreferrer"&gt;The Update Framework, for “securing software update systems”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devblogs.microsoft.com/nuget/NuGet-Package-Signing/" rel="noopener noreferrer"&gt;How NuGet package signing was planned&lt;/a&gt; and &lt;a href="https://haacked.com/archive/2019/04/03/nuget-package-signing/" rel="noopener noreferrer"&gt;Why NuGet Package Signing Is Not (Yet) for Me&lt;/a&gt; (Nuget)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.davidfischer.name/2012/05/signing-and-verifying-python-packages-with-pgp/" rel="noopener noreferrer"&gt;Signing and Verifying Packages with PGP&lt;/a&gt; (Pypi)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.grant-olson.net/news/2013/09/29/nobody-cares-about-signed-gems.html" rel="noopener noreferrer"&gt;Nobody cares about signed gems&lt;/a&gt; (Rubygems)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Footnotes:&lt;/h3&gt;

&lt;p&gt;* GitHub allows &lt;a href="https://help.github.com/en/github/authenticating-to-github/managing-commit-signature-verification" rel="noopener noreferrer"&gt;commits and tag signing&lt;/a&gt; and will label them as verified-or-not, although there are no signatures/checksums available for release zip/tar archives. &lt;/p&gt;

&lt;p&gt;** GitLab allows &lt;a href="https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/" rel="noopener noreferrer"&gt;commit signing&lt;/a&gt; and labels them as verified or not, but not for builds.&lt;/p&gt;

&lt;p&gt;*** BitBucket Server allows &lt;a href="https://confluence.atlassian.com/bitbucketserver/using-gpg-keys-913477014.html" rel="noopener noreferrer"&gt;commit and tag signing&lt;/a&gt; -- while Bitbucket Cloud &lt;a href="https://jira.atlassian.com/browse/BCLOUD-3166?_ga=2.248503567.94323029.1582068664-710106391.1582068664" rel="noopener noreferrer"&gt;does not yet&lt;/a&gt; -- but not for builds.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>opensource</category>
      <category>java</category>
    </item>
  </channel>
</rss>
