From 6e72a4ea77f987ddc027a25764e586f50b6c3c27 Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Fri, 20 Jul 2018 11:56:55 +1000 Subject: [PATCH 1/6] Support env: and file: prefixes --- hooks/pre-command | 13 ++++++++ tests/pre-command.bats | 68 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/hooks/pre-command b/hooks/pre-command index b6d0e47..3f02201 100755 --- a/hooks/pre-command +++ b/hooks/pre-command @@ -7,6 +7,19 @@ echo '--- Setting up access for :no_entry_sign: :npm: :package:' REGISTRY=${BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY:-'//registry.npmjs.org/'} NPM_TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN} +if [[ $NPM_TOKEN =~ ^file: ]] +then + file=$(echo "$NPM_TOKEN" | cut -f2 -d ':' ) + NPM_TOKEN=$(cat "$file") + + [[ -z $NPM_TOKEN ]] && exit 1 +elif [[ $NPM_TOKEN =~ ^env: ]] +then + env_var_name=$(echo "$NPM_TOKEN" | cut -f2 -d ':' ) + NPM_TOKEN="${!env_var_name}" + [[ -z $NPM_TOKEN ]] && exit 1 +fi + cat > .npmrc << EOF ${REGISTRY}:_authToken=${NPM_TOKEN} save-exact=true diff --git a/tests/pre-command.bats b/tests/pre-command.bats index f24cd93..3a84aba 100644 --- a/tests/pre-command.bats +++ b/tests/pre-command.bats @@ -16,6 +16,71 @@ teardown() { assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' } +@test "reads the token from a file if the file: prefix is used" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_token_file' + echo 'abc123' > my_token_file + + run $PWD/hooks/pre-command + + assert_success + assert [ -e '.npmrc' ] + assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' + + # clean up + rm -fr my_token_file +} + +@test "fails if the file: prefix is used but no file exists" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_missing_file' + + run $PWD/hooks/pre-command + + assert_failure +} + +@test "fails if the file: prefix is used but file is empty" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_empty_file' + + touch my_empty_file + + run $PWD/hooks/pre-command + + assert_failure + + # clean up + rm -fr my_empty_file +} + +@test "reads the token from the environment if the env: prefix is used" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_ENV_VAR' + export MY_ENV_VAR='abc123' + + run $PWD/hooks/pre-command + + assert_success + assert [ -e '.npmrc' ] + assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' +} + +@test "fails if the env: prefix is used but no such variable is defined" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_MISSING_VAR' + + run $PWD/hooks/pre-command + + assert_failure +} + +@test "fails if the env: prefix is used but the value of the variable is empty" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_EMPTY_VAR' + + export MY_EMPTY_VAR="" + + run $PWD/hooks/pre-command + + assert_failure + +} + @test "crates a npmrc file with supplied registry path and token" { export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='abc123' export BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY='//myprivateregistry.org/' @@ -32,4 +97,5 @@ teardown() { assert_failure refute [ -e '.npmrc' ] -} \ No newline at end of file +} + From 0c92d517d8698a74df67fe46b37cad403736ff3a Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Mon, 23 Jul 2018 10:53:14 +1000 Subject: [PATCH 2/6] Update README.md --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f38bfe5..0b63a49 100644 --- a/README.md +++ b/README.md @@ -3,39 +3,77 @@ A [Buildkite plugin](https://buildkite.com/docs/agent/v3/plugins) to allow pipeline steps to easily install private packages from an [npm](https://www.npmjs.com) repository. -Note this plugin should work equally well despite your personal preferences for either `yarn` or `npm`. +Note this plugin should work equally well despite any personal preferences for either `yarn` or `npm`. ## Example -The following pipeline will run `yarn install` (and presumably some private packages). +To read the value from an environment variable named `MY_TOKEN` when the plugin executes, use the `env:` prefix. ```yml steps: - command: yarn install plugins: - seek-oss/private-npm#v1.0.1: - token: ${NPM_TOKEN} + seek-oss/private-npm#v1.1.1: + token: "env:MY_TOKEN" ``` +To read the value from a file named `my_token_file`, use the `file:` prefix. + +```yml +steps: + - command: yarn install + plugins: + seek-oss/private-npm#v1.1.1: + token: "file:my_token_file" +``` + +Alternatively you can read the token directly from any value exposed toxs your `pipeline.yml` file. However, this +approach is discoraged in favour of using with the `env:` or `file:` prefix. This functionality remains in the interest + of backwards compatibility. + +```yml +steps: + - command: yarn install + plugins: + seek-oss/private-npm#v1.1.1: + token: ${MY_TOKEN} +``` + + You can also specify a custom npm registry if you are using your own mirror. ```yml steps: - command: yarn install plugins: - seek-oss/private-npm#v1.0.1: - token: ${NPM_TOKEN} + seek-oss/private-npm#v1.1.1: + token: ${MY_TOKEN} registry: //myprivatenpm.com/ ``` ## Configuration ### `token` (required) -The value of the NPM token. +The value of the NPM token. Using the prefix `env:` of `file:` changes the behaviour of how the token is read. By +omitting the prefix, the value will be read from a variable which is available to the Buildkite YAML parsing context. +This value is interpolated when the YAML configuration is parsed by the Buildgent agent and provided to the plugin "as +is". + +Using the `env:` prefix delays reading the value from the agent environment until the plugin executes. + +Using the `file:` prefix will attempt to read the value from a file. + +The prefix variants are recommended if you are using a secrets manager or some other kind of late variable binding +mechanism to configure your agent's environment. Please see the examples for useage. -Example: `${NPM_TOKEN}` +Example: `${MY_TOKEN}` +> **NOTE:** Don't put your tokens into source control. Don't use web interfaces you don't control to inject them into +> your environment either. Rather use a Secrets Manager. If you are an AWS user, perhaps consider the +> [aws-sm-buildkite-plugin](https://github.com/seek-oss/aws-sm-buildkite-plugin) which works well with this plugin. -> *NOTE* It's bad security practise to put your secrets into source control. A better idea is to use environment variables. +> **NOTE:** There is anecdotal evidence to suggest that using `NPM_TOKEN` as the variable name containing the +> token can intermittently cause the token to become empty. It is advised to use a different name as has been done in +> these docs. ### `registry` (optional) The path to a private npm repository. Please ensure you supply the trailing `/`! From de50272a1e7ff3b72f93a877e737b99608bdf50f Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Thu, 26 Jul 2018 12:43:53 +1000 Subject: [PATCH 3/6] Negate prefixes in favour of distintive fields --- hooks/pre-command | 21 ++++++++++----------- plugin.yml | 7 +++++-- tests/pre-command.bats | 26 +++++++++++++------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/hooks/pre-command b/hooks/pre-command index 3f02201..fd2a9c9 100755 --- a/hooks/pre-command +++ b/hooks/pre-command @@ -5,22 +5,21 @@ IFS=$'\n\t' echo '--- Setting up access for :no_entry_sign: :npm: :package:' REGISTRY=${BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY:-'//registry.npmjs.org/'} -NPM_TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN} +TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN:=''} +FILE=${BUILDKITE_PLUGIN_PRIVATE_NPM_FILE:=''} +ENV=${BUILDKITE_PLUGIN_PRIVATE_NPM_ENV:=''} -if [[ $NPM_TOKEN =~ ^file: ]] +if [[ -n "${FILE}" ]] then - file=$(echo "$NPM_TOKEN" | cut -f2 -d ':' ) - NPM_TOKEN=$(cat "$file") - - [[ -z $NPM_TOKEN ]] && exit 1 -elif [[ $NPM_TOKEN =~ ^env: ]] + TOKEN=$(cat "${FILE}") +elif [[ -n "${ENV}" ]] then - env_var_name=$(echo "$NPM_TOKEN" | cut -f2 -d ':' ) - NPM_TOKEN="${!env_var_name}" - [[ -z $NPM_TOKEN ]] && exit 1 + TOKEN="${!ENV}" fi +[[ -z $TOKEN ]] && exit 1 + cat > .npmrc << EOF -${REGISTRY}:_authToken=${NPM_TOKEN} +${REGISTRY}:_authToken=${TOKEN} save-exact=true EOF diff --git a/plugin.yml b/plugin.yml index 3aa65a9..a24dc7f 100644 --- a/plugin.yml +++ b/plugin.yml @@ -10,5 +10,8 @@ configuration: type: string token: type: string - required: - - token + env: + type: string + file: + type: string + diff --git a/tests/pre-command.bats b/tests/pre-command.bats index 3a84aba..f44afe4 100644 --- a/tests/pre-command.bats +++ b/tests/pre-command.bats @@ -16,8 +16,8 @@ teardown() { assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' } -@test "reads the token from a file if the file: prefix is used" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_token_file' +@test "reads the token from a file if the file parameter is used" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_token_file' echo 'abc123' > my_token_file run $PWD/hooks/pre-command @@ -30,16 +30,16 @@ teardown() { rm -fr my_token_file } -@test "fails if the file: prefix is used but no file exists" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_missing_file' +@test "fails if the file parameter is used but no file exists" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_missing_file' run $PWD/hooks/pre-command assert_failure } -@test "fails if the file: prefix is used but file is empty" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='file:my_empty_file' +@test "fails if the file parameter is used and the file exists but is empty" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_empty_file' touch my_empty_file @@ -51,8 +51,8 @@ teardown() { rm -fr my_empty_file } -@test "reads the token from the environment if the env: prefix is used" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_ENV_VAR' +@test "reads the token from the environment if the env parameter is used" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_ENV_VAR' export MY_ENV_VAR='abc123' run $PWD/hooks/pre-command @@ -62,16 +62,16 @@ teardown() { assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' } -@test "fails if the env: prefix is used but no such variable is defined" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_MISSING_VAR' +@test "fails if the env parameter is used but no such variable is defined" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_MISSING_VAR' run $PWD/hooks/pre-command assert_failure } -@test "fails if the env: prefix is used but the value of the variable is empty" { - export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='env:MY_EMPTY_VAR' +@test "fails if the env parameter is used but the value of the variable is empty" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_EMPTY_VAR' export MY_EMPTY_VAR="" @@ -92,7 +92,7 @@ teardown() { assert_equal "$(head -n1 .npmrc)" '//myprivateregistry.org/:_authToken=abc123' } -@test "the command fails if the token is not set" { +@test "the command fails if none of the fields are not set" { run $PWD/hooks/pre-command assert_failure From f8ea7aa61895dc1707e4ee336cf3f0bc6fa28fcb Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Thu, 26 Jul 2018 14:43:12 +1000 Subject: [PATCH 4/6] Fix default var assignments --- hooks/pre-command | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks/pre-command b/hooks/pre-command index fd2a9c9..af739eb 100755 --- a/hooks/pre-command +++ b/hooks/pre-command @@ -5,9 +5,9 @@ IFS=$'\n\t' echo '--- Setting up access for :no_entry_sign: :npm: :package:' REGISTRY=${BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY:-'//registry.npmjs.org/'} -TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN:=''} -FILE=${BUILDKITE_PLUGIN_PRIVATE_NPM_FILE:=''} -ENV=${BUILDKITE_PLUGIN_PRIVATE_NPM_ENV:=''} +TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN:-''} +FILE=${BUILDKITE_PLUGIN_PRIVATE_NPM_FILE:-''} +ENV=${BUILDKITE_PLUGIN_PRIVATE_NPM_ENV:-''} if [[ -n "${FILE}" ]] then From 9e976a3cf951b9361cbafb771f5cad21cefd0a82 Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Thu, 26 Jul 2018 16:57:52 +1000 Subject: [PATCH 5/6] Force exclusive use of fields --- hooks/pre-command | 18 +++++++-- tests/pre-command.bats | 88 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/hooks/pre-command b/hooks/pre-command index af739eb..171eff9 100755 --- a/hooks/pre-command +++ b/hooks/pre-command @@ -2,13 +2,19 @@ set -euo pipefail IFS=$'\n\t' -echo '--- Setting up access for :no_entry_sign: :npm: :package:' - REGISTRY=${BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY:-'//registry.npmjs.org/'} TOKEN=${BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN:-''} FILE=${BUILDKITE_PLUGIN_PRIVATE_NPM_FILE:-''} ENV=${BUILDKITE_PLUGIN_PRIVATE_NPM_ENV:-''} +if { [[ -n "${FILE}" ]] && [[ -n "${ENV}" ]]; } \ + || { [[ -n "${FILE}" ]] && [[ -n "${TOKEN}" ]]; } \ + || { [[ -n "${TOKEN}" ]] && [[ -n "${ENV}" ]]; } +then + echo ':no_entry_sign: :npm: :package: Failed! Only one of file, env or token parameters may be set' + exit 1 +fi + if [[ -n "${FILE}" ]] then TOKEN=$(cat "${FILE}") @@ -17,7 +23,13 @@ then TOKEN="${!ENV}" fi -[[ -z $TOKEN ]] && exit 1 +if [[ -z $TOKEN ]] +then + echo ':no_entry_sign: :npm: :package: Failed! A valid NPM_TOKEN could not be determined' + exit 1 +fi + +echo '--- Setting up access for :no_entry_sign: :npm: :package:' cat > .npmrc << EOF ${REGISTRY}:_authToken=${TOKEN} diff --git a/tests/pre-command.bats b/tests/pre-command.bats index f44afe4..6b02078 100644 --- a/tests/pre-command.bats +++ b/tests/pre-command.bats @@ -3,6 +3,13 @@ load "$BATS_PATH/load.bash" teardown() { rm -f .npmrc + unset BUILDKITE_PLUGIN_PRIVATE_NPM_ENV + unset BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN + unset BUILDKITE_PLUGIN_PRIVATE_NPM_FILE + unset BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY + unset MY_ENV_VAR + rm -fr my_token_file + rm -fr my_empty_file } @@ -25,9 +32,6 @@ teardown() { assert_success assert [ -e '.npmrc' ] assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' - - # clean up - rm -fr my_token_file } @test "fails if the file parameter is used but no file exists" { @@ -46,9 +50,6 @@ teardown() { run $PWD/hooks/pre-command assert_failure - - # clean up - rm -fr my_empty_file } @test "reads the token from the environment if the env parameter is used" { @@ -59,7 +60,7 @@ teardown() { assert_success assert [ -e '.npmrc' ] - assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' + assert_equal "$(head -n1 .npmrc)" '//registry.npmjs.org/:_authToken=abc123' } @test "fails if the env parameter is used but no such variable is defined" { @@ -78,10 +79,9 @@ teardown() { run $PWD/hooks/pre-command assert_failure - } -@test "crates a npmrc file with supplied registry path and token" { +@test "creates a npmrc file with supplied registry path and token" { export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='abc123' export BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY='//myprivateregistry.org/' @@ -92,6 +92,30 @@ teardown() { assert_equal "$(head -n1 .npmrc)" '//myprivateregistry.org/:_authToken=abc123' } +@test "creates a npmrc file with supplied registry path and env" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_ENV_VAR' + export MY_ENV_VAR='abc123' + export BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY='//myprivateregistry.org/' + + run $PWD/hooks/pre-command + + assert_success + assert [ -e '.npmrc' ] + assert_equal "$(head -n1 .npmrc)" '//myprivateregistry.org/:_authToken=abc123' +} + +@test "creates a npmrc file with supplied registry path and file" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_token_file' + echo 'abc123' > my_token_file + export BUILDKITE_PLUGIN_PRIVATE_NPM_REGISTRY='//myprivateregistry.org/' + + run $PWD/hooks/pre-command + + assert_success + assert [ -e '.npmrc' ] + assert_equal "$(head -n1 .npmrc)" '//myprivateregistry.org/:_authToken=abc123' +} + @test "the command fails if none of the fields are not set" { run $PWD/hooks/pre-command @@ -99,3 +123,49 @@ teardown() { refute [ -e '.npmrc' ] } +# There is an exclusive relationship between file, env, and token. These tests ensure only value is set and fail with +# a meaninful message otherwise +@test "fails if env and file are both set" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_token_file' + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_ENV_VAR' + + run $PWD/hooks/pre-command + + assert_failure + assert_output ':no_entry_sign: :npm: :package: Failed! Only one of file, env or token parameters may be set' + refute [ -e '.npmrc' ] +} + +@test "fails if token and file are both set" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_token_file' + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='abc123' + + run $PWD/hooks/pre-command + + assert_failure + assert_output ':no_entry_sign: :npm: :package: Failed! Only one of file, env or token parameters may be set' + refute [ -e '.npmrc' ] +} + +@test "fails if env and token are both set" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='abc123' + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_ENV_VAR' + + run $PWD/hooks/pre-command + + assert_failure + assert_output ':no_entry_sign: :npm: :package: Failed! Only one of file, env or token parameters may be set' + refute [ -e '.npmrc' ] +} + +@test "fails if env, file and token are all set" { + export BUILDKITE_PLUGIN_PRIVATE_NPM_FILE='my_token_file' + export BUILDKITE_PLUGIN_PRIVATE_NPM_ENV='MY_ENV_VAR' + export BUILDKITE_PLUGIN_PRIVATE_NPM_TOKEN='abc123' + + run $PWD/hooks/pre-command + + assert_failure + assert_output ':no_entry_sign: :npm: :package: Failed! Only one of file, env or token parameters may be set' + refute [ -e '.npmrc' ] +} \ No newline at end of file From 44f3d622bad788f63ef4c980112abeb887d7a781 Mon Sep 17 00:00:00 2001 From: Darren Beukes Date: Thu, 26 Jul 2018 17:28:28 +1000 Subject: [PATCH 6/6] Updated README --- README.md | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0b63a49..8e90fe4 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,28 @@ Note this plugin should work equally well despite any personal preferences for e ## Example -To read the value from an environment variable named `MY_TOKEN` when the plugin executes, use the `env:` prefix. +To read the value from an environment variable named `MY_TOKEN` when the plugin executes, use the `env` fiels. ```yml steps: - command: yarn install plugins: seek-oss/private-npm#v1.1.1: - token: "env:MY_TOKEN" + env: "MY_TOKEN" ``` -To read the value from a file named `my_token_file`, use the `file:` prefix. +To read the value from a file named `my_token_file`, use the `file` field. ```yml steps: - command: yarn install plugins: seek-oss/private-npm#v1.1.1: - token: "file:my_token_file" + file: "my_token_file" ``` Alternatively you can read the token directly from any value exposed toxs your `pipeline.yml` file. However, this -approach is discoraged in favour of using with the `env:` or `file:` prefix. This functionality remains in the interest +approach is discoraged in favour of using with the `env` or `file` fields. This functionality remains in the interest of backwards compatibility. ```yml @@ -47,24 +47,31 @@ steps: - command: yarn install plugins: seek-oss/private-npm#v1.1.1: - token: ${MY_TOKEN} + env: "MY_TOKEN" registry: //myprivatenpm.com/ ``` ## Configuration -### `token` (required) -The value of the NPM token. Using the prefix `env:` of `file:` changes the behaviour of how the token is read. By -omitting the prefix, the value will be read from a variable which is available to the Buildkite YAML parsing context. -This value is interpolated when the YAML configuration is parsed by the Buildgent agent and provided to the plugin "as -is". +> **NOTE** Even thought `env`, `file` and `token` are described as optional, _at least one must be set_ or the plugin +> will fail. + +### `env` (optional) -Using the `env:` prefix delays reading the value from the agent environment until the plugin executes. +The value of the NPM token will be read from the agent environment when the plugin executes. This is useful in working +around cases where eager binding of variables in `pipeline.yml` means some variables are not present in the +environment when the configuration file is parsed. -Using the `file:` prefix will attempt to read the value from a file. +### `file` (optional) -The prefix variants are recommended if you are using a secrets manager or some other kind of late variable binding -mechanism to configure your agent's environment. Please see the examples for useage. +The value of the NPM token will be read from a file on the agent when the plugin executes. This is useful when working +with secret that are created as files on the filesystem when a build is initiated. + +### `token` (optional) + +The value of the NPM token will be read from a variable which is available to the Buildkite YAML parsing context. +This value is interpolated when the YAML configuration is parsed by the Buildgent agent and provided to the plugin "as +is". Example: `${MY_TOKEN}` > **NOTE:** Don't put your tokens into source control. Don't use web interfaces you don't control to inject them into