Skip to content

Commit

Permalink
content(npm-i-everything): fix link to update, rephrase some paragrap…
Browse files Browse the repository at this point in the history
…hs and rewrite headings
  • Loading branch information
uncenter committed Jan 4, 2024
1 parent 4097a3a commit 6fb0285
Showing 1 changed file with 16 additions and 20 deletions.
36 changes: 16 additions & 20 deletions src/posts/npm-install-everything.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ comments: true

:::note

## An update!
## An update! {data-toc-exclude}

<details>
<summary>You might want to read the rest of the article first...</summary>
Expand Down Expand Up @@ -44,17 +44,17 @@ Ten years ago, [@PatrickJS](https://github.com/PatrickJS) created the `everythin

I saw the tweet on my timeline and [made a quick PR](https://github.com/everything-registry/everything/pull/6) to clean up a few things and help bring the repository up to speed. At the same time, Patrick had started an attempt to publish a `2.0.0` version of the package, but he discovered that there was now a `10` megabyte limit for the uncompressed size of a package. I [made a comment](https://github.com/everything-registry/everything/pull/6#issuecomment-1872278630) about the issue and we quickly [began brainstorming](https://github.com/everything-registry/everything/pull/6#issuecomment-1872294994) a solution.

## Phase 1: Brainstorming
## Brainstorming...

We moved to Twitter DMs, and by this time others who saw Trash's tweet wanted to join — [Hacksore](https://hacksore.com/), and Trash himself. We came up with a plan to divide the ~2.5m packages into "scoped" groups of packages; a group for packages starting with the letter "a", the letter "b", and the rest of the alphabet, and then the numbers "0" to "9", and finally an "other" category for anything else. Since each of these scoped packages would only be a subset of the total, they would easily pass the size limit, and the main `everything` package could just depend on each of these scoped packages.

{% image "plan-a.png", "A diagram of the core 'everything' package depending on many other scoped packages", { dark: "plan-a-dark.png" } %}

## Phase 2: Execution
## Unforseen issues

[I began implementing some code](https://github.com/everything-registry/everything/pull/7) to generate the required packages, and a few hours later we were ready to go- except we forget one thing. Or, rather, NPM didn't tell us one thing. It turns out that NPM has a limit for how many dependencies a package can have. And we were apparently _way_ over it. NPM has no apparent documentation on this and the limit wasn't visible in any public source code (the registry is private), so Hacksore [did some testing](https://github.com/Hacksore/max-npm-package-deps) and discovered the limit to be 800 dependencies. At the current range of 90k to 300k dependencies per scoped package... we needed a new plan.

## Phase 3: Back to the drawing board.
## Back to the drawing board

I suggested a new, very basic plan: just split them into "chunks" (groups) of 800 dependencies.

Expand All @@ -64,7 +64,7 @@ This leaves 3246 groups though, and 3246 is still too many for our main `everyth

{% image "plan-b.png", "A diagram of the core 'everything' package with arrows toward many 'chunked' packages, each of which in turn has arrows toward more 'sub-chunked' packages", { dark: "plan-b-dark.png" } %}

## Phase 4: Execution (again)
## 3...2...1... go!

Set on our new plan, we updated the code and triggered [our GitHub Actions workflow](https://github.com/everything-registry/everything/blob/1aef5aa3aa5e3d0e2107063cad6ce63f9cba9b0b/.github/workflows/release.yml)...

Expand All @@ -74,17 +74,13 @@ It worked! The [GitHub Action logs](https://github.com/everything-registry/every

{% image "plan-b-success.png" %}

We all went back to doing other things, and I checked the logs occasionally. Half an hour later though, we ran into a different problem.
We all went back to doing other things, and I checked the logs occasionally. Half an hour later though, we ran into a different problem... we had been rate limited. In 32 minutes, we had published 454 packages: the main `everything` package, all five "chunks", but only 448 "sub-chunks". It was only a fraction (roughly 14%) of everything (hah, pun intended) we needed to publish.

## 11:33 PM, EST

We had found the limits of NPM's API, and had been rate limited. In 32 minutes, we had published 454 packages: the main `everything` package, all five "chunks", but only 448 "sub-chunks". It was only a fraction (roughly 14%) of everything (hah, pun intended) we needed to publish.

## Phase 5: What next??
## What next??

I [made a quick fix](https://github.com/everything-registry/everything/commit/1aef5aa3aa5e3d0e2107063cad6ce63f9cba9b0b) before heading to bed to skip the packages we had already published, but we still didn't have any sort of plan to deal with rate limiting. Overnight between the 29^th^ and the 30^th^, we settled on a new plan. We would periodically run a workflow that publishes as many packages as it can, and then the workflow saves the work it did to the repository so the next run can pick up where the last one left off. I replaced the sketchy manual intervention from the night before with a proper `published.json` file to keep track of the published packages, and [initialized it](https://github.com/everything-registry/everything/commit/fafc0ccf92b74eb994136c49b3ae87a7016d6e77). I [wrote a release script](https://github.com/everything-registry/everything/commit/3bd649ab3bd74a6d7933b8e4ad5116b9b987889d) that wrote back to `published.json` after publishing each package (I know, I know, this could be better) and [added a step to the workflow](https://github.com/everything-registry/everything/commit/85c8bed75a15e81c66a750e3ea36a4f3bb166fcc) to commit the changes after each run. After a few hiccups[^1], it finally worked!

And so it began. Throughout the day I, very irregularly, manually dispatched the workflow. For a while, we sat and waited. We even began an effort to actually run `npm install everything` (well, `yarn add everything`) and put up a Twitch stream.
So it began. Throughout the day I (very irregularly) manually dispatched the workflow. For a while, we sat and waited. We even began an effort to actually run `npm install everything` (well, `yarn add everything`) and put up a Twitch stream of the installation on a virtual machine.

{% image "twitch-stream.png", { dark: "twitch-stream-dark.png" } %}

Expand All @@ -94,22 +90,22 @@ We also [made a website](ttps://everything-registry.github.io/)! Many thanks to

Finally, at 11:27PM, [the final workflow run](https://github.com/everything-registry/everything/actions/runs/7368358420) completed publishing the last 20 sub-chunks. All 5 chunks, 3246 sub-chunks, and the main `everything` package. In total, depending on over 2.5 million NPM packages!

[^1]: Namely https://github.com/everything-registry/everything/commit/9edd208769da652db2c2eb06196dad4ceb2b452d, https://github.com/everything-registry/everything/commit/f963df11963a80f50ba06107101fcabab7cb5825, and https://github.com/everything-registry/everything/commit/5c50a13ad6de8229f262ff98e798301cee6fc119.

## Response
## A vulnerability?

The initial response to our endeavour was... not positive. People began coming to the repository, complaining about not being able to unpublish. We looked into it, and it turns out that the issue is our usage of "star" versions; that is, specifying the version not as a typical semantic version in the format of `vX.Y.Z`, but as `*`. The star means "any and all" versions of a package - here is where the issue lies. NPM blocks package authors from unpublishing packages if another package depends on that version of the package. But since the star is _all_ versions, all versions of a package cannot be unpublished. This is usually harmless, but unintentionally us doing this on a large scale prevented _anyone_ from unpublishing. We immediately reached out to GitHub; Patrick used his network and contacts to speak to people at GitHub, and we sent multiple emails to the support and security team on NPM. Unfortunately, these events transpired over the holidays and the NPM/GitHub teams were out of the office. We continued to get harsh and rude comments from random people with a little too much time on their hands - one person even [wrote a 1400 word rant](https://github.com/everything-registry/everything/issues/21).
The initial response to our endeavour was... not positive. People began coming to the repository, complaining about not being able to unpublish. What?! We looked into it, and it turns out that the issue was our usage of "star" versions; that is, specifying the version not as a typical semantic version in the format of `X.Y.Z`, but as `*`. The star means "any and all" versions of a package - here is where the issue lies. NPM blocks package authors from unpublishing packages if another package depends on that version of the package. But since the star is _all_ versions, all versions of a package cannot be unpublished. This is usually harmless, but us (unintentionally) doing this on a large scale prevented _anyone_ from unpublishing. We immediately reached out to GitHub; Patrick used his network and contacts to speak to people at GitHub, and we sent multiple emails to the support and security teams on NPM. Unfortunately, these events transpired over the holidays and the NPM/GitHub teams were out of the office. We continued to get harsh and rude comments from random people with a little too much time on their hands... one person even [wrote a 1400 word rant](https://github.com/everything-registry/everything/issues/21) about the unpublishing issue, despite us repeatedly telling them we could do nothing further.

Thankfully on the night of Tuesday, Janurary 2^nd^, GitHub reached out and let us know they were aware of the problem. On the 3^rd^ of January, we received a notice that our GitHub organization had been "flagged" and our organization and repositories were hidden. Not what we wanted to see, but progress nonetheless.
Thankfully, on the night of Janurary 2^nd^, GitHub reached out and let us know they were aware of the problem. On the 3^rd^ of January, we received a notice that our GitHub organization had been "flagged" and our organization and repositories were hidden. Not what we wanted to see, but progress nonetheless.

{% image "org-flagged.png" %}

They also began removing our organization's scoped packages on NPM, as we had suggested. I think it's safe to say the initial problem has been solved, but we are still waiting to see how NPM prevents this issue in the future. My two cents are that NPM should either a) prevent folks from publishing packages with star versions in the package.json entirely, or b) don't consider a dependent of a package if it uses a star version when tallying how many packages depend on a package for unpublishing.
They also began removing our organization's scoped packages on NPM, as we had suggested. The initial problem had been solved, but we are still waiting to see how NPM prevents this issue in the future. My two cents are that NPM should either a) prevent folks from publishing packages with star versions in the package.json entirely, or b) don't consider a dependent of a package if it uses a star version when tallying how many packages depend on a package for unpublishing.

And lastly, I want to apologize for anyone frustrated, annoyed, or just angry at us. We made a mistake, and we've owned up to it. This all started as a harmless joke and we had no intentions of breaking, abusing, or doing any sort of damage to the registry. In short we, uhh... fucked around and found out.
Lastly, I want to apologize for anyone frustrated, annoyed, or just angry at us. We made a mistake, and we've owned up to it. This all started as a harmless joke and we had no intentions of breaking, abusing, or doing any sort of damage to the registry. In short we, uhh... fucked around and found out.

{% image "fuck-around-find-out.jpg" %}

Thanks for reading this, and have a lovely day!

_Now_ you can [read the update](http://localhost:8080/posts/npm-install-everything/#an-update!) if you haven't already!
_Now_ you can [read the update](#an-update!) if you haven't already!

[^1]: Namely https://github.com/everything-registry/everything/commit/9edd208769da652db2c2eb06196dad4ceb2b452d, https://github.com/everything-registry/everything/commit/f963df11963a80f50ba06107101fcabab7cb5825, and https://github.com/everything-registry/everything/commit/5c50a13ad6de8229f262ff98e798301cee6fc119.

0 comments on commit 6fb0285

Please sign in to comment.