Hacker News new | ask | show | jobs
by kibwen 3736 days ago

  > npm encourages the use of semver, or semantic 
  > versioning. With semver, dependencies are not locked to 
  > a certain version by default. For any dependency of a 
  > package, the dependency author can push a new version of 
  > the package.
I don't see how this has anything to do with semver. Semver doesn't say anything about not locking dependencies to a certain version (i.e., locking to a specific version is totally legal), nor does it have anything to do with allowing package authors to push new versions of their packages (I'm not even sure how to parse this sentence, really... should it be impossible to ever push new versions of a package? (EDIT: maybe it's suggesting there should be a central review process, like the iOS App Store?)).

In fact, the semver spec doesn't even advocate automatically upgrading when new patch versions are released:

"As a responsible developer you will, of course, want to verify that any package upgrades function as advertised. The real world is a messy place; there’s nothing we can do about that but be vigilant."

http://semver.org/#why-use-semantic-versioning

4 comments

When you `npm install` a package by default when other users `npm install` it it will install the most recent patch version - even if it's different from the one you installed. So if you install dependencies through `npm install --save` which is the default and advertized way - you can get completely different code between production and staging.

As a library maintainer, patches breaking the library is something that happens (not often, but still) - testing can eliminate a lot but not all bugs.

I'm not trying to dispute that a problem exists, only that semver is a red herring here. It seems like the problem that you describe doesn't have to do with semver, rather that it has to do with npm lacking something like lockfiles.
It is semver compounded with the "^x.y.z" version requirements for dependencies that NPM uses as a default when a package author `npm install --save` something.

When someone else installs that package it will bump y or z if `x > 0`, and z if `x == 0 && y > 0` for all dependencies.

You can manually freeze deps to 'x.y.z'.

The main problem is the "^" default.

The main problem is the "^" default.

This is true.

A secondary problem is the culture of having so many dependencies, which has been much discussed this past week. Even if you lock everything to a static version for consistency, how many people really know which packages from which sources they are relying on to build their system today? Presumably you trust your direct dependencies, and they in turn trust theirs, and so on, but all it takes is one package five levels deep in the tree where the developer was in a rush and npm install'd something vulnerable or malicious to compromise the entire tree.

Even if you manually freeze deps to 'x.y.z', the deps of your deps might still be specified with '^'. Ideally you'd shrinkwrap, and commit node_modules to your repo. (In case packages get deleted)
What's the point of shrinkwrap if you're commiting node_modules? And also why not use a package manager like RPM, Debian, etc so you don't bloat your Git history? (Genuine questions, I know many advocate what you're saying).
Vendoring by storing node_modules works great. It's not necessary to shrinkwrap in that case -- all the same data is derived from the node_modules directory tree. For production, I often use a separate git repo for storing node_modules, referenced as a submodule of the code repo. This has two advantages:

* You retain history for your full dependency tree separately from your codebase.

* Every commit of your code repo exactly specifies the contents of its dependency tree, since the submodule references your deps repo by commit hash.

what is the recommended way to globally change that default?

    npm config set save-exact true
> npm lacking something like lockfiles

`npm shrinkwrap --dev` will give you a shrinkwrap file, with dev-deps also locked. Still, it took me 3 months of heavy Node usage before I found that out. Over in PHP land, while Composer has its own set of faults, it's at least generating a lockfile automatically.

> you can get completely different code between production and staging.

That's not NPM's fault, its the fault of the way you deploy code. Even if you locked down a version, git is mutable so someone could change their code. That's why I "rsync" the code to production, so I know its the same as development.

It's also why one wag suggested using Twitter (which "doesn't have an edit button") as a repository:

* https://gist.github.com/rauchg/5b032c2c2166e4e36713

I mean, don't use `npm install --save` then. I'm not really sure why people started using it in the first place, it's such a lazy thing to do. Instead, add it to your package.json yourself with the exact specific version you want (none of the ^a.b.c funny business).
Instead, add it to your package.json yourself with the exact specific version you want

Unfortunately, the same problem then arises for your dependencies. If any of them don't specify exact versions, you are still vulnerable to getting uncontrolled changes.

This is why things like npm shrinkwrap exist, but it's still crazy that NPM's default behaviour is the uncontrolled case.

Yes, libraries should specify exact versions as well, it's insane that they don't.
or rather, npm install --save-exact :)

then upgrade with npm shrinkwrap

echo "save-prefix=''" > ~/.npmrc
When I bootstrap code I npm install --save, I have 10 packages I usually need right off the bat and I don't want to start an investigation every time I do this.
I think that semver encourages unaudited updates by acting as a substitute for auditing in practice. Obviously the spec doesn't say that you should blindly accept all bugfix updates, but in practice many people do. I often do.
Everyone does and I don't think we will be able to change that.

It would be nice if there would be a tool that would allow developers to mark a new release as safe. Every package would have it's social safety score and you could decide if you want to investigate a release further.

What do you mean by 'safe'? There is such a tool built-into semver -- it's releasing with a patch or minor version bump! Which means it should be entirely backwards compatible with the previous release. Do you mean something else by 'safe'?

I think the issue parent is worried about is if you can't trust the author's declaration of safety.

I think davnn meant a voting mechanism to allow other devs (besides the package's publisher) to vouch for its safety.

At least that's how I interpreted "social safety score".

Ah, I see. I guess that might be interesting. I suspect it would have to get very complicated supporting 'chains of trust' and possibly crypto implementation, to avoid gaming by someone who wanted to make their dangerous code look voted "safe" by lots of people.
Exactly!
> "As a responsible developer you will, of course, want to verify that any package upgrades function as advertised. The real world is a messy place; there’s nothing we can do about that but be vigilant."

Being a programmer you may, of course, try to automate that verification process with something like greenkeeper.io. That opens up its own kind of exploit opportunities.

https://twitter.com/davemethvin/status/711181897712455680

It's poorly worded. The real problem is that _by default_ npm doesn't pin you to an exact version of a dependency.