From da763a8f08fc21fd777419956f981a892a6c447d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:03:47 +0000 Subject: [PATCH 1/2] build(deps-dev): bump @microsoft/rush from 5.178.1 to 5.179.0 Bumps [@microsoft/rush](https://github.com/microsoft/rushstack/tree/HEAD/apps/rush) from 5.178.1 to 5.179.0. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/rush/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/HEAD/apps/rush) --- updated-dependencies: - dependency-name: "@microsoft/rush" dependency-version: 5.179.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ee69ab..fbbee0c 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", "@microsoft/api-extractor": "^7.48.1", - "@microsoft/rush": "5.178.1", + "@microsoft/rush": "5.179.0", "@nevware21/grunt-eslint-ts": "^0.5.1", "@nevware21/grunt-ts-plugin": "^0.5.1", "@nevware21/coverage-tools": ">= 0.1.4 < 2.x", From 9ad812e567a5952dd8447b78dd09eb33596a4f0c Mon Sep 17 00:00:00 2001 From: nevware21-bot <252503968+nevware21-bot@users.noreply.github.com> Date: Fri, 11 Sep 2026 07:04:07 -0700 Subject: [PATCH 2/2] chore: syncing versions and shrinkwrap --- common/config/rush/npm-shrinkwrap.json | 102 ++++---- common/scripts/install-run-rush.js | 58 +++++ common/scripts/install-run.js | 322 +++++++++++++++++++++---- rush.json | 3 +- 4 files changed, 391 insertions(+), 94 deletions(-) diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index dccee61..04ee836 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -449,17 +449,17 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.59.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.59.0.tgz", - "integrity": "sha512-KDYV8kSVjmG8JJWVg1f1aKxteNG1IQ44D07Rjhlcci8wlqrSFNhUfgv7dJhwT0W2h3NDIL5Vz2f+/DfO4OpDHw==", + "version": "7.59.1", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.59.1.tgz", + "integrity": "sha512-GjRUqx1MTY7xuH36urwASkfBPzrdxYG+irVeV7C9JEdRtn509AgMmwit/BhvztQzIoFk9vhFDTVYOp2cjw+9Uw==", "dependencies": { - "@microsoft/api-extractor-model": "7.33.11", + "@microsoft/api-extractor-model": "7.33.12", "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.1", - "@rushstack/node-core-library": "5.24.0", + "@rushstack/node-core-library": "5.24.1", "@rushstack/rig-package": "0.7.3", - "@rushstack/terminal": "0.24.3", - "@rushstack/ts-command-line": "5.3.13", + "@rushstack/terminal": "0.24.4", + "@rushstack/ts-command-line": "5.3.14", "diff": "~8.0.2", "minimatch": "10.2.3", "resolve": "~1.22.1", @@ -475,13 +475,13 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.33.11", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.11.tgz", - "integrity": "sha512-iDu1AtuRC2Z8XVs2SieZieVavF1FXPBX1C9pMexJh8Dx/Dd/3ZZ4nRQp/PU2Vk2rUHWuBz1wOyL4DcuhVnBXwg==", + "version": "7.33.12", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.12.tgz", + "integrity": "sha512-TdKOYgwf98xLjNW+y3iXIiCf4ZLQbilGAlqkMTTAqqAWfgRXAn9YCSGMsaiB1U7OPRvslUWg6n08EqQPbP93tA==", "dependencies": { "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.1", - "@rushstack/node-core-library": "5.24.0" + "@rushstack/node-core-library": "5.24.1" }, "engines": { "node": ">=20.9.0" @@ -1292,9 +1292,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.24.0.tgz", - "integrity": "sha512-g/Z47ZwARn/VkTnHcyJslrR26erRf1G5JbqPlfGZGBCrOcrEt8fTQXXDVhUDDNl/g/v3TXI1dNiAAT5FEks8BA==", + "version": "5.24.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.24.1.tgz", + "integrity": "sha512-ZlOrzv92MwnsCXA45qWfDj4L/kTasKghXezu+M2WmdtkbnXyPnZSCovfeBZx1Yc5qm+LkElbLw6IeSSWZDhZUg==", "dependencies": { "ajv": "~8.20.0", "ajv-draft-04": "~1.0.0", @@ -1355,11 +1355,11 @@ } }, "node_modules/@rushstack/terminal": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.3.tgz", - "integrity": "sha512-KxphDhPGC4xDrKg8O4yrWCEpPMi87aJc1iycXqMVh1dLgV0M34hiH9ZTgWjBRmcrT/OIHoOeWf48npcQFzgp+g==", + "version": "0.24.4", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.4.tgz", + "integrity": "sha512-3fRBWK0IMY293lBx5ycgit1DTMUi+nhOjALHlrIad9hQsqzM9Ak+XdBI1gJ/tZPxW+LraeAc4SsmMdcOflBmAQ==", "dependencies": { - "@rushstack/node-core-library": "5.24.0", + "@rushstack/node-core-library": "5.24.1", "@rushstack/problem-matcher": "0.2.1", "supports-color": "~8.1.1" }, @@ -1376,11 +1376,11 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "5.3.13", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.13.tgz", - "integrity": "sha512-+jNbxhh8CkrZYxMk9X3GRYM2+Myr1xCCj+eHbJ9Vp+PCdNHS0TUl5QQFT6UbM/aTFRCzs5jiBTKYzBRpe5uYbQ==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.14.tgz", + "integrity": "sha512-lT2JKZk2dukBMp4GFOh4RaDfVzpZehGgQOGpzpSliUn317NgEmOOCXyd7/d0eU46HHsbRxizP83GAm39s0lAlg==", "dependencies": { - "@rushstack/terminal": "0.24.3", + "@rushstack/terminal": "0.24.4", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -1579,11 +1579,11 @@ "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==" }, "node_modules/@types/node": { - "version": "26.4.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", - "integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==", + "version": "22.20.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz", + "integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==", "dependencies": { - "undici-types": "~8.3.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/resolve": { @@ -1912,9 +1912,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.11.21", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", - "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "version": "2.11.22", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.22.tgz", + "integrity": "sha512-pWc4w51fBFd7mav43/zKRC+RI6f4yfzQoVlfvE8dECePyfkn1bzLp01Fj0QACcyCZyFhiEMyD2qScfKRWgWibA==", "bin": { "baseline-browser-mapping": "dist/cli.cjs" }, @@ -1939,9 +1939,9 @@ "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==" }, "node_modules/body-parser": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", - "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", + "version": "1.20.8", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.8.tgz", + "integrity": "sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==", "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", @@ -1951,7 +1951,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.15.1", + "qs": "~6.16.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -3017,9 +3017,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.422", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", - "integrity": "sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==" + "version": "1.5.427", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.427.tgz", + "integrity": "sha512-n14zb3FdsChZ2BNobqNHAJMcP3ifFv4paox2LvCrfVAQcqGiSURgbJl+PfMpHVCNFkStnNc+RRVtPBTVW5PDgw==" }, "node_modules/elliptic": { "version": "6.6.1", @@ -4261,9 +4261,9 @@ ] }, "node_modules/ignore": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", - "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz", + "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==", "engines": { "node": ">= 4" } @@ -5672,9 +5672,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.54", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", - "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", "engines": { "node": ">=18" } @@ -6534,9 +6534,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" @@ -8008,9 +8008,9 @@ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, "node_modules/unicorn-magic": { "version": "0.4.0", @@ -8048,9 +8048,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", - "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "funding": [ { "type": "opencollective", diff --git a/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js index 5b1da11..d4545bd 100644 --- a/common/scripts/install-run-rush.js +++ b/common/scripts/install-run-rush.js @@ -16,6 +16,56 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ +/***/ 207008 +/*!*********************************************************************!*\ + !*** ./lib-intermediate-esm/scripts/generated/BootstrapProtocol.js ***! + \*********************************************************************/ +(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ BOOTSTRAP_PROTOCOL_MAJOR: () => (/* binding */ BOOTSTRAP_PROTOCOL_MAJOR), +/* harmony export */ encodeBootstrapEnvelope: () => (/* binding */ encodeBootstrapEnvelope) +/* harmony export */ }); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +// THIS FILE IS GENERATED. Run "rushx generate-bootstrap-protocol" in libraries/reporter to update it. +// Sources: libraries/reporter/src/bootstrap/BootstrapProtocol.ts +// libraries/reporter/src/protocol/ReporterProtocol.ts +/** + * The protocol major version frozen into the bootstrap encoder. + * + * @remarks + * The `install-run-rush` build embeds a generated copy of this constant and + * the encoder below. The generated module is checked byte-for-byte during the + * reporter build. + * + * @beta + */ +const BOOTSTRAP_PROTOCOL_MAJOR = 1; +/** + * Encodes one bootstrap event envelope without importing the reporter package. + * + * @beta + */ +function encodeBootstrapEnvelope(input) { + return JSON.stringify({ + protocolVersion: { major: BOOTSTRAP_PROTOCOL_MAJOR, minor: 0 }, + eventId: input.eventId, + sessionId: input.sessionId, + sequence: input.sequence, + timestamp: input.timestamp, + source: input.source, + privacy: input.privacy, + required: input.required, + type: input.type, + payload: input.payload === undefined ? {} : input.payload + }); +} +//# sourceMappingURL=BootstrapProtocol.js.map + +/***/ }, + /***/ 973024 /*!**************************!*\ !*** external "node:fs" ***! @@ -121,16 +171,23 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! node:fs */ 973024); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _generated_BootstrapProtocol__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./generated/BootstrapProtocol */ 207008); // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. /* eslint-disable no-console */ + const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run'); const PACKAGE_NAME = '@microsoft/rush'; const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; const RUSH_QUIET_MODE = 'RUSH_QUIET_MODE'; const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; +function _validateBundledBootstrapProtocol() { + if (_generated_BootstrapProtocol__WEBPACK_IMPORTED_MODULE_2__.BOOTSTRAP_PROTOCOL_MAJOR < 1 || typeof _generated_BootstrapProtocol__WEBPACK_IMPORTED_MODULE_2__.encodeBootstrapEnvelope !== 'function') { + throw new Error('The bundled Rush reporter bootstrap protocol is invalid.'); + } +} function _getRushVersion(logger) { const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION]; if (rushPreviewVersion !== undefined) { @@ -163,6 +220,7 @@ function _getBin(scriptName) { } } function _run() { + _validateBundledBootstrapProtocol(); const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv; // Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the // appropriate binary inside the rush package to run diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index 75d6014..ec8851f 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -57,6 +57,7 @@ function escapeArgumentIfNeeded(command, isWindows = IS_WINDOWS) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ getNpmrcEnvironmentVariables: () => (/* binding */ getNpmrcEnvironmentVariables), /* harmony export */ isVariableSetInNpmrcFile: () => (/* binding */ isVariableSetInNpmrcFile), /* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc), /* harmony export */ trimNpmrcFileLines: () => (/* binding */ trimNpmrcFileLines) @@ -78,7 +79,7 @@ __webpack_require__.r(__webpack_exports__); * The text of the the .npmrc. */ function _trimNpmrcFile(options) { - const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties, env = process.env } = options; + const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties, moveSensitiveSettingsToEnvironment, environmentVariableSettingNames, env = process.env } = options; let npmrcFileLines = []; if (linesToPrepend) { npmrcFileLines.push(...linesToPrepend); @@ -90,7 +91,7 @@ function _trimNpmrcFile(options) { npmrcFileLines.push(...linesToAppend); } npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); - const resultLines = trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties); + const resultLines = trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties, moveSensitiveSettingsToEnvironment, environmentVariableSettingNames); const combinedNpmrc = resultLines.join('\n'); return combinedNpmrc; } @@ -135,19 +136,239 @@ const PROPERTY_NAME_REGEX = /^([^=\[\s]+)/; * nameString:-fallbackString -> group 1: nameString, group 2: fallbackString */ const ENV_VAR_WITH_FALLBACK_REGEX = /^(?[^:-]+)(?::?-(?.+))?$/; +// Matches an environment variable reference such as "${NPM_TOKEN}" anywhere in a setting. +const ENVIRONMENT_VARIABLE_DETECTION_REGEX = /\$\{[^\}]+\}/; +/** + * The comment marker that is written in place of an .npmrc setting whose value was moved into an + * `npm_config_*` environment variable. The remainder of the line is the original (unexpanded) + * setting, so that the secret itself never gets written to disk. + * + * @remarks + * See {@link getNpmrcEnvironmentVariables} for the code that reads these lines back. + */ +const PROVIDED_VIA_ENVIRONMENT_PREFIX = '; PROVIDED VIA ENVIRONMENT: '; +/** + * The names of .npmrc settings that PNPM considers to be credentials. They may appear either + * as a bare setting name (`_authToken=...`) or scoped to a registry URI + * (`//registry.example.com/:_authToken=...`). + * + * @remarks + * This list mirrors PNPM's own list; PNPM 10.34.2 and newer refuse to expand `${VAR}` tokens in + * these settings when they come from a project or workspace .npmrc file. + */ +const AUTH_VALUE_SETTING_NAMES = new Set([ + '_authToken', + '_auth', + '_password', + 'username', + 'tokenHelper', + 'cert', + 'key' +]); +/** + * The names of .npmrc settings that determine where PNPM sends a request. PNPM 10.34.2 and newer + * refuse to expand `${VAR}` tokens in these settings when they come from a project or workspace + * .npmrc file, because a compromised value could redirect a request (and its credentials) to an + * attacker-controlled server. + */ +const REQUEST_DESTINATION_SETTING_NAMES = new Set([ + 'registry', + 'proxy', + 'http-proxy', + 'https-proxy' +]); +function _isRegistrySettingName(settingName) { + return settingName === 'registry' || (settingName.startsWith('@') && settingName.endsWith(':registry')); +} +/** + * Returns true if PNPM treats the setting's value as a credential. + */ +function _isAuthValueSettingName(settingName) { + if (AUTH_VALUE_SETTING_NAMES.has(settingName)) { + return true; + } + // Example: "//registry.example.com/:_authToken" --> "_authToken" + const lastColonIndex = settingName.lastIndexOf(':'); + return lastColonIndex >= 0 && AUTH_VALUE_SETTING_NAMES.has(settingName.substring(lastColonIndex + 1)); +} +/** + * Returns true if PNPM refuses to expand environment variables that appear in the setting's NAME. + */ +function _isRequestDestinationSettingName(settingName) { + return _isRegistrySettingName(settingName) || settingName.startsWith('//'); +} +/** + * Returns true if PNPM refuses to expand environment variables that appear in the setting's VALUE. + */ +function _isRequestDestinationValueSettingName(settingName) { + return _isRegistrySettingName(settingName) || REQUEST_DESTINATION_SETTING_NAMES.has(settingName); +} +function _tryParseNpmrcSetting(line) { + const equalsIndex = line.indexOf('='); + if (equalsIndex < 0) { + return undefined; + } + return { + line, + name: line.substring(0, equalsIndex), + value: line.substring(equalsIndex + 1) + }; +} +function _hasIgnoredEnvironmentVariable(setting) { + const { name, value } = setting; + return ((ENVIRONMENT_VARIABLE_DETECTION_REGEX.test(name) && + (_isRequestDestinationSettingName(name) || _isAuthValueSettingName(name))) || + (ENVIRONMENT_VARIABLE_DETECTION_REGEX.test(value) && + (_isRequestDestinationValueSettingName(name) || _isAuthValueSettingName(name)))); +} +/** + * Reproduces PNPM's `envKeyToSetting()`, which converts the portion of an `npm_config_*` environment + * variable name that follows the prefix back into an .npmrc setting name. + */ +function _environmentVariableSuffixToSettingName(suffix) { + const colonIndex = suffix.indexOf(':'); + if (colonIndex === -1) { + return _normalizeSettingNamePart(suffix); + } + return `${suffix.substring(0, colonIndex)}:${_normalizeSettingNamePart(suffix.substring(colonIndex + 1))}`; +} +function _normalizeSettingNamePart(settingNamePart) { + const lowerCased = settingNamePart.toLowerCase(); + if (lowerCased === '_authtoken') { + return '_authToken'; + } + // Underscores become dashes, except for a leading underscore + return lowerCased.charAt(0) + lowerCased.substring(1).replace(/_/g, '-'); +} +/** + * Returns true if the setting can be expressed as an `npm_config_*` environment variable without + * being mangled by PNPM's name normalization. + * + * @remarks + * For example, a registry URL that includes an explicit port such as + * `//registry.example.com:8080/:_authToken` cannot round-trip, because PNPM splits the name on its + * FIRST colon and then normalizes everything after it. + */ +function _canSettingRoundTripThroughEnvironmentVariable(settingName) { + return _environmentVariableSuffixToSettingName(settingName) === settingName; +} +// This finds environment variable tokens that look like "${VAR_NAME}" +const ENVIRONMENT_VARIABLE_REGEX = /\$\{([^\}]+)\}/g; +function _expandEnvironmentVariables(text, env, supportEnvVarFallbackSyntax) { + let hasVariable = false; + let hasUndefinedVariable = false; + const expandedText = text.replace(ENVIRONMENT_VARIABLE_REGEX, (token) => { + hasVariable = true; + /** + * Remove the leading "${" and the trailing "}" from the token + * + * ${nameString} -> nameString + * ${nameString-fallbackString} -> nameString-fallbackString + * ${nameString:-fallbackString} -> nameString:-fallbackString + */ + const nameWithFallback = token.slice(2, -1); + let environmentVariableName; + let fallback; + if (supportEnvVarFallbackSyntax) { + /** + * Get the environment variable name and fallback value. + * + * name fallback + * nameString -> nameString undefined + * nameString-fallbackString -> nameString fallbackString + * nameString:-fallbackString -> nameString fallbackString + */ + const matched = nameWithFallback.match(ENV_VAR_WITH_FALLBACK_REGEX); + environmentVariableName = matched?.groups?.name ?? nameWithFallback; + fallback = matched?.groups?.fallback; + } + else { + environmentVariableName = nameWithFallback; + } + const environmentVariableValue = env[environmentVariableName]; + if (environmentVariableValue) { + return environmentVariableValue; + } + else if (fallback) { + return fallback; + } + else { + hasUndefinedVariable = true; + return token; + } + }); + return { + expandedText: hasUndefinedVariable ? text : expandedText, + hasVariable, + hasUndefinedVariable + }; +} +/** + * Determines how a .npmrc line whose environment variables are all defined must be transformed + * so that PNPM 10.34.2 and newer will honor it. Returns `undefined` if PNPM expands the line's + * environment variables itself, in which case the line is left alone. + */ +function _classifySensitiveNpmrcSetting(setting, env, supportEnvVarFallbackSyntax) { + const { name: settingName, value: settingValue } = setting; + const expandedName = _expandEnvironmentVariables(settingName, env, supportEnvVarFallbackSyntax); + const expandedValue = _expandEnvironmentVariables(settingValue, env, supportEnvVarFallbackSyntax); + if (expandedName.hasUndefinedVariable || expandedValue.hasUndefinedVariable) { + return undefined; + } + // Consider both spellings, because PNPM discards the setting if EITHER form is sensitive + const isAuthValue = _isAuthValueSettingName(expandedName.expandedText) || _isAuthValueSettingName(settingName); + if (isAuthValue) { + if (_canSettingRoundTripThroughEnvironmentVariable(expandedName.expandedText)) { + return { + kind: 'environment', + variableName: `npm_config_${expandedName.expandedText}`, + variableValue: expandedValue.expandedText + }; + } + throw new Error(`The .npmrc credential setting "${expandedName.expandedText}" cannot be provided via an ` + + 'environment variable because PNPM cannot round-trip this setting name.'); + } + const isRequestDestination = (expandedName.hasVariable && + (_isRequestDestinationSettingName(expandedName.expandedText) || + _isRequestDestinationSettingName(settingName))) || + (expandedValue.hasVariable && _isRequestDestinationValueSettingName(expandedName.expandedText)); + if (isRequestDestination) { + return { kind: 'expand', expandedLine: `${expandedName.expandedText}=${expandedValue.expandedText}` }; + } + return undefined; +} +/** + * Returns the replacement text for a .npmrc line that PNPM would otherwise discard, or `undefined` + * if the line does not need to be rewritten. + */ +function _rewriteSensitiveNpmrcLine(setting, env, supportEnvVarFallbackSyntax) { + const action = _classifySensitiveNpmrcSetting(setting, env, supportEnvVarFallbackSyntax); + switch (action?.kind) { + case 'environment': + // Example output: + // "; PROVIDED VIA ENVIRONMENT: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" + return PROVIDED_VIA_ENVIRONMENT_PREFIX + setting.line; + case 'expand': + return action.expandedLine; + default: + return undefined; + } +} /** * * @param npmrcFileLines The npmrc file's lines * @param env The environment variables object * @param supportEnvVarFallbackSyntax Whether to support fallback values in the form of `${VAR_NAME:-fallback}` * @param filterNpmIncompatibleProperties Whether to filter out properties that npm doesn't understand + * @param moveSensitiveSettingsToEnvironment Whether to replace settings that PNPM refuses to expand + * environment variables in with a `; PROVIDED VIA ENVIRONMENT: ` comment. See + * {@link getNpmrcEnvironmentVariables}. + * @param environmentVariableSettingNames If provided, collects settings containing environment + * variable references that PNPM ignores in a project `.npmrc`. * @returns An array of processed npmrc file lines with undefined environment variables and npm-incompatible properties commented out */ -function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties = false) { - var _a, _b, _c; +function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties = false, moveSensitiveSettingsToEnvironment = false, environmentVariableSettingNames) { const resultLines = []; - // This finds environment variable tokens that look like "${VAR_NAME}" - const expansionRegExp = /\$\{([^\}]+)\}/g; // Comment lines start with "#" or ";" const commentRegExp = /^\s*[#;]/; // Trim out lines that reference environment variables that aren't defined @@ -161,6 +382,10 @@ function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, fi .join('='); // Ignore comment lines if (!commentRegExp.test(line)) { + const parsedSetting = _tryParseNpmrcSetting(line); + if (environmentVariableSettingNames && parsedSetting && _hasIgnoredEnvironmentVariable(parsedSetting)) { + environmentVariableSettingNames.add(parsedSetting.name); + } // Check if this is a property that npm doesn't understand if (filterNpmIncompatibleProperties) { // Extract the property name (everything before the '=' or '[') @@ -192,42 +417,16 @@ function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, fi } // Check for undefined environment variables if (!lineShouldBeTrimmed) { - const environmentVariables = line.match(expansionRegExp); - if (environmentVariables) { - for (const token of environmentVariables) { - /** - * Remove the leading "${" and the trailing "}" from the token - * - * ${nameString} -> nameString - * ${nameString-fallbackString} -> name-fallbackString - * ${nameString:-fallbackString} -> name:-fallbackString - */ - const nameWithFallback = token.slice(2, -1); - let environmentVariableName; - let fallback; - if (supportEnvVarFallbackSyntax) { - /** - * Get the environment variable name and fallback value. - * - * name fallback - * nameString -> nameString undefined - * nameString-fallbackString -> nameString fallbackString - * nameString:-fallbackString -> nameString fallbackString - */ - const matched = nameWithFallback.match(ENV_VAR_WITH_FALLBACK_REGEX); - environmentVariableName = (_b = (_a = matched === null || matched === void 0 ? void 0 : matched.groups) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : nameWithFallback; - fallback = (_c = matched === null || matched === void 0 ? void 0 : matched.groups) === null || _c === void 0 ? void 0 : _c.fallback; - } - else { - environmentVariableName = nameWithFallback; - } - // Is the environment variable and fallback value defined. - if (!env[environmentVariableName] && !fallback) { - // No, so trim this line - lineShouldBeTrimmed = true; - trimReason = 'MISSING_ENVIRONMENT_VARIABLE'; - break; - } + const { hasVariable, hasUndefinedVariable } = _expandEnvironmentVariables(line, env, supportEnvVarFallbackSyntax); + if (hasUndefinedVariable) { + lineShouldBeTrimmed = true; + trimReason = 'MISSING_ENVIRONMENT_VARIABLE'; + } + else if (hasVariable && moveSensitiveSettingsToEnvironment && parsedSetting) { + const rewrittenLine = _rewriteSensitiveNpmrcLine(parsedSetting, env, supportEnvVarFallbackSyntax); + if (rewrittenLine !== undefined) { + resultLines.push(rewrittenLine); + continue; } } } @@ -305,6 +504,45 @@ function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarF const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); return trimmedNpmrcFile.match(variableKeyRegExp) !== null; } +/** + * Returns the `npm_config_*` environment variables that must be passed to the package manager to + * provide the credentials that {@link syncNpmrc} moved out of the generated .npmrc file when its + * `moveSensitiveSettingsToEnvironment` option was enabled. Returns `undefined` if there are none. + * + * @remarks + * PNPM only expands `${VAR}` tokens in credentials that come from a trusted source, and an + * environment variable is such a source. Recomputing the variables from the generated .npmrc file + * (instead of remembering them from the {@link syncNpmrc} call) allows commands such as + * `rush-pnpm` to authenticate without re-synchronizing the file. + */ +function getNpmrcEnvironmentVariables(options) { + const { npmrcFolder, supportEnvVarFallbackSyntax, env = process.env } = options; + let npmrcFileContent; + try { + npmrcFileContent = node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(node_path__WEBPACK_IMPORTED_MODULE_1__.join(npmrcFolder, '.npmrc')).toString(); + } + catch (e) { + if (e.code === 'ENOENT') { + return undefined; + } + throw e; + } + let environmentVariables; + for (const npmrcFileLine of npmrcFileContent.split('\n')) { + const trimmedLine = npmrcFileLine.trim(); + if (!trimmedLine.startsWith(PROVIDED_VIA_ENVIRONMENT_PREFIX)) { + continue; + } + const originalLine = trimmedLine.substring(PROVIDED_VIA_ENVIRONMENT_PREFIX.length); + const parsedSetting = _tryParseNpmrcSetting(originalLine); + const action = parsedSetting && _classifySensitiveNpmrcSetting(parsedSetting, env, supportEnvVarFallbackSyntax); + if (action?.kind === 'environment') { + environmentVariables ??= {}; + environmentVariables[action.variableName] = action.variableValue; + } + } + return environmentVariables; +} //# sourceMappingURL=npmrcUtilities.js.map /***/ }, diff --git a/rush.json b/rush.json index a9ecc13..851b03e 100644 --- a/rush.json +++ b/rush.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", "npmVersion": "9.9.3", - "rushVersion": "5.178.1", + "rushVersion": "5.179.0", "projectFolderMaxDepth": 4, "projects": [ { @@ -28,3 +28,4 @@ +