-
Notifications
You must be signed in to change notification settings - Fork 169
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
feat: download the latest version instead of a pinned one #134
Conversation
0a588c3
to
c33fa1d
Compare
README.md
Outdated
@@ -106,6 +113,8 @@ This command will retrieve the given package manager from the specified archive | |||
|
|||
- `COREPACK_ENABLE_NETWORK` can be set to `0` to prevent Corepack from accessing the network (in which case you'll be responsible for hydrating the package manager versions that will be required for the projects you'll run, using `corepack hydrate`). | |||
|
|||
- `COREPACK_NO_LOOKUP` can be set in order to instruct Corepack not to lookup on the remote registry for the latest version of the selected package manager. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably find a better name for this env variable, I don't think one could infer what it's doing from the name only. Does anyone has suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to understand the difference between COREPACK_ENABLE_NETWORK=0
and COREPACK_NO_LOOKUP=1
? In theory I would expect no network to behave the same since corepack ships with Known Good Versions but I must be overlooking a use case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When COREPACK_NO_LOOKUP
is set, Corepack will use the version defined in config.json
instead of asking the npm registry for the most up-to-date version. COREPACK_ENABLE_NETWORK
can disable all access to the network, both for finding what's the most up-to-date version number and to download the tarball.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is config.json
available to configure by the user of corepack or is it just internals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only internals, bundled in the corepack executable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about COREPACK_IGNORE_LATEST?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with COREPACK_DEFAULT_TO_LATEST
which is true by default, and is set to 0
to use the value in config.json
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about using “default” as a verb here.
How about COREPACK_ENABLE_FETCH_LATEST=0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like the naming to make clear that it's only relevant if there's no local clue on what version to use. ENABLE_FETCH_LATEST
could mean that the latest is always downloaded, or at least that's how I read it.
Not sure about using “default” as a verb here.
I'm not a native english speaker, so genuine question: is it incorrect or something to use "default" as a verb?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s not incorrect, just that “default” can be a verb or a noun. It’s probably fine 👍
|
||
The Known Good Releases can be updated system-wide using the `--activate` flag from the `corepack prepare` and `corepack hydrate` commands. | ||
If there is no Known Good Release for the requested package manager, Corepack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what case would there be no Known Good Release?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon the first time Corepack is run with a given package manager. The idea behind this PR would be not to rely on what version is set on config.json
but instead get the most up-to-date version from npm registry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How often does it check the registry? Does it check every time you invoke yarn/pnpm/npm because that seems slow. Especially if I just want to do npm run <script>
which should work offline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, only the first time, at which point it saves it as Known Good Release. Users can then update (or downgrade) that version by using corepack prepare
or corepack hydrate
(e.g. corepack prepare pnpm@latest --activate
to get the latest pnpm by default). We could make an automated process for the Known Good Version to expire after some time, but that's not part of this initial implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I understand now 👍
I think expiring would could be confusing. I also think this any auto update could be confusing because it no longer ties the package manager version to the corepack version (or node version for that matter).
I think it’s best to let the user decide when to upgrade and perhaps provide better docs how to upgrade (this isn’t super clear today). Without corepack, this is handled with a notification that says something like npm i -g npm@latest.
Has any of this behavior been reviewed by the npm team? I think they had some ideas about Know Good Release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think this any auto update could be confusing because it no longer ties the package manager version to the corepack version (or node version for that matter).
Well that's the reason Corepack exists, because the Node.js TSC doesn't want to have specific version of a package manager tied in with a specific Node.js version – specifically, several Node.js TSC members have expressed that the reason they are supportive of Corepack is to get rid of having to do security releases every time a vulnerability is reported in npm rather than node
itself.
So the auto-lookup during the first use has to be the default behavior.
I think it’s best to let the user decide when to upgrade and perhaps provide better docs how to upgrade (this isn’t super clear today). Without corepack, this is handled with a notification that says something like npm i -g npm@latest.
Yes that makes sense, letting the end-user in control is very much the goal here. So instead of npm i -g npm@latest
, users would type corepack prepare npm@latest --activate
, which is arguably quite similar. Improving docs is of course always a goal.
Has any of this behavior been reviewed by the npm team? I think they had some ideas about Know Good Release.
The npm team hasn't shown much interest in the development of Corepack, so I don't think they have.
export async function fetchLatestStableVersion(spec: RegistrySpec) { | ||
switch (spec.type) { | ||
case `npm`: { | ||
const {[`dist-tags`]: {latest}, versions: {[latest]: {dist: {shasum}}}} = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this consider the major version? What about when npm 7 bumped to npm 8 to drop support for node 12. Imagine if corepack existed then and suddenly npm stopped working because of the automatic fetch latest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s worth discussing, but imo it’s ok to ignore that for the initial implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's acceptable to me (Yarn isn't impacted that much since we don't make very frequent / risky releases to 1.22 anyway). Maybe we should wait a bit to see if @zkochan has an opinion?
Sorry for not answering. I think it is OK to ship the latest pnpm. Thanks |
I have some concerns about this change.
|
The workaround is to set a specific version in the project
Contributions are welcome to improve this workflow. |
Of course there are workarounds. But good defaults matter, and I’m proposing that the default should remain the secure known-good version. A user who discovers they need a later version than the known-good version is in a position to go read the corepack documentation and configure it appropriately. (Most likely what they really want is to set a version in Meanwhile, a user who unexpectedly gets a later (or earlier!) version when they didn’t make a change—they just re-ran the same script on a different system—is in a much more confusing position. They could very well be trying to get dozens of things working at the same time; they might not be an expert on the particular part of the script that failed, and might not even realize in the moment that their Yarn or pnpm is coming from corepack. Could they (or someone else who wrote the script) have had the foresight to reconfigure corepack more deterministically? Of course, but a trap that could be avoided is still a trap; good defaults matter. Users don’t expect that installing a deterministic version of A should give them a nondeterministic version of B. We shouldn’t force them to remember or disable an exception to this rule. |
That’s exactly what users in this ecosystem expect - determinism, for better or worse, is simply not an expectation (beyond a lockfile), and anything else is surprising and very inconvenient, and in this case, causes many more people to have a buggy or insecure version of their package manager CLI. |
That's the catch, the known-good version is more likely to be less secure than the latest one. I agree with Jordan, I don't think most users care about that kind of determinism (otherwise, they would set a specific version either system-wise, or at the project level). Also, as I wrote in #134, the reason Corepack is integrated in the Node.js project is that it make decouple what version of npm comes bundled with the Node.js installation, users can get a secure version of their package manager without Node.js needing to issue a security update. |
What makes you think that users are not setting a specific version? I see many projects using |
Having a fixed default version would not change anything for those users, since they're setting a specific one anyway, right? What I'm saying is that in my experience, folks expect to get the latest version by default, and they are used to set a specific version instead if/when they want determinism (and they should, that's why we added the |
This change isn’t giving them the latest version. It’s giving them the latest version as of the time they ran But the security concern isn’t just that they might get an older version—it’s that skipping the hash protection provided by known-good versions may make it easier for an attacker to maliciously alter the code in transit, since HTTPS can much easier to defeat in environments with intercepting proxy middleboxes and dubious certificate authorities. |
I reckon the current setup is not ideal, it's a first implementation and I'd be delighted to see it improve in a way that's more convenient for the users. Contributions would be much welcome, as we don't have a clear plan on how to give a way for users to update without relying on them remembering to run a command manually on a regular basis.
I think #10 would be a better response to this, as it should give us the best of both worlds. |
This PR ensures that fresh install of Corepack would always use the latest available version for a given package manager.
We probably want to add a command to clear the cache for
lastKnownGood
version (although I think that's more or less whatcorepack prepare
is doing), and/or have a expiracy date for thelastKnownGood
version to make Corepack update the default version from time to time.Fixes: #93