mirror of
https://github.com/NixOS/rfcs.git
synced 2025-11-09 03:56:11 +01:00
Merge 42121167c4 into c655bdaab4
This commit is contained in:
commit
a7e9d66920
1 changed files with 203 additions and 0 deletions
203
rfcs/0191-lockfile-generation.md
Normal file
203
rfcs/0191-lockfile-generation.md
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
---
|
||||||
|
feature: lockfile-generation
|
||||||
|
start-date: 2025-10-09
|
||||||
|
author: dish (@pyrox0)
|
||||||
|
co-authors: (find a buddy later to help out with the RFC)
|
||||||
|
shepherd-team: (names, to be nominated and accepted by RFC steering committee)
|
||||||
|
shepherd-leader: (name to be appointed by RFC steering committee)
|
||||||
|
related-issues: (will contain links to implementation PRs)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
[summary]: #summary
|
||||||
|
|
||||||
|
When adding packages to nixpkgs, or migrating them within nixpkgs, some packages do not contain lockfiles
|
||||||
|
that would allow us to lock their dependencies correctly. This is an issue with packages based on the
|
||||||
|
NPM, Yarn, PNPM, and Cargo package managers, but is not limited to them. Therefore, we should support
|
||||||
|
some mechanism for creating these sorts of lockfiles, **without** bloating the nixpkgs tarball with
|
||||||
|
megabytes of lockfiles that are only useful for a handful of packages.
|
||||||
|
|
||||||
|
# Motivation
|
||||||
|
|
||||||
|
[motivation]: #motivation
|
||||||
|
|
||||||
|
I have been migrating many packages from the deprecated `nodePackages` package set, into the main nixpkgs
|
||||||
|
package set(under `pkgs/by-name`). Many packages, such as [alex](https://github.com/get-alex/alex),
|
||||||
|
most(or all) packages by [`sindresorhus`](https://github.com/sindresorhus), and even projects using
|
||||||
|
Cargo and Rust such as [`proxmox-backup-client`](https://git.proxmox.com/?p=proxmox-backup.git;a=tree) do not have lockfiles.
|
||||||
|
This becomes an issue. Currently, the solution is to generate these lockfiles, and then vendor them within nixpkgs,
|
||||||
|
then using the `postPatch` phase(mostly) to copy this lockfile to the source tree, allowing for package
|
||||||
|
reproducibility.
|
||||||
|
|
||||||
|
The issue, of course, is that this massively increases the size of the nixpkgs tarball. nixpkgs issues such as
|
||||||
|
[#327064](https://github.com/NixOS/nixpkgs/issues/327064) and [#327063](https://github.com/NixOS/nixpkgs/issues/327063) have found
|
||||||
|
the effects of this are staggering, with nearly 6MiB of size(at the time) added to the nixpkgs tarball,
|
||||||
|
and this also contributed a lot of eval time of nixpkgs(See [this comment](https://github.com/NixOS/nixpkgs/issues/320528#issuecomment-2227185095)).
|
||||||
|
|
||||||
|
However, I believe there are solutions to this problem. The
|
||||||
|
[`rustPlatform.fetchCargoVendor`](https://nixos.org/manual/nixpkgs/stable/#vendoring-of-dependencies)
|
||||||
|
function allows for using upstream Cargo.lock files without parsing them within
|
||||||
|
nixpkgs, thus solving the previous problem of parsing these lockfiles within
|
||||||
|
nixpkgs itself, removing much of the eval time penalty. This does not solve the
|
||||||
|
issue for packages that do not ship their own lockfiles, however, which still
|
||||||
|
requires vendoring the lockfile within nixpkgs, which contributes to the above
|
||||||
|
evaluation time and tarball size issues.
|
||||||
|
|
||||||
|
Note also that the following design DOES NOT rely on [`import-from-derivation`](https://nix.dev/manual/nix/latest/language/import-from-derivation.html), as far as I know. This is a critical point for anything in
|
||||||
|
nixpkgs, as we should not require IFD to evaluate nixpkgs or build any packages.
|
||||||
|
|
||||||
|
# Detailed design
|
||||||
|
|
||||||
|
[design]: #detailed-design
|
||||||
|
|
||||||
|
I propose that a new repo, named `NixOS/lockfile-storage`(or something similar)
|
||||||
|
be created in the NixOS repo, along with a GitHub App for this purpose. This app
|
||||||
|
would help streamline the process of generating these lockfiles.
|
||||||
|
|
||||||
|
Note, for the rest of this document, I will refer to the above repository as "LFR", for "Lockfile Repository",
|
||||||
|
and the GitHub app/bot that manage it as the "LFR Bot".
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
The following diagram illustrates an idealized workflow using this new process.
|
||||||
|
|
||||||
|
Note also that I've designed this to be as simple from an end-user(PR Author)'s perspective. The
|
||||||
|
only additional friction they should have from this process is potentially waiting for someone to
|
||||||
|
approve an LFR PR, so that the lockfile will be accessible.
|
||||||
|
|
||||||
|
Caveats: We assume that the PR Author is also a committer, and we also skip over a potential approval
|
||||||
|
step for PRs in the lockfile repo in order to keep the repo safe over time.
|
||||||
|
|
||||||
|
Notes: `lfr` is Lockfile Repo, and `lfr_bot` is the mentioned GitHub App that would do this
|
||||||
|
automatically.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant auth as PR Author
|
||||||
|
participant nixpkgs@{ "type": "database" }
|
||||||
|
auth->>nixpkgs: Submits PR
|
||||||
|
auth->>nixpkgs: Comment mentioning @LFR_Bot
|
||||||
|
create participant LFR_Bot@{"type": "queue"}
|
||||||
|
nixpkgs-->>LFR_Bot: processes ping
|
||||||
|
lfr_bot->>LFR_Bot:Creates lockfile with tooling
|
||||||
|
create participant LFR@{ "type": "database" }
|
||||||
|
lfr_bot->>LFR: Creates PR associated with nixpkgs PR
|
||||||
|
note left of LFR: Processes and<br>merges PR
|
||||||
|
destroy LFR
|
||||||
|
LFR-->>LFR:
|
||||||
|
LFR_Bot->>nixpkgs: Adds "LFR:processed" label to PR
|
||||||
|
LFR_Bot->>nixpkgs: Comments link to lockfile for fetching
|
||||||
|
auth->>nixpkgs: Updates PR with lockfile
|
||||||
|
auth->>nixpkgs: Merges PR
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lockfile Repo Bot
|
||||||
|
|
||||||
|
For ease of contribution and extensibility, this bot should be written in Python, a la [nixpkgs-merge-bot](https://github.com/NixOS/nixpkgs-merge-bot).
|
||||||
|
|
||||||
|
When a user submits a PR, they should be able to immediately ping the bot to start the process of creating the lockfile.
|
||||||
|
This may involve an approval step, if users are not committers or maintainers, but otherwise should execute automatically.
|
||||||
|
|
||||||
|
The bot would be a simple Python script that recieves two things: A source URL, and a package manager type.
|
||||||
|
The source URL would be the `git clone`-able URL for a git repo, which is the only currently envisioned
|
||||||
|
source type, but again this could be designed to be easily extensible. The package manager type would be
|
||||||
|
one of a set of strings, such as "npm", "yarn", "yarn_berry", "cargo", or other similar phrase. This
|
||||||
|
would act as the two inputs to the script, where it would first clone the repository, then execute the
|
||||||
|
package manager's command to create a lockfile without actually installing dependencies, such as:
|
||||||
|
|
||||||
|
* npm: `npm install --package-lock-only`
|
||||||
|
* yarn berry: `yarn install --mode=update-lockfile`
|
||||||
|
* cargo: `cargo generate-lockfile`
|
||||||
|
* etc...
|
||||||
|
|
||||||
|
This allows us to follow a similar pattern to tools such as [Renovate](https://www.mend.io/renovate/) or [Dependabot](https://github.com/dependabot),
|
||||||
|
which can update lockfiles but do not need to install all dependencies to do so, which allows them to scale better.
|
||||||
|
Further, not installing code allows us to avoid many security issues that come from downloading and running untrusted code.
|
||||||
|
|
||||||
|
## Lockfile Repo
|
||||||
|
|
||||||
|
This would be a very simple repo. A package for lockfiles from each ecosystem, and then a folder per-package that uses that package manager. That way, there are not errors at the top level with "too many files", and so that if you know where a package is, you can find it easily.
|
||||||
|
|
||||||
|
Further, updates to a package should automatically update the lockfile, and replace it in the
|
||||||
|
lockfile repo, NOT adding an additional file to the repo. This is to prevent unbounded growth of the
|
||||||
|
repo, and to try and keep it reasonable to clone if needed(though again, the workflow is designed to
|
||||||
|
hopefully not need that). Finally, when dropping a package, this should be able to be automatically
|
||||||
|
detected and a PR removing it from the LFR should be automatically generated. Old lockfiles,
|
||||||
|
however, would still be accessible since they are stored in the data of previous commits.
|
||||||
|
|
||||||
|
|
||||||
|
# Examples and Interactions
|
||||||
|
|
||||||
|
[examples-and-interactions]: #examples-and-interactions
|
||||||
|
|
||||||
|
From a user perspective, I want this to be as smooth as possible. So, after submitting a PR, you would add a comment with the following structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
@NixOS/LFR_Bot [repo] [type]
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
@NixOS/LFR_Bot https://github.com/NixOS/nixpkgs npm
|
||||||
|
```
|
||||||
|
|
||||||
|
which would `git clone` the nixpkgs repo and attempt to create an npm `package-lock.json` file.
|
||||||
|
|
||||||
|
These commands should be sanitized so that only the original author of the PR or committers can run
|
||||||
|
this process, avoiding some potential issues. Further, non-maintainers must wait for an approval
|
||||||
|
step on the workflow, possibly with a committer having to comment `@NixOS/LFR_Bot approve` or some
|
||||||
|
similar message.
|
||||||
|
|
||||||
|
# Drawbacks
|
||||||
|
|
||||||
|
[drawbacks]: #drawbacks
|
||||||
|
|
||||||
|
If the lockfile storage repository is deleted or purged in any way, then anything relying on this
|
||||||
|
repository is broken, unless the lockfile has already been fetched locally and stored as a FOD. We
|
||||||
|
could approach this problem by having some special fetcher that can use alternative sources, such as
|
||||||
|
a CDN or other server(for users in China who may have issues accessing GitHub, for instance).
|
||||||
|
|
||||||
|
Further, this is another potential way for someone to sneak untrusted code into nixpkgs, but:
|
||||||
|
|
||||||
|
* The lockfiles are generated on nixpkgs-related infrastructure(either self-hosted or GHA), so
|
||||||
|
there is not a risk of attackers patching lockfiles for malicious purposes.
|
||||||
|
* Non-maintainers should go through an initial approval before having this run for their PRs.
|
||||||
|
* The lockfiles should also only be generated for supported ecosystems, and if lockfiles already exist,
|
||||||
|
they should be used instead of relying on this tool.
|
||||||
|
|
||||||
|
# Alternatives
|
||||||
|
|
||||||
|
[alternatives]: #alternatives
|
||||||
|
|
||||||
|
* Not packaging packages with missing lockfiles
|
||||||
|
* A very valid idea! However, there are enough of these sorts of packages, and lockfiles are already such an issue
|
||||||
|
for nixpkgs, that we should solve this so that we can move more lockfiles out of tree.
|
||||||
|
* Storing lockfiles in-tree
|
||||||
|
* See above issues r.e massively increased tarball size. I aim to prevent that with this, so doing that
|
||||||
|
would be antithetical to this.
|
||||||
|
|
||||||
|
# Prior art
|
||||||
|
|
||||||
|
[prior-art]: #prior-art
|
||||||
|
|
||||||
|
Currently, we store lockfiles in-tree. This is bad, for all the reasons mentioned above, and so that is the only prior art I've considered while writing this.
|
||||||
|
|
||||||
|
However, you could consider projects like `node2nix`, `cargo2nix`, and others, prior art for this,
|
||||||
|
but that involves translating the lockfile and storing that representation in the nixpkgs repo,
|
||||||
|
which still contributes to the size issue mentioned. Further, this also has a larger impact on
|
||||||
|
evaluation time, as some of these fetchers have each dependency as their own separate derivations,
|
||||||
|
which means a lot of derivations could be instantiated and fetched, which does pose an
|
||||||
|
outsized(though relatively minor) disk size impact due to the ratio of metadata to derivation size.
|
||||||
|
|
||||||
|
# Unresolved questions
|
||||||
|
|
||||||
|
[unresolved]: #unresolved-questions
|
||||||
|
|
||||||
|
Lots of it! I don't know any particular questions that remain unanswered at the moment, but I would be glad to answer those if they come up.
|
||||||
|
|
||||||
|
# Future work
|
||||||
|
|
||||||
|
[future]: #future-work
|
||||||
|
|
||||||
|
This may create additional maintenance burdens in the future, with an additional repo being part of the nixpkgs process in some cases, but I have tried to design this with an eye for maintainability over time.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue