Erreur 401 à l’installation d’une dépendance depuis le registre privé de GitHub avec npm v7

Au quotidien, sur l’une des briques logicielles sur laquelle je travaille, nous avons dans les dépendances de notre projet Node, une bibliothèque partagée à partir du registre privé de GitHub. Après une mise à jour de npm de la version 6 à la version 7, j’ai commencé à voir apparaître des erreurs 401 à l’exécution de la commande npm install. Ayant d’autres sujets plus urgents à traiter, nous avons donc pris la décision de rester sur la version 6 de npm.

Quelques mois après, avec le passage de Node 16 en version LTS et la publication de npm version 8, je me suis penché une nouvelle fois sur la question. En changeant la syntaxe de mon fichier .npmrc et en utilisant le nouveau format de token GitHub déployé il y a plusieurs semaines, les erreurs ont fini par disparaître. Voici donc la syntaxe utilisée:

//npm.pkg.github.com/:_authToken=ghp_xxxxxxxxxxxxxxxxxxxx
@scope:registry=https://npm.pkg.github.com

J’ai été devancé alors que je m’apprêtais à partager la disparition des erreurs avec cette configuration dans le ticket de bug dédié, où nous apprenons que cette correction fonctionne correctement pour les versions 6, 7 et 8 de npm.

Installation d’un package npm depuis un dépôt GitLab

Pour utiliser un dépôt hébergé sur sa propre instance GitLab, rien de bien compliquer, si ce n’est le protocole à utiliser : git+https et pas juste https (ou git+http au lieu de http).

Ce qui nous donne pour la branche master d’un projet :

{
  ...
  "dependencies": {
    "mon-projet": "git+https://<mon-domaine-gitlab>/<user>/<mon-projet>#master",
    ...
  }
}

Illustration pour récupérer une configuration eslint sous forme de module dans son dépôt propre :

{
  ...
  "devDependencies": {
    "eslint-config-unicoda": "git+https://gitlab.unicoda.com/vvision/javascript-convention#master",
    ...
  }
}

[NPM] Wrong python executable at install

In case you get an error similar to this when trying to npm install :

Error: Python executable "python" is v3.4.2, which is not supported by gyp.

You should tell npm which executable to use with the following command:

npm config set python python2

If you are on ArchLinux, you’re likely to encounter this problem since the default python is python3. Fortunately, it’s easy to fix.

Proxy

Lorsqu’on travaille derrière un proxy, on se retrouve vite à devoir configurer nos outils pour être certain que leur trafic passera bien par celui-ci. Voici donc quelques paramètres de configuration pour répondre à ce problème.

GNU/Linux

Les variables d’environnement qui nous intéresse sont les suivantes:

  • http_proxy
  • https_proxy
  • ftp_proxy
  • no_proxy

On peut également les retrouver en majuscule: HTTP_PROXY par exemple.

La configuration s’effectue de la manière suivante dans un terminal:

export http_proxy=http://yourproxyaddress:proxyport
export no_proxy='127.0.0.1, *.local'

Pour visualiser le contenu d’une variable:

echo $http_proxy

GNOME

gsettings set org.gnome.system.proxy ignore-hosts "['127.0.0.1','*.local' ]"

APT-GET/APTITUDE

Si aptitude n’utilise pas le proxy défini au niveau système pour une raison ou une autre, on peut modifier le fichier /etc/apt/apt.conf pour y ajouter la ligne suivante:

Acquire::http::Proxy "http://yourproxyaddress:proxyport";

GIT

git config --global http.proxy http://yourproxyadress:port
git config --global https.proxy http://yourproxyaddress:port

Si le proxy bloque le protocole git://, on force l’utilisation de http:// :

git config --global url."http://".insteadOf git://

Et en cas de problème avec le protocole https://, on peut envisager :

git config --global http.sslVerify false

WINDOWS

NPM

Dans le fichier .npmrc, ajouter les lignes:

proxy=http://yourproxyadress:port
strict-ssl = false

BOWER

Dans le fichier .bowerrc, ajouter les lignes:

{
  "proxy":"http://yourproxyadress:port",
  "https-proxy":"http://yourproxyadress:port"
}

NPM: noproxy Configuration

For security reasons, every firms are generally using a proxy to manage their internet connection. Coding behind a proxy is fine. Most softwares are able to deal with it. You just have to set it in the environment variable of your GNU/Linux OS or directly in the software.

But there is one problem. Because every request must go through the proxy, it’s impossible to request url based in the internal network. There is only one solution: disable proxy, make request, enable proxy. If you are using npm until now, that’s what you have to do.

In order to make this process easier, I’ve made a pull request which add a noproxy configuration. When npm fetches a package from a given url, the hostname is compared with noproxy configuration. If there is a match, the request is made without proxy, if not proxy is used.

The noproxy configuration looks for a variable named « noproxy » in npm configuration.
« noproxy » is a string containing hostnames. So, this list of hostnames will not ever go through a proxy.
Code concerned:

var proxy = null
if(npm.config.get("noproxy").search(remote.hostname) === -1) {
  if (remote.protocol !== "https:" || 
      !(proxy = npm.config.get("https-proxy"))) {
    proxy = npm.config.get("proxy")
  }
}

var opts = { url: remote
          , proxy: proxy
          , strictSSL: npm.config.get("strict-ssl")
          , ca: remote.host === regHost ? 
                                npm.config.get("ca") : undefined
          , headers: { "user-agent": npm.config.get("user-agent") }}

var req = request(opts)

At the moment, I’m still waiting for Isaacs to add the pull request in npm.
I hope it will be added soon.

Update:                                                                                                                                     Isaacs has pointed out that it’s good for the npm bit but some modifications are still needed in npm-registry-client and npmconf . So here are new additions:

  • npmconf:
 , "noproxy" : process.env.NO_PROXY || process.env.no_proxy ||  "null"
 , "no-proxy" : ["null", String]
  • npm-registry-client:
  var p = this.conf.get('proxy')
  var sp = this.conf.get('https-proxy') || p
  var np = this.conf.get('noproxy')

  if(np.search(remote.hostname) === -1) {
    opts.proxy = remote.protocol === "https:" ? sp : p
  }

I hope everything is now in order so that noproxy configuration can be added to npm :).