Установите учетные данные npm для 'npm login' без чтения ввода из stdin

Я пытаюсь автоматизировать npm publish внутри контейнера Docker, но у меня возникают проблемы, когда команда npm login пытается прочитать имя пользователя и адрес электронной почты из приглашений:

npm login << EOF
username
password
email
EOF

Он работает в терминале Bash, но не в контейнере без открытого stdin, и показывает следующее сообщение об ошибке:

Username: Password: npm ERR! cb() never called!
npm ERR! not ok code 0

По словам npm-adduser:

Имя пользователя, пароль и адрес электронной почты считываются из приглашений.

Так как я могу запустить npm login не открывая стандартный ввод?

Ответ 1

TL; DR: сделать HTTP-запрос непосредственно в реестр:

TOKEN=$(curl -s \
  -H "Accept: application/json" \
  -H "Content-Type:application/json" \
  -X PUT --data '{"name": "username_here", "password": "password_here"}' \
  http://your_registry/-/user/org.couchdb.user:username_here 2>&1 | grep -Po \
  '(?<="token": ")[^"]*')

npm set registry "http://your_registry"
npm set //your_registry/:_authToken $TOKEN

обоснование

За кулисами npm adduser делает HTTP-запрос в реестр. Вместо того, чтобы заставлять adduser вести себя так, как вы хотите, вы можете сделать запрос напрямую в реестр, не проходя через cli, а затем установить токен аутентификации с npm set.

Исходный код предполагает, что вы можете сделать запрос PUT на http://your_registry / -/user/org.couchdb.user:your-username со следующей полезной нагрузкой

{
  name: username,
  password: password
}

и это создаст нового пользователя в реестре.

Большое спасибо @shawnzhu за то, что он нашел более чистый подход к решению проблемы.

Ответ 2

Сценарий ожидания работал для меня. Вы должны убедиться, что ожидаемый установлен, эта команда должна сделать это для ubuntu:

apt-get install expect-dev

Ваш скрипт может выглядеть примерно так (npm_login_expect):

#!/usr/bin/expect -f

# set our args into variables
set i 0; foreach n $argv {set "p[incr i]" $n}

set timeout 60
#npm login command, add whatever command-line args are necessary
spawn npm login
match_max 100000

expect "Username"    
send "$p1\r"

expect "Password"
send "$p2\r" 

expect "Email"
send "$p3\r"

expect {
   timeout      exit 1
   eof
}

И затем назовите это так:

expect -f npm_login_expect myuser mypassword "[email protected]"

Ответ 3

Я принял несколько иной подход, который, похоже, отлично работает. Для начала вам понадобится токен аутентификации. Это легко получить локально запущенным npm adduser а затем захватить сгенерированный токен из вашего ~/.npmrc находящегося в вашей папке пользователя. Чтобы быть аутентифицированным на вашем сервере ci, этот токен аутентификации должен быть добавлен к URL-адресу реестра в пользователе .npmrc (аналогично тому, как он был локально), а не .npmrc находящемуся в репо, поэтому они отлично работали, как шаги сценария в моей конфигурации CI

- echo "//<npm-registry>:8080/:_authToken=$AUTH_TOKEN" > ~/.npmrc
- npm publish

где AUTH_TOKEN хранится как секретная переменная в ваших настройках. Хороший способ проверить это - заменить npm publish на npm whoami для тестирования и убедиться, что он успешно выполнил вход в систему.

Вот моя вся публикация конфигурации

publish:
  stage: deploy
  only:
    - tags
  script:
    - yarn run build
    - echo "//<npm-registry>:8080/:_authToken=$NPME_AUTH_TOKEN" > ~/.npmrc
    - npm publish
    - echo 'Congrats on your publication!'

Я использую gitlab-ci, но я не понимаю, почему это не распространяется на какое-либо приложение ci.

Ответ 4

npm-cli-login позволяет вам войти в NPM без STDIN.

Для того, чтобы установить запустить

npm install -g npm-cli-login

пример использования: -

npm-cli-login -u Имя пользователя -p Пароль -e [email protected] -r https://ваш -p rivate -r egistry-link

Ответ 5

Это основано на ответе Александра Ф. Это просто упрощенная версия предоставленного им кода, смешанного с примером кода, предоставленного npm-registry-client.

"use strict";

var RegClient = require('npm-registry-client')
var client = new RegClient()
var uri = "https://registry.npmjs.org/npm"
var params = {timeout: 1000}

var username = 'my.npm.username'
var password = 'myPassword'
var email = '[email protected]'

var params = {
  auth: {
    username,
    password,
    email
  }
};

client.adduser(uri, params, function (error, data, raw, res) {
  if(error) {
    console.error(error);
    return;
  }
  console.log('Login succeeded');
  console.log('data: ${JSON.stringify(data,null,2)}');
  console.log('NPM access token: ${data.token}');
});

Ответ 6

Трудно поверить, что после этого времени решения для npm по-прежнему не существует. Уверен, что вы можете взять токен один раз и использовать его для всех ваших потребностей в CI, но как насчет последствий безопасности никогда не истекающего токена? И что, если однажды админы решат, что токены должны истечь?

Ниже представлено мое хакерское решение javascript с использованием пакета npm-registry-client. Просто передайте аргумент json string, и он войдет в систему и напишет файл .npmrc в ваш текущий .npmrc. Чтобы выйти из npm logout выполните обычную процедуру npm logout.

var client = new (require('npm-registry-client'))({});
var std_in = JSON.parse(process.argv[2]);

if (std_in.uri === undefined) {
    console.error('Must input registry uri!');
    return;
}

// fix annoying trailing '/' thing in registry uri
if (std_in.uri[std_in.uri.length - 1] !== '/') {
    std_in.uri = std_in.uri + '/';
}

if (std_in.scope === undefined) {
    console.error('Must input scope!');
    return;
    //std_in.scope = '@my-scope'; // or add default scope of your own
}

if (std_in.scope[0] !== '@') {
    std_in.scope = '@' + std_in.scope;
}

client.adduser(std_in.uri, std_in.params, function(err, data, raw, res) {
    if (err) {
        console.error(err);
        return;
    } 
    require('fs').writeFileSync('.npmrc', '${std_in.scope}:registry=${std_in.uri}\n//${(std_in.uri.split('//'))[1]}:_authToken=${data.token}');
});

Пример ввода:

{ 
    "uri": "https://my-nmp.reg",
    "scope": "@my-scope",
    "params": {
        "auth": {
            "username": "secret-agent",
            "password": "12345",
            "email": "[email protected]"
        }
    }
}

Ответ 7

Одним из решений является получение токена и обновление ~/.npmrc

export ARTIFACTORY_TOKEN='curl --silent --show-error --fail -u $ARTIFACTORY_USERNAME:$ARTIFACTORY_API_KEY https://artifactory.my.io/artifactory/api/npm/auth | \
grep -oP '_auth[\s?]=[\s?]\K(.*)$''

echo "@my:registry=https://artifactory.my.io/artifactory/api/npm/npm-release-local/" > ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:_auth=${ARTIFACTORY_TOKEN}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:email=${ARTIFACTORY_USERNAME}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:always-auth=true" >> ~/.npmrc

Это предотвращает проблемы с получением пакета @scope от npmjs

Ответ 8

Вместо этого вы можете использовать сценарий ожидания или написать сценарий узла, который использует pty.js.

Ответ 9

Это сработало на одном из моих рабочих мест в Дженкинсе:

шаги

  1. Сгенерируйте _auth из учетных данных реестра npm на базе 64, используя оболочку для безопасности:
    echo -n 'myuser:mypassword' | openssl base64
    Result will be something like : eWFob29vb2E=
  1. Задайте URL реестра npm и _auth до установки npm...
    npm config set registry https://nexus-acme.com/repository/npm-group/
    npm config set _auth eWFob29vb2E=

Это все. Вы можете запустить npm install, и ваши личные модули будут загружены.

Ответ 10

npm set //<registry>/:_authToken $TOKEN

Пример для реестра пакетов Github:

npm set //npm.pkg.github.com/:_authToken $GITHUB_TOKEN

Это самое простое решение, которое я нашел.