jshttp / content-type

Create and parse HTTP Content-Type header
MIT License
131 stars 27 forks source link

lchown /node_modules/content-type/HISTORY.md: invalid argument. #21

Closed playground closed 1 year ago

playground commented 1 year ago

I have a docker image that includes an express server v4.18.2. It's failing on HISTORY.md every time.

4e7e0215f4ad: Pull complete f206d87fdd12: Pull complete 5d2b14b7402b: Pull complete 85cbc4392f0e: Pull complete 77411fe1f4da: Pull complete 23f844e44e9e: Pull complete 4334efab300b: Pull complete 6496e772977a: Pull complete 3877be6b3e68: Pull complete b65ae8fc6c48: Extracting [==================================================>] 26.25MB/26.25MB 3be3ca4d8f67: Download complete 02847af5dbd7: Download complete 4397228b905c: Download complete docker: failed to register layer: Error processing tar file(exit status 1): lchown /node_modules/content-type/HISTORY.md: invalid argument.

Nitamet commented 1 year ago

Got the same issue with this package and express. It seems like this file has an ownership issue. Despite this, the package used to work in Docker, but stopped due to: https://github.com/npm/cli/blob/latest/CHANGELOG.md#900-pre6-2022-10-19

npm will no longer attempt to modify ownership of files it creates
this package no longer attempts to change file ownership automatically
this package no longer attempts to change file ownership automatically

Switching to the user node before running npm install helped me.

FROM node:alpine
...
USER node
...
RUN npm install
dougwilson commented 1 year ago

Sorry for the issue in this package. If someone can provide specific instructions on what to do or to make a pull request to fix it, it would be much appreciated, as I don't know what is wrong or how to fix.

clearly-tyler-whitney commented 1 year ago

I also ran across this issue in the context of a failed container pull. It looks like there are a couple of factors working together to create a problem.

The first is the high UID (1516583083) of the owner of files in the content-type-1.0.4.tgz archive as published to npmjs.org, which we can pull with:

$ npm pack content-type
npm notice 
npm notice 📦  content-type@1.0.4
npm notice === Tarball Contents === 
npm notice 436B  HISTORY.md  
npm notice 1.1kB LICENSE     
npm notice 2.8kB README.md   
npm notice 4.8kB index.js    
npm notice 1.1kB package.json
npm notice === Tarball Details === 
npm notice name:          content-type                            
npm notice version:       1.0.4                                   
npm notice filename:      content-type-1.0.4.tgz                  
npm notice package size:  4.7 kB                                  
npm notice unpacked size: 10.2 kB                                 
npm notice shasum:        e138cc75e040c727b1966fe5e5f8c9aee256fe3b
npm notice integrity:     sha512-hIP3EEPs8tB9A[...]c9mOUJiPBhPXA==
npm notice total files:   5                                       
npm notice 
content-type-1.0.4.tgz

And inspect, without extracting:

$ tar 2>/dev/null -tvf content-type-1.0.4.tgz
-rw-r--r-- 1516583083/0   1070 2017-09-11 17:32 package/package.json
-rw-r--r-- 1516583083/0   2796 2017-09-11 12:57 package/README.md
-rw-r--r-- 1516583083/0   1089 2017-09-11 12:57 package/LICENSE
-rw-r--r-- 1516583083/0   4809 2017-09-11 17:31 package/index.js
-rw-r--r-- 1516583083/0    436 2017-09-11 17:34 package/HISTORY.md

As mentioned by @Nitamet, the second is that the npm CLI no longer changes file ownership of extracted files to the UID:GID of the process owner when unpacking to node_modules. Hence, the tar package is allowed to decide, and when running as root/UID 0, it prefers to preserve ownership.

So, if a container image which adds this package with an npm install stage that runs as root using npm@^9 gets pulled by a non-root consumer (Podman in my case, however I imagine Docker in rootless mode is affected as well), an error results when the container image tool chain is asked to write/manipulate files with a UID:GID that the user cannot remap/lay claim to.

Whether a high UID was intended or not at the time 1.0.4 was published some years ago (2017-09-11T21:42:36.476Z), none of the current top 10 package archives on npmjs.org have any files owned by a UID:GID other than 0:0, so if there's a good reason for setting the UID as 1516583083, I don't know what it would be. Version 1.0.3 published 17 hours prior also appears "normal" in this regard.

As for solutions, @Nitamet's fix works but I might argue that just bumping package.json to 1.0.5, rebuilding, and publishing (after ensuring no more funky file ownership in the .tgz archive) would address the problem more broadly.

EDIT: Linking to https://github.com/moby/moby/issues/43576

dougwilson commented 1 year ago

Thanks @clearly-tyler-whitney ! As far as publishing, all I do is run npm publish from my Windows machine and npm just does everything... IDK anything about the UID:GID numbers, as I don't think I can even changes those on Windows or however it's done. I can always publish a new version, but who is to say it's not just the same again? Is there a way I can check before publishing it so I don't have to keep publishing new versions in a trial/error type of thing?

Edit: to be clear, I have no issue releasing a new patch release if that fixes it. Just want to know how to verify that before I make a new release is all.

clearly-tyler-whitney commented 1 year ago

Running npm pack with no arguments in the project root builds the package .tgz archive from source without pushing to the registry. As above, inspecting the resulting archive with tar will indicate the UID/GID. Assuming it looks good, all that remains is to npm publish the archive file by name, i.e. npm publish content-type-<version>.tgz.

dougwilson commented 1 year ago

Sweet, thanks! Didn't know that. Looks like I have further investigation to do to figure out how to generate a proper archive:

$ npm pack
npm notice
npm notice 📦  content-type@1.0.4
npm notice === Tarball Contents ===
npm notice 436B  HISTORY.md
npm notice 1.1kB LICENSE
npm notice 2.8kB README.md
npm notice 4.8kB index.js
npm notice 1.1kB package.json
npm notice === Tarball Details ===
npm notice name:          content-type
npm notice version:       1.0.4
npm notice filename:      content-type-1.0.4.tgz
npm notice package size:  3.7 kB
npm notice unpacked size: 10.3 kB
npm notice shasum:        6066218a3c448057dedc7a67b18055e9f77b6f35
npm notice integrity:     sha512-vfuVp8iklNdET[...]uvO7QGG8wqnoQ==
npm notice total files:   5
npm notice
content-type-1.0.4.tgz

$ tar -tvf content-type-1.0.4.tgz
-rw-r--r-- 1673653032/0   1089 1985-10-26 04:15 package/LICENSE
-rw-r--r-- 1673653032/0   4839 1985-10-26 04:15 package/index.js
-rw-r--r-- 1673653032/0   1070 1985-10-26 04:15 package/package.json
-rw-r--r-- 1673653032/0    436 1985-10-26 04:15 package/HISTORY.md
-rw-r--r-- 1673653032/0   2840 1985-10-26 04:15 package/README.md
clearly-tyler-whitney commented 1 year ago

What version of npm are you using above? I tried 9.3.0 on Windows 10 and Fedora 37 and wasn't able to reproduce this.

dougwilson commented 1 year ago

I had just installed the latest Node.js LTS a few days ago, so looks like

$ npm -v
8.19.3

Edit: I will install the latest "current" Node.js. I don't need to be on LTS, was just being lazy, haha :)

dougwilson commented 1 year ago

Thanks everyone and especially @clearly-tyler-whitney ! Version 1.0.5 is now published to npm with a 0 uid and 0 gid in the tarball. For those using Express.js, the dependency is a range that will pick up 1.0.5 automatically, you may just need to update your package-lock file.