Skip to content

Commit a7d44dd

Browse files
committed
Use one time password when publishing to npm (facebook#20701)
Summary: This pull request addresses the failing publish-npm.js script from earlier this week. For background, last month we reset all npm access tokens for any package related to Facebook, and we now require all accounts with publish permissions to have two factor enabled. The publish-npm.js script relied on one such token that is configured in Circle CI as a envvar. The token has been updated in Circle CI, but we now need a way of passing the one time password to npm. With this PR, we can now grab the otp from Circle CI's envvars. Considering otps are ephemeral, this requires the NPM_CONFIG_OTP envvar to be set by someone with publishing permissions anytime a new release will be pushed to npm. The token is short lived, but it would still be good to clear the envvar after the package is published. Circle CI envvars are not passed on to PR/forked builds. This PR is effectively a breaking change for the release process, as the publish step will not succeed if the OTP is not valid. OTPs are short-lived, and the publish_npm_package job will definitely outlive the token. Unfortunately this will require some timing to get right, but the alternative is to ssh into the Circle CI machine and re-run the `npm publish --otp` command, which again would still require someone with publish access to provide the otp. Pull Request resolved: facebook#20701 Differential Revision: D9478488 Pulled By: hramos fbshipit-source-id: 6af631a9cb425271b98c03d158aec390ebc95304
1 parent 6eac2d4 commit a7d44dd

File tree

2 files changed

+29
-17
lines changed

2 files changed

+29
-17
lines changed

.circleci/config.yml

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,10 @@ jobs:
596596
publish_npm_package:
597597
<<: *android_defaults
598598
steps:
599-
- attach_workspace:
600-
at: ~/react-native
599+
- checkout
600+
601+
- restore-cache: *restore-yarn-cache
602+
- run: *yarn
601603

602604
# Configure Android SDK and related dependencies
603605
- run: *configure-android-path
@@ -624,13 +626,19 @@ jobs:
624626
- run: *yarn
625627

626628
- run:
627-
name: Publish React Native Package
629+
name: Authenticate with npm
630+
command: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
631+
632+
- run:
633+
name: Authenticate git user
628634
command: |
629-
echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
630-
git config --global user.email "reactjs-bot@users.noreply.github.com"
635+
git config --global user.email "react-native-bot@users.noreply.github.com"
631636
git config --global user.name "npm Deployment Script"
632-
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
633-
node ./scripts/publish-npm.js
637+
echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc
638+
639+
- run:
640+
name: Publish React Native Package
641+
command: node ./scripts/publish-npm.js
634642

635643
# Workflows enables us to run multiple jobs in parallel
636644
workflows:

scripts/publish-npm.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
require('shelljs/global');
5252

5353
const buildBranch = process.env.CIRCLE_BRANCH;
54+
const otp = process.env.NPM_CONFIG_OTP;
5455

5556
let branchVersion;
5657
if (buildBranch.indexOf('-stable') !== -1) {
@@ -79,7 +80,7 @@ const tagsWithVersion = exec(`git ls-remote origin | grep ${currentCommit}`, {
7980

8081
if (tagsWithVersion.length === 0) {
8182
echo(
82-
"Error: Can't find version tag in current commit. To deploy to NPM you must add tag v0.XY.Z[-rc] to your commit",
83+
'Error: Cannot find version tag in current commit. To deploy to NPM you must add tag v0.XY.Z[-rc] to your commit',
8384
);
8485
exit(1);
8586
}
@@ -96,7 +97,7 @@ if (tagsWithVersion[0].indexOf('-rc') === -1) {
9697

9798
// -------- Generating Android Artifacts with JavaDoc
9899
if (exec('./gradlew :ReactAndroid:installArchives').code) {
99-
echo("Couldn't generate artifacts");
100+
echo('Could not generate artifacts');
100101
exit(1);
101102
}
102103

@@ -121,15 +122,18 @@ artifacts.forEach(name => {
121122
}
122123
});
123124

124-
if (releaseVersion.indexOf('-rc') === -1) {
125-
// release, package will be installed by default
126-
exec('npm publish');
125+
// if version contains -rc, tag as prerelease
126+
const tagFlag = releaseVersion.indexOf('-rc') === -1 ? '' : '--tag next';
127+
128+
// use otp from envvars if available
129+
const otpFlag = otp ? `--otp ${otp}` : '';
130+
131+
if (exec(`npm publish ${tagFlag} ${otpFlag}`).code) {
132+
echo('Failed to publish package to npm');
133+
exit(1);
127134
} else {
128-
// RC release, package will be installed only if users specifically do it
129-
exec('npm publish --tag next');
135+
echo(`Published to npm ${releaseVersion}`);
136+
exit(0);
130137
}
131138

132-
echo(`Published to npm ${releaseVersion}`);
133-
134-
exit(0);
135139
/*eslint-enable no-undef */

0 commit comments

Comments
 (0)