diff --git a/.gitignore b/.gitignore index 68c897ad310..a7871370954 100644 --- a/.gitignore +++ b/.gitignore @@ -123,3 +123,6 @@ dist-storybook/ # Heft temporary files .cache/ .heft/ + +# VS Code test runner files +.vscode-test/ diff --git a/README.md b/README.md index 066b4ee740e..f76cc8702ea 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/heft-plugins/heft-serverless-stack-plugin](./heft-plugins/heft-serverless-stack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin) | [changelog](./heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md) | [@rushstack/heft-serverless-stack-plugin](https://www.npmjs.com/package/@rushstack/heft-serverless-stack-plugin) | | [/heft-plugins/heft-storybook-plugin](./heft-plugins/heft-storybook-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin) | [changelog](./heft-plugins/heft-storybook-plugin/CHANGELOG.md) | [@rushstack/heft-storybook-plugin](https://www.npmjs.com/package/@rushstack/heft-storybook-plugin) | | [/heft-plugins/heft-typescript-plugin](./heft-plugins/heft-typescript-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin) | [changelog](./heft-plugins/heft-typescript-plugin/CHANGELOG.md) | [@rushstack/heft-typescript-plugin](https://www.npmjs.com/package/@rushstack/heft-typescript-plugin) | +| [/heft-plugins/heft-vscode-extension-plugin](./heft-plugins/heft-vscode-extension-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin) | [changelog](./heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md) | [@rushstack/heft-vscode-extension-plugin](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-plugin) | | [/heft-plugins/heft-webpack4-plugin](./heft-plugins/heft-webpack4-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin) | [changelog](./heft-plugins/heft-webpack4-plugin/CHANGELOG.md) | [@rushstack/heft-webpack4-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack4-plugin) | | [/heft-plugins/heft-webpack5-plugin](./heft-plugins/heft-webpack5-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin) | [changelog](./heft-plugins/heft-webpack5-plugin/CHANGELOG.md) | [@rushstack/heft-webpack5-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack5-plugin) | | [/libraries/api-extractor-model](./libraries/api-extractor-model/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model.svg)](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model) | [changelog](./libraries/api-extractor-model/CHANGELOG.md) | [@microsoft/api-extractor-model](https://www.npmjs.com/package/@microsoft/api-extractor-model) | @@ -98,6 +99,7 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/libraries/typings-generator](./libraries/typings-generator/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftypings-generator.svg)](https://badge.fury.io/js/%40rushstack%2Ftypings-generator) | [changelog](./libraries/typings-generator/CHANGELOG.md) | [@rushstack/typings-generator](https://www.npmjs.com/package/@rushstack/typings-generator) | | [/libraries/worker-pool](./libraries/worker-pool/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fworker-pool.svg)](https://badge.fury.io/js/%40rushstack%2Fworker-pool) | [changelog](./libraries/worker-pool/CHANGELOG.md) | [@rushstack/worker-pool](https://www.npmjs.com/package/@rushstack/worker-pool) | | [/rigs/heft-node-rig](./rigs/heft-node-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig) | [changelog](./rigs/heft-node-rig/CHANGELOG.md) | [@rushstack/heft-node-rig](https://www.npmjs.com/package/@rushstack/heft-node-rig) | +| [/rigs/heft-vscode-extension-rig](./rigs/heft-vscode-extension-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig) | [changelog](./rigs/heft-vscode-extension-rig/CHANGELOG.md) | [@rushstack/heft-vscode-extension-rig](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-rig) | | [/rigs/heft-web-rig](./rigs/heft-web-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig) | [changelog](./rigs/heft-web-rig/CHANGELOG.md) | [@rushstack/heft-web-rig](https://www.npmjs.com/package/@rushstack/heft-web-rig) | | [/rush-plugins/rush-amazon-s3-build-cache-plugin](./rush-plugins/rush-amazon-s3-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin) | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-amazon-s3-build-cache-plugin) | | [/rush-plugins/rush-azure-storage-build-cache-plugin](./rush-plugins/rush-azure-storage-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin) | | [@rushstack/rush-azure-storage-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-azure-storage-build-cache-plugin) | @@ -108,6 +110,9 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/rush-plugins/rush-redis-cobuild-plugin](./rush-plugins/rush-redis-cobuild-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin) | | [@rushstack/rush-redis-cobuild-plugin](https://www.npmjs.com/package/@rushstack/rush-redis-cobuild-plugin) | | [/rush-plugins/rush-resolver-cache-plugin](./rush-plugins/rush-resolver-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin) | | [@rushstack/rush-resolver-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-resolver-cache-plugin) | | [/rush-plugins/rush-serve-plugin](./rush-plugins/rush-serve-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin) | | [@rushstack/rush-serve-plugin](https://www.npmjs.com/package/@rushstack/rush-serve-plugin) | +| [/vscode-extensions/tls-sync-vscode-extension-pack](./vscode-extensions/tls-sync-vscode-extension-pack/) | [![npm version](https://badge.fury.io/js/tls-sync-vscode-extension-pack.svg)](https://badge.fury.io/js/tls-sync-vscode-extension-pack) | [changelog](./vscode-extensions/tls-sync-vscode-extension-pack/CHANGELOG.md) | [tls-sync-vscode-extension-pack](https://www.npmjs.com/package/tls-sync-vscode-extension-pack) | +| [/vscode-extensions/tls-sync-vscode-ui-extension](./vscode-extensions/tls-sync-vscode-ui-extension/) | [![npm version](https://badge.fury.io/js/tls-sync-vscode-ui-extension.svg)](https://badge.fury.io/js/tls-sync-vscode-ui-extension) | | [tls-sync-vscode-ui-extension](https://www.npmjs.com/package/tls-sync-vscode-ui-extension) | +| [/vscode-extensions/tls-sync-vscode-workspace-extension](./vscode-extensions/tls-sync-vscode-workspace-extension/) | [![npm version](https://badge.fury.io/js/tls-sync-vscode-workspace-extension.svg)](https://badge.fury.io/js/tls-sync-vscode-workspace-extension) | | [tls-sync-vscode-workspace-extension](https://www.npmjs.com/package/tls-sync-vscode-workspace-extension) | | [/webpack/hashed-folder-copy-plugin](./webpack/hashed-folder-copy-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fhashed-folder-copy-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fhashed-folder-copy-plugin) | [changelog](./webpack/hashed-folder-copy-plugin/CHANGELOG.md) | [@rushstack/hashed-folder-copy-plugin](https://www.npmjs.com/package/@rushstack/hashed-folder-copy-plugin) | | [/webpack/loader-load-themed-styles](./webpack/loader-load-themed-styles/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Floader-load-themed-styles.svg)](https://badge.fury.io/js/%40microsoft%2Floader-load-themed-styles) | [changelog](./webpack/loader-load-themed-styles/CHANGELOG.md) | [@microsoft/loader-load-themed-styles](https://www.npmjs.com/package/@microsoft/loader-load-themed-styles) | | [/webpack/loader-raw-script](./webpack/loader-raw-script/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Floader-raw-script.svg)](https://badge.fury.io/js/%40rushstack%2Floader-raw-script) | [changelog](./webpack/loader-raw-script/CHANGELOG.md) | [@rushstack/loader-raw-script](https://www.npmjs.com/package/@rushstack/loader-raw-script) | @@ -218,6 +223,8 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/rush-plugins/rush-litewatch-plugin](./rush-plugins/rush-litewatch-plugin/) | An experimental alternative approach for multi-project watch mode | | [/vscode-extensions/rush-vscode-command-webview](./vscode-extensions/rush-vscode-command-webview/) | Part of the Rush Stack VSCode extension, provides a UI for invoking Rush commands | | [/vscode-extensions/rush-vscode-extension](./vscode-extensions/rush-vscode-extension/) | Enhanced experience for monorepos that use the Rush Stack toolchain | +| [/vscode-extensions/tls-sync-vscode-shared](./vscode-extensions/tls-sync-vscode-shared/) | | +| [/vscode-extensions/vscode-shared](./vscode-extensions/vscode-shared/) | | | [/webpack/webpack-deep-imports-plugin](./webpack/webpack-deep-imports-plugin/) | This plugin creates a bundle and commonJS files in a 'lib' folder mirroring modules in another 'lib' folder. | diff --git a/common/changes/@rushstack/debug-certificate-manager/bmiddha-tls-sync_2025-06-27-01-35.json b/common/changes/@rushstack/debug-certificate-manager/bmiddha-tls-sync_2025-06-27-01-35.json new file mode 100644 index 00000000000..bb881fd6355 --- /dev/null +++ b/common/changes/@rushstack/debug-certificate-manager/bmiddha-tls-sync_2025-06-27-01-35.json @@ -0,0 +1,25 @@ +{ + "changes": [ + { + "packageName": "@rushstack/debug-certificate-manager", + "comment": "CertificateStore - Add params to support custom paths and filenames", + "type": "minor" + }, + { + "packageName": "@rushstack/debug-certificate-manager", + "comment": "CertificateManager - Update `untrustCertificateAsync` to clear `caCertificateData`", + "type": "minor" + }, + { + "packageName": "@rushstack/debug-certificate-manager", + "comment": "CertificateManager - Use osascript (applescript) to run elevated command on macOS instead of sudo package.", + "type": "minor" + }, + { + "packageName": "@rushstack/debug-certificate-manager", + "comment": "CertificateManager - Expose `getCertificateExpirationAsync` method to retrieve certificate expiration date", + "type": "minor" + } + ], + "packageName": "@rushstack/debug-certificate-manager" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-vscode-extension-plugin/bmiddha-tls-sync_2025-06-27-01-35.json b/common/changes/@rushstack/heft-vscode-extension-plugin/bmiddha-tls-sync_2025-06-27-01-35.json new file mode 100644 index 00000000000..5aa1f5c26b8 --- /dev/null +++ b/common/changes/@rushstack/heft-vscode-extension-plugin/bmiddha-tls-sync_2025-06-27-01-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-vscode-extension-plugin", + "comment": "Add new Heft plugin to package files into a VSIX file", + "type": "minor" + } + ], + "packageName": "@rushstack/heft-vscode-extension-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-vscode-extension-rig/bmiddha-tls-sync_2025-07-01-20-54.json b/common/changes/@rushstack/heft-vscode-extension-rig/bmiddha-tls-sync_2025-07-01-20-54.json new file mode 100644 index 00000000000..13937b05866 --- /dev/null +++ b/common/changes/@rushstack/heft-vscode-extension-rig/bmiddha-tls-sync_2025-07-01-20-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-vscode-extension-rig", + "comment": "Add new rig to build VS Code extensions", + "type": "minor" + } + ], + "packageName": "@rushstack/heft-vscode-extension-rig" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/bmiddha-tls-sync_2025-07-01-20-54.json b/common/changes/@rushstack/node-core-library/bmiddha-tls-sync_2025-07-01-20-54.json new file mode 100644 index 00000000000..1d6e9437bfe --- /dev/null +++ b/common/changes/@rushstack/node-core-library/bmiddha-tls-sync_2025-07-01-20-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/node-core-library", + "comment": "Add a `Async.runWithTimeoutAsync` function that executes an async function, resolving if the specified timeout elapses first.", + "type": "minor" + } + ], + "packageName": "@rushstack/node-core-library" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json b/common/changes/@rushstack/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json new file mode 100644 index 00000000000..0fd5df88305 --- /dev/null +++ b/common/changes/@rushstack/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/tls-sync-vscode-shared", + "comment": "Add shared utilities for the Workspace and UI TLS Sync VS Code extensions", + "type": "minor" + } + ], + "packageName": "@rushstack/tls-sync-vscode-shared" +} \ No newline at end of file diff --git a/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json b/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json new file mode 100644 index 00000000000..ea49adc9636 --- /dev/null +++ b/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "tls-sync-vscode-extension-pack", + "comment": "Add VSCode Extension to sync TLS certificates when using VS Code remoting.", + "type": "minor" + } + ], + "packageName": "tls-sync-vscode-extension-pack" +} \ No newline at end of file diff --git a/common/config/azure-pipelines/vscode-extension-publish.yaml b/common/config/azure-pipelines/vscode-extension-publish.yaml index d2452e5c561..172133d03b5 100644 --- a/common/config/azure-pipelines/vscode-extension-publish.yaml +++ b/common/config/azure-pipelines/vscode-extension-publish.yaml @@ -2,6 +2,26 @@ variables: - name: FORCE_COLOR value: 1 +parameters: + - name: shouldPublish + type: boolean + default: true + - name: ExtensionPublishConfig + type: object + default: + - key: 'tls-sync-vscode-ui-extension' + vsixPath: 'dist/vsix/packaged.vsix' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/tls-sync-vscode-ui-extension' + - key: 'tls-sync-vscode-workspace-extension' + vsixPath: 'dist/vsix/packaged.vsix' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/tls-sync-vscode-workspace-extension' + - key: 'tls-sync-vscode-extension-pack' + vsixPath: 'dist/vsix/packaged.vsix' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/tls-sync-vscode-extension-pack' + - key: 'rush-vscode-extension' + vsixPath: 'dist/vsix/packaged.vsix' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension' + resources: repositories: - repository: 1esPipelines @@ -22,6 +42,14 @@ extends: pool: name: publish-rushstack os: linux + templateContext: + outputs: + - ${{ each extension in parameters.ExtensionPublishConfig }}: + - output: pipelineArtifact + artifactName: ${{ extension.key }} + targetPath: ${{ extension.projectPath }}/${{ extension.vsixPath }} + displayName: 'Publish Artifact: ${{ extension.key }}' + steps: - checkout: self persistCredentials: true @@ -31,14 +59,16 @@ extends: - template: /common/config/azure-pipelines/templates/build.yaml@self parameters: BuildParameters: > - --to rushstack - - - script: node $(Build.SourcesDirectory)/common/scripts/install-run-rushx.js package - workingDirectory: $(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension - displayName: 'Package vscode extension' + --to tag:vsix - - script: node $(Build.SourcesDirectory)/common/scripts/install-run-rushx.js deploy - workingDirectory: $(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension - displayName: 'Publish vscode extension' - env: - VSCE_PAT: $(vscePat) + - ${{ if parameters.shouldPublish }}: + - ${{ each extension in parameters.ExtensionPublishConfig }}: + - task: AzureCLI@2 + displayName: 'Publish VSIX: ${{ extension.key }}' + inputs: + azureSubscription: rushstack-vscode-publish + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + node node_modules/@rushstack/heft-vscode-extension-rig/node_modules/@rushstack/heft-vscode-extension-plugin/node_modules/@vscode/vsce/vsce publish --no-dependencies --azure-credential --packagePath ${{ extension.vsixPath }} + workingDirectory: ${{ extension.projectPath }} diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 13e6fa0f8eb..1bc39a45f06 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -120,7 +120,7 @@ }, { "name": "@rushstack/debug-certificate-manager", - "allowedCategories": [ "libraries" ] + "allowedCategories": [ "libraries", "vscode-extensions" ] }, { "name": "@rushstack/eslint-bulk", @@ -210,6 +210,14 @@ "name": "@rushstack/heft-typescript-plugin", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/heft-vscode-extension-plugin", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@rushstack/heft-vscode-extension-rig", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/heft-web-rig", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] @@ -306,6 +314,10 @@ "name": "@rushstack/terminal", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/tls-sync-vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/tree-pattern", "allowedCategories": [ "libraries" ] @@ -318,6 +330,10 @@ "name": "@rushstack/typings-generator", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/webpack-deep-imports-plugin", "allowedCategories": [ "libraries" ] @@ -430,6 +446,10 @@ "name": "@vscode/test-electron", "allowedCategories": [ "vscode-extensions" ] }, + { + "name": "@vscode/vsce", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, { "name": "@yarnpkg/lockfile", "allowedCategories": [ "libraries" ] @@ -942,6 +962,14 @@ "name": "timsort", "allowedCategories": [ "libraries" ] }, + { + "name": "tls-sync-vscode-ui-extension", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "tls-sync-vscode-workspace-extension", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "true-case-path", "allowedCategories": [ "libraries" ] @@ -970,10 +998,6 @@ "name": "uuid", "allowedCategories": [ "libraries" ] }, - { - "name": "vsce", - "allowedCategories": [ "vscode-extensions" ] - }, { "name": "watchpack", "allowedCategories": [ "libraries" ] diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index f4aaf7f6fe5..90e6a85f38c 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -105,5 +105,15 @@ "version": "5.155.1", "nextBump": "patch", "mainProject": "@microsoft/rush" + }, + { + // This policy is used for the TLS Sync VS Code extensions. + // Updating them in lockstep is necessary for the UI and Workspace extensions to work together. + // The Workspace and UI extensions perform a ping-pong version check to ensure they are compatible. + "policyName": "tls-sync-vscode-extensions", + "definitionName": "lockStepVersion", + "version": "0.0.1", + "nextBump": "minor", + "mainProject": "tls-sync-vscode-extension-pack" } ] diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json index c4ffc9bf939..6c98abe1563 100644 --- a/common/config/subspaces/build-tests-subspace/repo-state.json +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -2,5 +2,5 @@ { "pnpmShrinkwrapHash": "e8913fc783fabd3c2743397b9e8494b7d39dce34", "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9", - "packageJsonInjectedDependenciesHash": "6399d13a4e2ea790ca192a8f56ae04e26d205bd4" + "packageJsonInjectedDependenciesHash": "8f951e62240e50b2601a58e625da39e294a7b50f" } diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index 7bcb706acaa..575d03d83f5 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -3110,6 +3110,31 @@ importers: specifier: ~5.8.2 version: 5.8.2 + ../../../heft-plugins/heft-vscode-extension-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@vscode/vsce': + specifier: 3.3.2 + version: 3.3.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.25.1 + version: 9.25.1(supports-color@8.1.1) + ../../../heft-plugins/heft-webpack4-plugin: dependencies: '@rushstack/debug-certificate-manager': @@ -3226,9 +3251,6 @@ importers: node-forge: specifier: ~1.3.1 version: 1.3.1 - sudo: - specifier: ~1.0.3 - version: 1.0.3 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -4105,6 +4127,40 @@ importers: specifier: workspace:* version: link:../../apps/heft + ../../../rigs/heft-vscode-extension-rig: + dependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../heft-node-rig + '@rushstack/heft-vscode-extension-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-vscode-extension-plugin + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/webpack-preserve-dynamic-require-plugin': + specifier: workspace:* + version: link:../../webpack/preserve-dynamic-require-plugin + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + eslint: + specifier: ~9.25.1 + version: 9.25.1(supports-color@8.1.1) + jest-environment-node: + specifier: ~29.5.0 + version: 29.5.0 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + ../../../rigs/heft-web-rig: dependencies: '@microsoft/api-extractor': @@ -4657,15 +4713,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-webpack5-plugin': - specifier: workspace:* - version: link:../../heft-plugins/heft-webpack5-plugin - '@rushstack/package-extractor': + '@rushstack/heft-vscode-extension-rig': specifier: workspace:* - version: link:../../libraries/package-extractor - '@rushstack/webpack-preserve-dynamic-require-plugin': - specifier: workspace:* - version: link:../../webpack/preserve-dynamic-require-plugin + version: link:../../rigs/heft-vscode-extension-rig '@types/glob': specifier: 7.1.1 version: 7.1.1 @@ -4687,15 +4737,145 @@ importers: glob: specifier: ~7.0.5 version: 7.0.6 - local-node-rig: - specifier: workspace:* - version: link:../../rigs/local-node-rig mocha: specifier: ^10.1.0 version: 10.4.0 - vsce: - specifier: ~2.14.0 - version: 2.14.0 + + ../../../vscode-extensions/tls-sync-vscode-extension-pack: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-vscode-extension-rig': + specifier: workspace:* + version: link:../../rigs/heft-vscode-extension-rig + tls-sync-vscode-ui-extension: + specifier: workspace:* + version: link:../tls-sync-vscode-ui-extension + tls-sync-vscode-workspace-extension: + specifier: workspace:* + version: link:../tls-sync-vscode-workspace-extension + + ../../../vscode-extensions/tls-sync-vscode-shared: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: ^1.63.0 + version: 1.87.0 + + ../../../vscode-extensions/tls-sync-vscode-ui-extension: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/tls-sync-vscode-shared': + specifier: workspace:* + version: link:../tls-sync-vscode-shared + '@rushstack/vscode-shared': + specifier: workspace:* + version: link:../vscode-shared + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-vscode-extension-rig': + specifier: workspace:* + version: link:../../rigs/heft-vscode-extension-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: ^1.63.0 + version: 1.87.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + + ../../../vscode-extensions/tls-sync-vscode-workspace-extension: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/tls-sync-vscode-shared': + specifier: workspace:* + version: link:../tls-sync-vscode-shared + '@rushstack/vscode-shared': + specifier: workspace:* + version: link:../vscode-shared + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-vscode-extension-rig': + specifier: workspace:* + version: link:../../rigs/heft-vscode-extension-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: ^1.63.0 + version: 1.87.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + + ../../../vscode-extensions/vscode-shared: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: ^1.63.0 + version: 1.87.0 ../../../webpack/hashed-folder-copy-plugin: dependencies: @@ -9557,6 +9737,30 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} + /@isaacs/balanced-match@4.0.1: + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + dev: false + + /@isaacs/brace-expansion@5.0.0: + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/balanced-match': 4.0.1 + dev: false + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -12574,7 +12778,7 @@ packages: '@storybook/core-events': 6.4.22 core-js: 3.36.0 global: 4.4.0 - qs: 6.13.0 + qs: 6.14.0 telejson: 5.3.3 dev: true @@ -12662,7 +12866,7 @@ packages: global: 4.4.0 lodash: 4.17.21 memoizerific: 1.11.3 - qs: 6.13.0 + qs: 6.14.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 @@ -13311,7 +13515,7 @@ packages: markdown-to-jsx: 7.4.3(react@17.0.2) memoizerific: 1.11.3 polished: 4.3.1 - qs: 6.13.0 + qs: 6.14.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-draggable: 4.4.6(react-dom@17.0.2)(react@17.0.2) @@ -13662,7 +13866,7 @@ packages: /@types/heft-jest@1.0.1: resolution: {integrity: sha512-cF2iEUpvGh2WgLowHVAdjI05xuDo+GwCA8hGV3Q5PBl8apjd6BTcpPFQ2uPlfUM7BLpgur2xpYo8VeBXopMI4A==} dependencies: - '@types/jest': 29.2.5 + '@types/jest': 28.1.1 /@types/hoist-non-react-statics@3.3.5: resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} @@ -13723,7 +13927,6 @@ packages: dependencies: jest-matcher-utils: 27.5.1 pretty-format: 27.5.1 - dev: true /@types/jest@29.2.5: resolution: {integrity: sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==} @@ -14811,6 +15014,128 @@ packages: - supports-color dev: true + /@vscode/vsce-sign-alpine-arm64@2.0.5: + resolution: {integrity: sha512-XVmnF40APwRPXSLYA28Ye+qWxB25KhSVpF2eZVtVOs6g7fkpOxsVnpRU1Bz2xG4ySI79IRuapDJoAQFkoOgfdQ==} + cpu: [arm64] + os: [alpine] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-alpine-x64@2.0.5: + resolution: {integrity: sha512-JuxY3xcquRsOezKq6PEHwCgd1rh1GnhyH6urVEWUzWn1c1PC4EOoyffMD+zLZtFuZF5qR1I0+cqDRNKyPvpK7Q==} + cpu: [x64] + os: [alpine] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-darwin-arm64@2.0.5: + resolution: {integrity: sha512-z2Q62bk0ptADFz8a0vtPvnm6vxpyP3hIEYMU+i1AWz263Pj8Mc38cm/4sjzxu+LIsAfhe9HzvYNS49lV+KsatQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-darwin-x64@2.0.5: + resolution: {integrity: sha512-ma9JDC7FJ16SuPXlLKkvOD2qLsmW/cKfqK4zzM2iJE1PbckF3BlR08lYqHV89gmuoTpYB55+z8Y5Fz4wEJBVDA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-arm64@2.0.5: + resolution: {integrity: sha512-Hr1o0veBymg9SmkCqYnfaiUnes5YK6k/lKFA5MhNmiEN5fNqxyPUCdRZMFs3Ajtx2OFW4q3KuYVRwGA7jdLo7Q==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-arm@2.0.5: + resolution: {integrity: sha512-cdCwtLGmvC1QVrkIsyzv01+o9eR+wodMJUZ9Ak3owhcGxPRB53/WvrDHAFYA6i8Oy232nuen1YqWeEohqBuSzA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-x64@2.0.5: + resolution: {integrity: sha512-XLT0gfGMcxk6CMRLDkgqEPTyG8Oa0OFe1tPv2RVbphSOjFWJwZgK3TYWx39i/7gqpDHlax0AP6cgMygNJrA6zg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-win32-arm64@2.0.5: + resolution: {integrity: sha512-hco8eaoTcvtmuPhavyCZhrk5QIcLiyAUhEso87ApAWDllG7djIrWiOCtqn48k4pHz+L8oCQlE0nwNHfcYcxOPw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-win32-x64@2.0.5: + resolution: {integrity: sha512-1ixKFGM2FwM+6kQS2ojfY3aAelICxjiCzeg4nTHpkeU1Tfs4RC+lVLrgq5NwcBC7ZLr6UfY3Ct3D6suPeOf7BQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign@2.0.6: + resolution: {integrity: sha512-j9Ashk+uOWCDHYDxgGsqzKq5FXW9b9MW7QqOIYZ8IYpneJclWTBeHZz2DJCSKQgo+JAqNcaRRE1hzIx0dswqAw==} + requiresBuild: true + optionalDependencies: + '@vscode/vsce-sign-alpine-arm64': 2.0.5 + '@vscode/vsce-sign-alpine-x64': 2.0.5 + '@vscode/vsce-sign-darwin-arm64': 2.0.5 + '@vscode/vsce-sign-darwin-x64': 2.0.5 + '@vscode/vsce-sign-linux-arm': 2.0.5 + '@vscode/vsce-sign-linux-arm64': 2.0.5 + '@vscode/vsce-sign-linux-x64': 2.0.5 + '@vscode/vsce-sign-win32-arm64': 2.0.5 + '@vscode/vsce-sign-win32-x64': 2.0.5 + dev: false + + /@vscode/vsce@3.3.2: + resolution: {integrity: sha512-XQ4IhctYalSTMwLnMS8+nUaGbU7v99Qm2sOoGfIEf2QC7jpiLXZZMh7NwArEFsKX4gHTJLx0/GqAUlCdC3gKCw==} + engines: {node: '>= 20'} + hasBin: true + dependencies: + '@azure/identity': 4.5.0 + '@vscode/vsce-sign': 2.0.6 + azure-devops-node-api: 12.5.0 + chalk: 2.4.2 + cheerio: 1.0.0-rc.12 + cockatiel: 3.2.1 + commander: 12.1.0 + form-data: 4.0.0 + glob: 11.0.3 + hosted-git-info: 4.1.0 + jsonc-parser: 3.3.1 + leven: 3.1.0 + markdown-it: 14.1.0 + mime: 1.6.0 + minimatch: 3.0.8 + parse-semver: 1.1.1 + read: 1.0.7 + semver: 7.5.4 + tmp: 0.2.3 + typed-rest-client: 1.8.11 + url-join: 4.0.1 + xml2js: 0.5.0 + yauzl: 2.10.0 + yazl: 2.5.1 + optionalDependencies: + keytar: 7.9.0 + transitivePeerDependencies: + - supports-color + dev: false + /@vue/compiler-core@3.4.21: resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==} dependencies: @@ -15331,7 +15656,6 @@ packages: /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: true /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -15352,7 +15676,6 @@ packages: /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: true /ansi-to-html@0.6.15: resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==} @@ -15861,12 +16184,12 @@ packages: xml2js: 0.6.2 dev: true - /azure-devops-node-api@11.2.0: - resolution: {integrity: sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==} + /azure-devops-node-api@12.5.0: + resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} dependencies: tunnel: 0.0.6 typed-rest-client: 1.8.11 - dev: true + dev: false /babel-core@7.0.0-bridge.0(@babel/core@7.20.12): resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} @@ -16397,7 +16720,6 @@ packages: /buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - dev: true /buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -16749,7 +17071,7 @@ packages: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.1.0 - dev: true + dev: false /cheerio@1.0.0-rc.12: resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} @@ -16762,7 +17084,7 @@ packages: htmlparser2: 8.0.2 parse5: 7.1.2 parse5-htmlparser2-tree-adapter: 7.0.0 - dev: true + dev: false /chokidar@2.1.8: resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} @@ -16984,6 +17306,11 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + /cockatiel@3.2.1: + resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} + engines: {node: '>=16'} + dev: false + /code-point-at@1.1.0: resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} engines: {node: '>=0.10.0'} @@ -17078,6 +17405,11 @@ packages: engines: {node: '>=18'} dev: false + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + dev: false + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -17557,7 +17889,7 @@ packages: domhandler: 5.0.3 domutils: 3.1.0 nth-check: 2.1.1 - dev: true + dev: false /css-tree@1.1.3: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} @@ -17816,6 +18148,7 @@ packages: /deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} + requiresBuild: true /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -18008,7 +18341,9 @@ packages: /detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} - dev: true + requiresBuild: true + dev: false + optional: true /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} @@ -18047,7 +18382,6 @@ packages: /diff-sequences@27.5.1: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} @@ -18127,7 +18461,7 @@ packages: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.5.0 - dev: true + dev: false /dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} @@ -18158,7 +18492,7 @@ packages: engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 - dev: true + dev: false /domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -18173,7 +18507,7 @@ packages: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 - dev: true + dev: false /dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -18253,7 +18587,6 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -18300,7 +18633,6 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true /emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} @@ -18380,10 +18712,6 @@ packages: strip-ansi: 6.0.1 dev: true - /entities@2.1.0: - resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} - dev: true - /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -19818,7 +20146,9 @@ packages: /expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - dev: true + requiresBuild: true + dev: false + optional: true /expand-tilde@2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} @@ -20097,7 +20427,6 @@ packages: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} dependencies: pend: 1.2.0 - dev: true /fdir@6.4.6(picomatch@4.0.2): resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} @@ -20368,6 +20697,14 @@ packages: signal-exit: 3.0.7 dev: true + /foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + dev: false + /fork-ts-checker-webpack-plugin@4.1.6: resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} engines: {node: '>=6.11.5', yarn: '>=1.0.0'} @@ -20465,7 +20802,6 @@ packages: /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} @@ -20742,7 +21078,9 @@ packages: /github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - dev: true + requiresBuild: true + dev: false + optional: true /github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} @@ -20793,6 +21131,19 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + /glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + dev: false + /glob@7.0.6: resolution: {integrity: sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==} dependencies: @@ -21228,6 +21579,7 @@ packages: engines: {node: '>=10'} dependencies: lru-cache: 6.0.0 + dev: false /hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} @@ -21330,7 +21682,7 @@ packages: domhandler: 5.0.3 domutils: 3.1.0 entities: 4.5.0 - dev: true + dev: false /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} @@ -21632,10 +21984,6 @@ packages: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} dev: true - /inpath@1.0.2: - resolution: {integrity: sha512-DTt55ovuYFC62a8oJxRjV2MmTPUdxN43Gd8I2ZgawxbAha6PvJkDQy/RbZGFCJF5IXrpp4PAYtW1w3aV7jXkew==} - dev: false - /inquirer@7.3.3: resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} engines: {node: '>=8.0.0'} @@ -22334,6 +22682,13 @@ packages: has-symbols: 1.1.0 set-function-name: 2.0.2 + /jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + dev: false + /jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -22565,7 +22920,6 @@ packages: diff-sequences: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 - dev: true /jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} @@ -22639,7 +22993,6 @@ packages: /jest-get-type@27.5.1: resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true /jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} @@ -22709,7 +23062,6 @@ packages: jest-diff: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 - dev: true /jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} @@ -23225,6 +23577,10 @@ packages: engines: {node: '>=6'} hasBin: true + /jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + dev: false + /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -23335,7 +23691,8 @@ packages: dependencies: node-addon-api: 4.3.0 prebuild-install: 7.1.2 - dev: true + dev: false + optional: true /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -23470,11 +23827,11 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /linkify-it@3.0.3: - resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} + /linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} dependencies: - uc.micro: 1.0.6 - dev: true + uc.micro: 2.1.0 + dev: false /listenercount@1.0.1: resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} @@ -23677,6 +24034,11 @@ packages: highlight.js: 10.7.3 dev: true + /lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + dev: false + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -23777,16 +24139,17 @@ packages: resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} dev: true - /markdown-it@12.3.2: - resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} + /markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true dependencies: argparse: 2.0.1 - entities: 2.1.0 - linkify-it: 3.0.3 - mdurl: 1.0.1 - uc.micro: 1.0.6 - dev: true + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + dev: false /markdown-to-jsx@7.4.3(react@17.0.2): resolution: {integrity: sha512-qwu2XftKs/SP+f6oCe0ruAFKX6jZaKxrBfDBV4CthqbVbRQwHhNM28QGDQuTldCaOn+hocaqbmGvCuXO5m3smA==} @@ -23845,6 +24208,10 @@ packages: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} dev: true + /mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + dev: false + /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -24017,6 +24384,7 @@ packages: /mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + requiresBuild: true /min-document@2.19.0: resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} @@ -24044,6 +24412,13 @@ packages: /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + /minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/brace-expansion': 5.0.0 + dev: false + /minimatch@3.0.8: resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} dependencies: @@ -24190,7 +24565,9 @@ packages: /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true + requiresBuild: true + dev: false + optional: true /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} @@ -24278,6 +24655,7 @@ packages: /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + dev: false /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -24315,7 +24693,9 @@ packages: /napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - dev: true + requiresBuild: true + dev: false + optional: true /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -24361,9 +24741,11 @@ packages: /node-abi@3.56.0: resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} engines: {node: '>=10'} + requiresBuild: true dependencies: semver: 7.5.4 - dev: true + dev: false + optional: true /node-addon-api@3.2.1: resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} @@ -24371,7 +24753,9 @@ packages: /node-addon-api@4.3.0: resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} - dev: true + requiresBuild: true + dev: false + optional: true /node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} @@ -24984,6 +25368,10 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: false + /package-json@7.0.0: resolution: {integrity: sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==} engines: {node: '>=12'} @@ -25061,7 +25449,7 @@ packages: resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} dependencies: semver: 5.7.2 - dev: true + dev: false /parse-statements@1.0.11: resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} @@ -25072,7 +25460,7 @@ packages: dependencies: domhandler: 5.0.3 parse5: 7.1.2 - dev: true + dev: false /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} @@ -25128,6 +25516,14 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + dev: false + /path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} @@ -25159,7 +25555,6 @@ packages: /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - dev: true /picocolors@0.2.1: resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} @@ -25180,10 +25575,6 @@ packages: engines: {node: '>=12'} dev: false - /pidof@1.0.2: - resolution: {integrity: sha512-LLJhTVEUCZnotdAM5rd7KiTdLGgk6i763/hsd5pO+8yuF7mdgg0ob8w/98KrTAcPsj6YzGrkFLPVtBOr1uW2ag==} - dev: false - /pify@3.0.0: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} @@ -25743,6 +26134,7 @@ packages: resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} engines: {node: '>=10'} hasBin: true + requiresBuild: true dependencies: detect-libc: 2.0.2 expand-template: 2.0.3 @@ -25756,7 +26148,8 @@ packages: simple-get: 4.0.1 tar-fs: 2.1.1 tunnel-agent: 0.6.0 - dev: true + dev: false + optional: true /preferred-pm@3.1.3: resolution: {integrity: sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==} @@ -25803,7 +26196,6 @@ packages: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 - dev: true /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -25956,6 +26348,11 @@ packages: inherits: 2.0.4 pump: 2.0.1 + /punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + dev: false + /punycode@1.3.2: resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} dev: true @@ -26023,7 +26420,6 @@ packages: engines: {node: '>=0.6'} dependencies: side-channel: 1.1.0 - dev: false /querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} @@ -26451,6 +26847,7 @@ packages: engines: {node: '>=0.8'} dependencies: mute-stream: 0.0.8 + dev: false /readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -27747,17 +28144,26 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: false + /simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - dev: true + requiresBuild: true + dev: false + optional: true /simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + requiresBuild: true dependencies: decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 - dev: true + dev: false + optional: true /sirv@1.0.19: resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} @@ -28176,7 +28582,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true /string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} @@ -28306,7 +28711,6 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: true /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -28335,6 +28739,7 @@ packages: /strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + requiresBuild: true /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -28394,15 +28799,6 @@ packages: resolution: {integrity: sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==} dev: false - /sudo@1.0.3: - resolution: {integrity: sha512-3xMsaPg+8Xm+4LQm0b2V+G3lz3YxtDBzlqiU8CXw2AOIIDSvC1kBxIxBjnoCTq8dTTXAy23m58g6mdClUocpmQ==} - engines: {node: '>=0.8'} - dependencies: - inpath: 1.0.2 - pidof: 1.0.2 - read: 1.0.7 - dev: false - /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -28507,12 +28903,14 @@ packages: /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + requiresBuild: true dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 pump: 3.0.0 tar-stream: 2.2.0 - dev: true + dev: false + optional: true /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -28523,7 +28921,6 @@ packages: fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true /tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} @@ -28775,7 +29172,7 @@ packages: /tmp@0.2.3: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} - dev: true + dev: false /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -29092,14 +29489,16 @@ packages: /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + requiresBuild: true dependencies: safe-buffer: 5.2.1 - dev: true + dev: false + optional: true /tunnel@0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - dev: true + dev: false /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -29237,10 +29636,10 @@ packages: /typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} dependencies: - qs: 6.13.0 + qs: 6.14.0 tunnel: 0.0.6 underscore: 1.13.6 - dev: true + dev: false /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -29273,9 +29672,9 @@ packages: engines: {node: '>=14.17'} hasBin: true - /uc.micro@1.0.6: - resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} - dev: true + /uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + dev: false /uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} @@ -29304,7 +29703,7 @@ packages: /underscore@1.13.6: resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} - dev: true + dev: false /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -29526,7 +29925,7 @@ packages: /url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - dev: true + dev: false /url-loader@4.1.1(file-loader@6.2.0)(webpack@4.47.0): resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==} @@ -29761,34 +30160,6 @@ packages: /vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - /vsce@2.14.0: - resolution: {integrity: sha512-LH0j++sHjcFNT++SYcJ86Zyw49GvyoTRfzYJGmaCgfzTyL7MyMhZeVEnj9K9qKh/m1N3/sdWWNxP+PFS/AvWiA==} - engines: {node: '>= 14'} - deprecated: vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead. - hasBin: true - dependencies: - azure-devops-node-api: 11.2.0 - chalk: 2.4.2 - cheerio: 1.0.0-rc.12 - commander: 6.2.1 - glob: 7.0.6 - hosted-git-info: 4.1.0 - keytar: 7.9.0 - leven: 3.1.0 - markdown-it: 12.3.2 - mime: 1.6.0 - minimatch: 3.0.8 - parse-semver: 1.1.1 - read: 1.0.7 - semver: 5.7.2 - tmp: 0.2.3 - typed-rest-client: 1.8.11 - url-join: 4.0.1 - xml2js: 0.4.23 - yauzl: 2.10.0 - yazl: 2.5.1 - dev: true - /w3c-xmlserializer@4.0.0: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} engines: {node: '>=14'} @@ -30385,7 +30756,6 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -30479,13 +30849,13 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - /xml2js@0.4.23: - resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + /xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} dependencies: sax: 1.3.0 xmlbuilder: 11.0.1 - dev: true + dev: false /xml2js@0.6.2: resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} @@ -30502,7 +30872,6 @@ packages: /xmlbuilder@11.0.1: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} - dev: true /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -30623,13 +30992,12 @@ packages: dependencies: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 - dev: true /yazl@2.5.1: resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} dependencies: buffer-crc32: 0.2.13 - dev: true + dev: false /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index d3eff4b0498..7d1c539babc 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "f7608960f8f1a8c1232f2d12dabeaa3369bc428b", + "pnpmShrinkwrapHash": "79f96eccf6ba5dbdba5a8478dc7fa309e2747884", "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9" } diff --git a/common/reviews/api/debug-certificate-manager.api.md b/common/reviews/api/debug-certificate-manager.api.md index 863a0d77872..536abe8b1f3 100644 --- a/common/reviews/api/debug-certificate-manager.api.md +++ b/common/reviews/api/debug-certificate-manager.api.md @@ -8,14 +8,16 @@ import type { ITerminal } from '@rushstack/terminal'; // @public export class CertificateManager { - constructor(); + constructor(options?: ICertificateManagerOptions); + readonly certificateStore: CertificateStore; ensureCertificateAsync(canGenerateNewCertificate: boolean, terminal: ITerminal, options?: ICertificateGenerationOptions): Promise; untrustCertificateAsync(terminal: ITerminal): Promise; + validateCertificateAsync(terminal: ITerminal, options?: ICertificateGenerationOptions): Promise; } // @public export class CertificateStore { - constructor(); + constructor(options?: ICertificateStoreOptions); get caCertificateData(): string | undefined; set caCertificateData(certificate: string | undefined); get caCertificatePath(): string; @@ -24,6 +26,8 @@ export class CertificateStore { get certificatePath(): string; get keyData(): string | undefined; set keyData(key: string | undefined); + get keyPath(): string; + get storePath(): string; } // @public @@ -45,4 +49,23 @@ export interface ICertificateGenerationOptions { validityInDays?: number; } +// @public +export interface ICertificateManagerOptions extends ICertificateStoreOptions { +} + +// @public +export interface ICertificateStoreOptions { + caCertificateFilename?: string; + certificateFilename?: string; + keyFilename?: string; + storePath?: string; +} + +// @public +export interface ICertificateValidationResult { + certificate?: ICertificate; + isValid: boolean; + validationMessages: string[]; +} + ``` diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index 85b452da201..a0fc83dccdc 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -40,6 +40,7 @@ export class Async { weighted: true; }): Promise; static runWithRetriesAsync({ action, maxRetries, retryDelayMs }: IRunWithRetriesOptions): Promise; + static runWithTimeoutAsync({ action, timeoutMs, timeoutMessage }: IRunWithTimeoutOptions): Promise; static sleepAsync(ms: number): Promise; static validateWeightedIterable(operation: IWeighted): void; } @@ -623,6 +624,13 @@ export interface IRunWithRetriesOptions { retryDelayMs?: number; } +// @public (undocumented) +export interface IRunWithTimeoutOptions { + action: () => Promise | TResult; + timeoutMessage?: string; + timeoutMs: number; +} + // @public export interface IStringBuilder { append(text: string): void; diff --git a/heft-plugins/heft-vscode-extension-plugin/.npmignore b/heft-plugins/heft-vscode-extension-plugin/.npmignore new file mode 100644 index 00000000000..65edae3d51a --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/.npmignore @@ -0,0 +1,28 @@ +# Ignore everything by default +** + +# Use negative patterns to bring back the specific things we want to publish +!/bin/** +!/lib/** +!/dist/** +!ThirdPartyNotice.txt +!/EULA/** + +# Ignore certain files in the above folder +/dist/*.stats.* +/lib/**/test/** +/lib/**/*.js.map +/dist/**/*.js.map + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README (and its variants) +# CHANGELOG (and its variants) +# LICENSE / LICENCE + +## Project specific definitions +# ----------------------------- + +# (Add your exceptions here) +!heft-plugin.json diff --git a/heft-plugins/heft-vscode-extension-plugin/LICENSE b/heft-plugins/heft-vscode-extension-plugin/LICENSE new file mode 100644 index 00000000000..80caec73dd4 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-vscode-extension-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-vscode-extension-plugin/README.md b/heft-plugins/heft-vscode-extension-plugin/README.md new file mode 100644 index 00000000000..70ece6d3ffe --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-vscode-extension-plugin + +This is a Heft plugin for packaging Visual Studio Code extensions using the `vsce` tool. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-vscode-extension-plugin/config/rig.json b/heft-plugins/heft-vscode-extension-plugin/config/rig.json new file mode 100644 index 00000000000..6ac88a96368 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-node-rig" +} diff --git a/heft-plugins/heft-vscode-extension-plugin/eslint.config.js b/heft-plugins/heft-vscode-extension-plugin/eslint.config.js new file mode 100644 index 00000000000..006cb82d1c0 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/eslint.config.js @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json b/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json new file mode 100644 index 00000000000..98845cc6151 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "vscode-extension-package-plugin", + "entryPoint": "./lib/VSCodeExtensionPackagePlugin.js" + } + ] +} diff --git a/heft-plugins/heft-vscode-extension-plugin/package.json b/heft-plugins/heft-vscode-extension-plugin/package.json new file mode 100644 index 00000000000..869093d09fb --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/package.json @@ -0,0 +1,35 @@ +{ + "name": "@rushstack/heft-vscode-extension-plugin", + "version": "0.0.0", + "description": "Heft plugin for building vscode extensions.", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-vscode-extension-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "main": "lib/index.js", + "types": "lib/index.d.ts", + "peerDependencies": { + "@rushstack/heft": "^0.73.6" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-node-rig": "workspace:*", + "eslint": "~9.25.1", + "@types/node": "20.17.19" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@vscode/vsce": "3.3.2", + "@rushstack/terminal": "workspace:*" + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts new file mode 100644 index 00000000000..e5b4cc694ba --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; +import { Executable, IWaitForExitResult } from '@rushstack/node-core-library'; +import type { ChildProcess } from 'node:child_process'; +import * as path from 'node:path'; +import { TerminalStreamWritable, TerminalProviderSeverity } from '@rushstack/terminal'; + +interface IVSCodeExtensionPackagePluginOptions { + /** + * The folder where the unpacked VSIX files are located. + * This is typically the output folder of the VSCode extension build. + */ + unpackedFolderPath: string; + /** + * The path where the packaged VSIX file will be saved. + * This can be a directory or a full vsix file path. + * If a directory is provided, the VSIX file will be named based on the extension's `package.json` name and version. + */ + vsixPath: string; +} + +const PLUGIN_NAME: 'vscode-extension-package-plugin' = 'vscode-extension-package-plugin'; + +const vsceBasePackagePath: string = require.resolve('@vscode/vsce/package.json'); +const vsceScript: string = path.resolve(vsceBasePackagePath, '../vsce'); + +export default class VSCodeExtensionPackagePlugin + implements IHeftTaskPlugin +{ + public apply( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IVSCodeExtensionPackagePluginOptions + ): void { + heftTaskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { unpackedFolderPath, vsixPath } = pluginOptions; + const { + logger: { terminal } + } = heftTaskSession; + + terminal.writeLine(`Using VSCE script: ${vsceScript}`); + terminal.writeLine(`Packaging VSIX from ${unpackedFolderPath} to ${vsixPath}`); + const terminalOutStream: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.log + }); + const terminalErrorStream: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.error + }); + + const childProcess: ChildProcess = Executable.spawn( + 'node', + [vsceScript, 'package', '--no-dependencies', '--out', `${path.resolve(vsixPath)}`], + { + currentWorkingDirectory: path.resolve(unpackedFolderPath), + stdio: [ + 'ignore', // stdin + 'pipe', // stdout + 'pipe' // stderr + ] + } + ); + + childProcess.stdout?.pipe(terminalOutStream); + childProcess.stderr?.pipe(terminalErrorStream); + + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + + if (result.exitCode !== 0) { + throw new Error(`VSIX packaging failed with exit code ${result.exitCode}`); + } + terminal.writeLine('VSIX successfully packaged.'); + }); + } +} diff --git a/heft-plugins/heft-vscode-extension-plugin/tsconfig.json b/heft-plugins/heft-vscode-extension-plugin/tsconfig.json new file mode 100644 index 00000000000..7f8cf47e02b --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/tsconfig.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/debug-certificate-manager/package.json b/libraries/debug-certificate-manager/package.json index 61075b84ce5..6c1ee38c441 100644 --- a/libraries/debug-certificate-manager/package.json +++ b/libraries/debug-certificate-manager/package.json @@ -17,8 +17,7 @@ "dependencies": { "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", - "node-forge": "~1.3.1", - "sudo": "~1.0.3" + "node-forge": "~1.3.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", diff --git a/libraries/debug-certificate-manager/src/CertificateManager.ts b/libraries/debug-certificate-manager/src/CertificateManager.ts index ece1808321d..b89e3ca74ca 100644 --- a/libraries/debug-certificate-manager/src/CertificateManager.ts +++ b/libraries/debug-certificate-manager/src/CertificateManager.ts @@ -2,13 +2,13 @@ // See LICENSE in the project root for license information. import type { pki } from 'node-forge'; -import * as path from 'path'; -import { EOL } from 'os'; +import * as path from 'node:path'; +import { EOL } from 'node:os'; import { FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import { runSudoAsync, type IRunResult, runAsync } from './runCommand'; -import { CertificateStore } from './CertificateStore'; +import { darwinRunSudoAsync, type IRunResult, randomTmpPath, runAsync } from './runCommand'; +import { CertificateStore, type ICertificateStoreOptions } from './CertificateStore'; const CA_SERIAL_NUMBER: string = '731c321744e34650a202e3ef91c3c1b0'; const TLS_SERIAL_NUMBER: string = '731c321744e34650a202e3ef00000001'; @@ -60,6 +60,27 @@ export interface ICertificate { subjectAltNames: readonly string[] | undefined; } +/** + * Information about certificate validation results + * @public + */ +export interface ICertificateValidationResult { + /** + * Whether valid certificates exist and are usable + */ + isValid: boolean; + + /** + * List of validation messages/issues found + */ + validationMessages: string[]; + + /** + * The existing certificate if it exists and is valid + */ + certificate?: ICertificate; +} + interface ICaCertificate { /** * Certificate @@ -116,6 +137,12 @@ export interface ICertificateGenerationOptions { skipCertificateTrust?: boolean; } +/** + * Options for configuring the `CertificateManager`. + * @public + */ +export interface ICertificateManagerOptions extends ICertificateStoreOptions {} + const MAX_CERTIFICATE_VALIDITY_DAYS: 365 = 365; /** @@ -124,10 +151,14 @@ const MAX_CERTIFICATE_VALIDITY_DAYS: 365 = 365; * @public */ export class CertificateManager { - private _certificateStore: CertificateStore; + /** + * Get the certificate store used by this manager. + * @public + */ + public readonly certificateStore: CertificateStore; - public constructor() { - this._certificateStore = new CertificateStore(); + public constructor(options: ICertificateManagerOptions = {}) { + this.certificateStore = new CertificateStore(options); } /** @@ -143,8 +174,6 @@ export class CertificateManager { ): Promise { const optionsWithDefaults: Required = applyDefaultOptions(options); - const { certificateData: existingCert, keyData: existingKey } = this._certificateStore; - if (process.env[DISABLE_CERT_GENERATION_VARIABLE_NAME] === '1') { // Allow the environment (e.g. GitHub codespaces) to forcibly disable dev cert generation terminal.writeLine( @@ -153,102 +182,34 @@ export class CertificateManager { canGenerateNewCertificate = false; } - if (existingCert && existingKey) { - const messages: string[] = []; - - const forge: typeof import('node-forge') = await import('node-forge'); - const certificate: pki.Certificate = forge.pki.certificateFromPem(existingCert); - const altNamesExtension: ISubjectAltNameExtension | undefined = certificate.getExtension( - 'subjectAltName' - ) as ISubjectAltNameExtension; - if (!altNamesExtension) { - messages.push( - 'The existing development certificate is missing the subjectAltName ' + - 'property and will not work with the latest versions of some browsers.' - ); - } else { - const missingSubjectNames: Set = new Set(optionsWithDefaults.subjectAltNames); - for (const altName of altNamesExtension.altNames) { - missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value); - } - if (missingSubjectNames.size) { - messages.push( - `The existing development certificate does not include the following expected subjectAltName values: ` + - Array.from(missingSubjectNames, (name: string) => `"${name}"`).join(', ') - ); - } - } - - const { notBefore, notAfter } = certificate.validity; - const now: Date = new Date(); - if (now < notBefore) { - messages.push( - `The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.` - ); - } - - if (now > notAfter) { - messages.push( - `The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.` - ); - } - - now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays); - if (notAfter > now) { - messages.push( - `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` + - `This will be rejected by many browsers.` - ); - } - - if ( - notBefore.getTime() - notAfter.getTime() > - optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS - ) { - messages.push( - "The existing development certificate's validity period is longer " + - `than ${optionsWithDefaults.validityInDays} days.` - ); - } + // Validate existing certificates + const validationResult: ICertificateValidationResult = await this.validateCertificateAsync( + terminal, + options + ); - const { caCertificateData } = this._certificateStore; + if (validationResult.isValid && validationResult.certificate) { + // Existing certificate is valid, return it + return validationResult.certificate; + } - if (!caCertificateData) { - messages.push( - 'The existing development certificate is missing a separate CA cert as the root ' + - 'of trust and will not work with the latest versions of some browsers.' + // Certificate is invalid or doesn't exist + if (validationResult.validationMessages.length > 0) { + if (canGenerateNewCertificate) { + validationResult.validationMessages.push( + 'Attempting to untrust the certificate and generate a new one.' ); - } - - const isTrusted: boolean = await this._detectIfCertificateIsTrustedAsync(terminal); - if (!isTrusted) { - messages.push('The existing development certificate is not currently trusted by your system.'); - } - - if (messages.length > 0) { - if (canGenerateNewCertificate) { - messages.push('Attempting to untrust the certificate and generate a new one.'); - terminal.writeWarningLine(messages.join(' ')); - if (!options?.skipCertificateTrust) { - await this.untrustCertificateAsync(terminal); - } - return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); - } else { - messages.push( - 'Untrust the certificate and generate a new one, or set the ' + - '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.' - ); - throw new Error(messages.join(' ')); + terminal.writeWarningLine(validationResult.validationMessages.join(' ')); + if (!options?.skipCertificateTrust) { + await this.untrustCertificateAsync(terminal); } + return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); } else { - return { - pemCaCertificate: caCertificateData, - pemCertificate: existingCert, - pemKey: existingKey, - subjectAltNames: altNamesExtension.altNames.map((entry) => - isIPAddress(entry) ? entry.ip : entry.value - ) - }; + validationResult.validationMessages.push( + 'Untrust the certificate and generate a new one, or set the ' + + '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.' + ); + throw new Error(validationResult.validationMessages.join(' ')); } } else if (canGenerateNewCertificate) { return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); @@ -266,8 +227,9 @@ export class CertificateManager { * @public */ public async untrustCertificateAsync(terminal: ITerminal): Promise { - this._certificateStore.certificateData = undefined; - this._certificateStore.keyData = undefined; + this.certificateStore.certificateData = undefined; + this.certificateStore.keyData = undefined; + this.certificateStore.caCertificateData = undefined; switch (process.platform) { case 'win32': @@ -292,7 +254,7 @@ export class CertificateManager { const macFindCertificateResult: IRunResult = await runAsync('security', [ 'find-certificate', '-c', - 'localhost', + CA_ALT_NAME, '-a', '-Z', MAC_KEYCHAIN @@ -315,7 +277,7 @@ export class CertificateManager { terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`); } - const macUntrustResult: IRunResult = await runSudoAsync('security', [ + const macUntrustResult: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ 'delete-certificate', '-Z', shaHash, @@ -335,7 +297,7 @@ export class CertificateManager { terminal.writeLine( 'Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' + 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' + - `root certification authorities: "${this._certificateStore.certificatePath}". The ` + + `root certification authorities: "${this.certificateStore.certificatePath}". The ` + `certificate has serial number "${CA_SERIAL_NUMBER}".` ); return false; @@ -568,7 +530,7 @@ export class CertificateManager { 'root password in the prompt.' ); - const result: IRunResult = await runSudoAsync('security', [ + const result: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ 'add-trusted-cert', '-d', '-r', @@ -639,7 +601,7 @@ export class CertificateManager { const macFindCertificateResult: IRunResult = await runAsync('security', [ 'find-certificate', '-c', - 'localhost', + CA_ALT_NAME, '-a', '-Z', MAC_KEYCHAIN @@ -673,7 +635,7 @@ export class CertificateManager { terminal.writeVerboseLine( 'Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' + 'and macOS. Manually verify this development certificate is present in your trusted ' + - `root certification authorities: "${this._certificateStore.certificatePath}". ` + + `root certification authorities: "${this.certificateStore.certificatePath}". ` + `The certificate has serial number "${CA_SERIAL_NUMBER}".` ); // Always return true on Linux to prevent breaking flow. @@ -723,11 +685,12 @@ export class CertificateManager { options: Required, terminal: ITerminal ): Promise { - const certificateStore: CertificateStore = this._certificateStore; + const certificateStore: CertificateStore = this.certificateStore; const generatedCertificate: ICertificate = await this._createDevelopmentCertificateAsync(options); const certificateName: string = Date.now().toString(); - const tempDirName: string = path.join(__dirname, '..', 'temp'); + const tempDirName: string = randomTmpPath('rushstack', 'temp'); + await FileSystem.ensureFolderAsync(tempDirName); const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`); const pemFileContents: string | undefined = generatedCertificate.pemCaCertificate; @@ -769,6 +732,116 @@ export class CertificateManager { }; } + /** + * Validate existing certificates to check if they are usable. + * + * @public + */ + public async validateCertificateAsync( + terminal: ITerminal, + options?: ICertificateGenerationOptions + ): Promise { + const optionsWithDefaults: Required = applyDefaultOptions(options); + const { certificateData: existingCert, keyData: existingKey } = this.certificateStore; + + if (!existingCert || !existingKey) { + return { + isValid: false, + validationMessages: ['No development certificate found.'] + }; + } + + const messages: string[] = []; + + const forge: typeof import('node-forge') = await import('node-forge'); + const parsedCertificate: pki.Certificate = forge.pki.certificateFromPem(existingCert); + const altNamesExtension: ISubjectAltNameExtension | undefined = parsedCertificate.getExtension( + 'subjectAltName' + ) as ISubjectAltNameExtension; + + if (!altNamesExtension) { + messages.push( + 'The existing development certificate is missing the subjectAltName ' + + 'property and will not work with the latest versions of some browsers.' + ); + } else { + const missingSubjectNames: Set = new Set(optionsWithDefaults.subjectAltNames); + for (const altName of altNamesExtension.altNames) { + missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value); + } + if (missingSubjectNames.size) { + messages.push( + `The existing development certificate does not include the following expected subjectAltName values: ` + + Array.from(missingSubjectNames, (name: string) => `"${name}"`).join(', ') + ); + } + } + + const { notBefore, notAfter } = parsedCertificate.validity; + const now: Date = new Date(); + if (now < notBefore) { + messages.push( + `The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.` + ); + } + + if (now > notAfter) { + messages.push( + `The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.` + ); + } + + now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays); + if (notAfter > now) { + messages.push( + `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` + + `This will be rejected by many browsers.` + ); + } + + if ( + notBefore.getTime() - notAfter.getTime() > + optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS + ) { + messages.push( + "The existing development certificate's validity period is longer " + + `than ${optionsWithDefaults.validityInDays} days.` + ); + } + + const { caCertificateData } = this.certificateStore; + + if (!caCertificateData) { + messages.push( + 'The existing development certificate is missing a separate CA cert as the root ' + + 'of trust and will not work with the latest versions of some browsers.' + ); + } + + const isTrusted: boolean = await this._detectIfCertificateIsTrustedAsync(terminal); + if (!isTrusted) { + messages.push('The existing development certificate is not currently trusted by your system.'); + } + + const isValid: boolean = messages.length === 0; + const validCertificate: ICertificate | undefined = isValid + ? { + pemCaCertificate: caCertificateData, + pemCertificate: existingCert, + pemKey: existingKey, + subjectAltNames: altNamesExtension?.altNames.map((entry) => + isIPAddress(entry) ? entry.ip : entry.value + ) + } + : undefined; + + return { + isValid, + validationMessages: messages, + certificate: validCertificate + }; + } + private _parseMacOsMatchingCertificateHash(findCertificateOuput: string): string | undefined { let shaHash: string | undefined = undefined; for (const line of findCertificateOuput.split(EOL)) { diff --git a/libraries/debug-certificate-manager/src/CertificateStore.ts b/libraries/debug-certificate-manager/src/CertificateStore.ts index 999268e0dda..7acfbfd1ca1 100644 --- a/libraries/debug-certificate-manager/src/CertificateStore.ts +++ b/libraries/debug-certificate-manager/src/CertificateStore.ts @@ -6,6 +6,33 @@ import { homedir } from 'os'; import { FileSystem } from '@rushstack/node-core-library'; +/** + * Options for configuring paths and filenames used by the `CertificateStore`. + * @public + */ +export interface ICertificateStoreOptions { + /** + * Path to the directory where the certificate store will be created. + * If not provided, it defaults to `/.rushstack`. + */ + storePath?: string; + /** + * Filename of the CA certificate file within the store directory. + * If not provided, it defaults to `rushstack-ca.pem`. + */ + caCertificateFilename?: string; + /** + * Filename of the TLS certificate file within the store directory. + * If not provided, it defaults to `rushstack-serve.pem`. + */ + certificateFilename?: string; + /** + * Filename of the TLS key file within the store directory. + * If not provided, it defaults to `rushstack-serve.key`. + */ + keyFilename?: string; +} + /** * Store to retrieve and save debug certificate data. * @public @@ -14,24 +41,39 @@ export class CertificateStore { private readonly _caCertificatePath: string; private readonly _certificatePath: string; private readonly _keyPath: string; + private readonly _storePath: string; private _caCertificateData: string | undefined; private _certificateData: string | undefined; private _keyData: string | undefined; - public constructor() { - const unresolvedUserFolder: string = homedir(); - const userProfilePath: string = path.resolve(unresolvedUserFolder); - if (!FileSystem.exists(userProfilePath)) { - throw new Error("Unable to determine the current user's home directory"); + public constructor(options: ICertificateStoreOptions = {}) { + const requestedStorePath: string | undefined = options.storePath; + let storePath: string | undefined; + if (requestedStorePath) { + storePath = path.resolve(requestedStorePath); + } else { + // Default to the user's home directory under `.rushstack` + const unresolvedUserFolder: string = homedir(); + const userProfilePath: string = path.resolve(unresolvedUserFolder); + if (!FileSystem.exists(userProfilePath)) { + throw new Error("Unable to determine the current user's home directory"); + } + storePath = path.join(userProfilePath, '.rushstack'); } + this._storePath = storePath; + FileSystem.ensureFolder(storePath); - const serveDataPath: string = path.join(userProfilePath, '.rushstack'); - FileSystem.ensureFolder(serveDataPath); + this._caCertificatePath = path.join(storePath, options.caCertificateFilename ?? 'rushstack-ca.pem'); + this._certificatePath = path.join(storePath, options.certificateFilename ?? 'rushstack-serve.pem'); + this._keyPath = path.join(storePath, options.keyFilename ?? 'rushstack-serve.key'); + } - this._caCertificatePath = path.join(serveDataPath, 'rushstack-ca.pem'); - this._certificatePath = path.join(serveDataPath, 'rushstack-serve.pem'); - this._keyPath = path.join(serveDataPath, 'rushstack-serve.key'); + /** + * Path to the directory where the debug certificates are stored. + */ + public get storePath(): string { + return this._storePath; } /** @@ -48,6 +90,13 @@ export class CertificateStore { return this._certificatePath; } + /** + * Path to the saved debug TLS key + */ + public get keyPath(): string { + return this._keyPath; + } + /** * Debug Certificate Authority certificate pem file contents. */ diff --git a/libraries/debug-certificate-manager/src/index.ts b/libraries/debug-certificate-manager/src/index.ts index 0802f214a03..02562f4baea 100644 --- a/libraries/debug-certificate-manager/src/index.ts +++ b/libraries/debug-certificate-manager/src/index.ts @@ -21,6 +21,8 @@ export { type ICertificate, CertificateManager, type ICertificateGenerationOptions, + type ICertificateManagerOptions, + type ICertificateValidationResult, DEFAULT_CERTIFICATE_SUBJECT_NAMES } from './CertificateManager'; -export { CertificateStore } from './CertificateStore'; +export { CertificateStore, type ICertificateStoreOptions } from './CertificateStore'; diff --git a/libraries/debug-certificate-manager/src/runCommand.ts b/libraries/debug-certificate-manager/src/runCommand.ts index 3af0c22c0a8..b2a06e04eab 100644 --- a/libraries/debug-certificate-manager/src/runCommand.ts +++ b/libraries/debug-certificate-manager/src/runCommand.ts @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Executable } from '@rushstack/node-core-library'; -import type * as child_process from 'child_process'; +import { Executable, FileSystem, Text } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import type * as child_process from 'node:child_process'; +import * as path from 'node:path'; +import * as os from 'node:os'; export interface IRunResult { stdout: string[]; @@ -13,19 +16,79 @@ export interface IRunResult { exitCode: number; } -export interface ISudoOptions { - cachePassword?: boolean; - prompt?: string; - spawnOptions?: object; +export function randomTmpPath(prefix?: string, suffix?: string): string { + return path.join(os.tmpdir(), `${prefix || 'tmp-'}${Math.random().toString(36).slice(2)}${suffix || ''}`); } -export async function runSudoAsync(command: string, params: string[]): Promise { - const sudo: (args: string[], options: ISudoOptions) => child_process.ChildProcess = require('sudo'); - const result: child_process.ChildProcess = sudo([command, ...params], { - cachePassword: false, - prompt: 'Enter your password: ' - }); - return await _handleChildProcess(result); +export async function darwinRunSudoAsync( + terminal: ITerminal, + command: string, + params: string[] +): Promise { + if (process.platform !== 'darwin') { + throw new Error('This function is only supported on macOS.'); + } + + const basename: string = randomTmpPath('sudo-runner-'); + const stdoutFile: string = `${basename}.stdout`; + const stderrFile: string = `${basename}.stderr`; + const exitFile: string = `${basename}.exit`; + const scriptFile: string = `${basename}.script`; + + const commandStr: string = `${command} ${params.join(' ')}`; + terminal.writeLine(`Running command with elevated privileges: ${commandStr}`); + + // Wrap the shell command in a bash command and capture stdout, stderr, and exit code + const shellScript: string = `#!/bin/bash +set -v +echo "\\n\\nRunning command with elevated privileges: ${commandStr}"; +sudo ${commandStr} > >(tee -a ${stdoutFile}) 2> >(tee -a ${stderrFile} >&2) +echo $? > "${exitFile}" +`; + + FileSystem.writeFile(scriptFile, shellScript); + + // This AppleScript opens a new Terminal window, runs the shell script, waits for it to finish and then closes the Terminal window. + const appleScript: string = ` + tell application "Terminal" + activate + set win to do script "bash '${scriptFile}'" + repeat + delay 0.5 + if not busy of window 1 then exit repeat + end repeat + close window 1 + end tell + `; + + terminal.writeLine(`Running AppleScript: ${appleScript}`); + + const child: child_process.ChildProcess = Executable.spawn('osascript', ['-e', appleScript]); + + await Executable.waitForExitAsync(child); + + const [stdoutContent, stderrContent, exitCodeStr] = await Promise.all([ + FileSystem.readFileAsync(stdoutFile), + FileSystem.readFileAsync(stderrFile), + FileSystem.readFileAsync(exitFile) + ]); + + const stdout: string[] = Text.splitByNewLines(stdoutContent); + const stderr: string[] = Text.splitByNewLines(stderrContent); + const exitCode: number = exitCodeStr ? Number(exitCodeStr) : -1; + + await Promise.all([ + FileSystem.deleteFileAsync(stdoutFile), + FileSystem.deleteFileAsync(stderrFile), + FileSystem.deleteFileAsync(exitFile), + FileSystem.deleteFileAsync(scriptFile) + ]); + + return { + stdout, + stderr, + exitCode + }; } export async function runAsync(command: string, params: string[]): Promise { diff --git a/libraries/node-core-library/src/Async.ts b/libraries/node-core-library/src/Async.ts index 2a2a8de816f..85d0b0fcdb0 100644 --- a/libraries/node-core-library/src/Async.ts +++ b/libraries/node-core-library/src/Async.ts @@ -49,6 +49,27 @@ export interface IRunWithRetriesOptions { retryDelayMs?: number; } +/** + * @remarks + * Used with {@link Async.runWithTimeoutAsync}. + * + * @public + */ +export interface IRunWithTimeoutOptions { + /** + * The action to be performed. The action is executed with a timeout. + */ + action: () => Promise | TResult; + /** + * The timeout in milliseconds. + */ + timeoutMs: number; + /** + * The message to use for the error if the timeout is reached. + */ + timeoutMessage?: string; +} + /** * @remarks * Used with {@link (Async:class).(forEachAsync:2)} and {@link (Async:class).(mapAsync:2)}. @@ -358,6 +379,31 @@ export class Async { public static getSignal(): [Promise, () => void, (err: Error) => void] { return getSignal(); } + + /** + * Runs a promise with a timeout. If the promise does not resolve within the specified timeout, + * it will reject with an error. + * @remarks If the action is completely synchronous, runWithTimeoutAsync doesn't do anything meaningful. + */ + public static async runWithTimeoutAsync({ + action, + timeoutMs, + timeoutMessage = 'Operation timed out' + }: IRunWithTimeoutOptions): Promise { + let timeoutHandle: NodeJS.Timeout | undefined; + const promise: Promise = Promise.resolve(action()); + const timeoutPromise: Promise = new Promise((resolve, reject) => { + timeoutHandle = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs); + }); + + try { + return Promise.race([promise, timeoutPromise]); + } finally { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + } + } } /** diff --git a/libraries/node-core-library/src/index.ts b/libraries/node-core-library/src/index.ts index eb988c247fb..16c5c26da65 100644 --- a/libraries/node-core-library/src/index.ts +++ b/libraries/node-core-library/src/index.ts @@ -15,6 +15,7 @@ export { AsyncQueue, type IAsyncParallelismOptions, type IRunWithRetriesOptions, + type IRunWithTimeoutOptions, type IWeighted } from './Async'; export type { Brand } from './PrimitiveTypes'; diff --git a/rigs/heft-vscode-extension-rig/.npmignore b/rigs/heft-vscode-extension-rig/.npmignore new file mode 100644 index 00000000000..2b485313c3f --- /dev/null +++ b/rigs/heft-vscode-extension-rig/.npmignore @@ -0,0 +1,35 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- + +!/profiles/** +!/shared/** diff --git a/rigs/heft-vscode-extension-rig/LICENSE b/rigs/heft-vscode-extension-rig/LICENSE new file mode 100644 index 00000000000..c0887f981ee --- /dev/null +++ b/rigs/heft-vscode-extension-rig/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-vscode-extension-rig + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/rigs/heft-vscode-extension-rig/README.md b/rigs/heft-vscode-extension-rig/README.md new file mode 100644 index 00000000000..c6f0edc65e5 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/README.md @@ -0,0 +1,30 @@ +## @rushstack/heft-vscode-extension-rig + +A rig package for Node.js projects that build using [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. To learn more about rig packages, consult the +[@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) documentation. + +This rig contains a single profile: `default` + +To enable it, add a **rig.json** file to your project, as shown below: + +**config/rig.json** +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} +``` + +The config files provided by this rig profile can be found in the [heft-vscode-extension-rig/profiles/default]( +https://github.com/microsoft/rushstack/tree/main/rigs/heft-vscode-extension-rig/profiles/default) source folder. + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/rigs/heft-vscode-extension-rig/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/heft-vscode-extension-rig` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/rigs/heft-vscode-extension-rig/package.json b/rigs/heft-vscode-extension-rig/package.json new file mode 100644 index 00000000000..22d232c7a52 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rushstack/heft-vscode-extension-rig", + "version": "0.0.0", + "description": "A rig package for VSCode Extensions that build using Heft", + "license": "MIT", + "scripts": { + "build": "", + "_phase:build": "" + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "rigs/heft-vscode-extension-rig" + }, + "peerDependencies": { + "@rushstack/heft": "^0.74.0" + }, + "dependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft-node-rig": "workspace:*", + "@rushstack/heft-vscode-extension-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "eslint": "~9.25.1", + "jest-environment-node": "~29.5.0", + "typescript": "~5.8.2", + "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*" + } +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json b/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json new file mode 100644 index 00000000000..3f29e70fe23 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/api-extractor-task.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/api-extractor-task.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json b/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json new file mode 100644 index 00000000000..29002b40b08 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json", + + /** + * The list of Heft phases that can be run by Heft. + */ + "phasesByName": { + "build": { + "phaseDescription": "Build and lint the project.", + "cleanFiles": [{ "includeGlobs": ["lib-esm", "lib-dts", "release", ".vscode-test"] }], + + "tasksByName": { + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + }, + "copy-assets": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": ".", + "destinationFolders": ["dist/vsix/unpacked"], + "includeGlobs": ["package.json", "README.md", "LICENSE", ".vscodeignore", "assets/**"] + } + ] + } + } + }, + + "package-vsix": { + "taskDependencies": ["typescript", "webpack", "copy-assets"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-vscode-extension-plugin", + "pluginName": "vscode-extension-package-plugin", + "options": { + "unpackedFolderPath": "dist/vsix/unpacked", + "vsixPath": "dist/vsix/packaged.vsix" + } + } + } + } + } + } +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json b/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json new file mode 100644 index 00000000000..4bb17bde3ee --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json b/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json new file mode 100644 index 00000000000..bce265a4f3f --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + }, + { + "operationName": "build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + } + ] +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json b/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json new file mode 100644 index 00000000000..92590ba960e --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json @@ -0,0 +1,8 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/typescript.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..62d215f24c5 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..31940fac123 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/packlets'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..8a307de74c1 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..6754a7434f0 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js new file mode 100644 index 00000000000..4ec8da74a49 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); + +module.exports = [ + ...nodeTrustedToolProfile, + { + files: ['**/*.ts', '**/*.tsx'], + rules: { + // Rationale: Use of `void` to explicitly indicate that a floating promise is expected + // and allowed. + 'no-void': ['error', { allowAsStatement: true }], + + // Rationale: Use of `console` logging is generally discouraged. Use VS Code output + // channels where possible to surface logs. + 'no-console': ['warn', { allow: ['debug', 'info', 'time', 'timeEnd', 'trace'] }] + } + } +]; diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.js new file mode 100644 index 00000000000..d6374c9eaf7 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + rules: { + // Rationale: Use of `void` to explicitly indicate that a floating promise is expected + // and allowed. + 'no-void': ['error', { allowAsStatement: true }] + } + } +]; diff --git a/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json b/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json new file mode 100644 index 00000000000..a1fa195979a --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "extends": "../../node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "outDir": "../../../../../lib", + "rootDir": "../../../../../src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strict": true, + "useUnknownInCatchVariables": false, + "esModuleInterop": true, + "noEmitOnError": false, + "allowUnreachableCode": false, + "resolveJsonModule": true, + "skipLibCheck": true, + + "types": ["heft-jest"], + "typeRoots": ["../../../../../node_modules/@types", "../../node_modules/@types"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "incremental": true + }, + "include": ["../../../../../src/**/*.ts", "../../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js b/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js new file mode 100644 index 00000000000..e9610c1d27b --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js @@ -0,0 +1,77 @@ +// @ts-check +/* eslint-env es6 */ + +'use strict'; + +const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); + +/** @typedef {import('webpack').Configuration} WebpackConfig **/ +function createExtensionConfig({ production, webpack, entry, outputPath }) { + /** @type WebpackConfig */ + const extensionConfig = { + target: 'node', + mode: production ? 'production' : 'none', + entry, + output: { + path: outputPath, + filename: 'extension.js', + libraryTarget: 'commonjs2' + }, + externals: { + vscode: 'commonjs vscode' + }, + devtool: production ? 'hidden-source-map' : 'source-map', + infrastructureLogging: { + level: 'log' + }, + plugins: [ + new PreserveDynamicRequireWebpackPlugin(), + new webpack.DefinePlugin({ + ___DEV___: JSON.stringify(!production) + }) + ], + optimization: { + minimize: false + } + }; + return extensionConfig; +} + +function createWebExtensionConfig({ production, webpack, entry, outputPath }) { + /** @type WebpackConfig */ + const webExtensionConfig = { + target: 'webworker', // extensions run in a webworker context + mode: production ? 'production' : 'none', + entry, + output: { + filename: 'extension.js', + path: outputPath, + libraryTarget: 'commonjs' + }, + plugins: [ + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1 // disable chunks by default since web extensions must be a single bundle + }), + new webpack.ProvidePlugin({ + process: 'process/browser' // provide a shim for the global `process` variable + }), + new webpack.DefinePlugin({ + ___DEV___: JSON.stringify(!production) + }) + ], + externals: { + vscode: 'commonjs vscode' + }, + devtool: production ? 'hidden-source-map' : 'source-map', + infrastructureLogging: { + level: 'log' + }, + optimization: { + minimize: false + } + }; + + return webExtensionConfig; +} + +module.exports = { createExtensionConfig, createWebExtensionConfig }; diff --git a/rush.json b/rush.json index cc4812d6565..9b6c3c754f3 100644 --- a/rush.json +++ b/rush.json @@ -1101,6 +1101,12 @@ "reviewCategory": "libraries", "shouldPublish": true }, + { + "packageName": "@rushstack/heft-vscode-extension-plugin", + "projectFolder": "heft-plugins/heft-vscode-extension-plugin", + "reviewCategory": "libraries", + "shouldPublish": true + }, { "packageName": "@rushstack/heft-webpack4-plugin", "projectFolder": "heft-plugins/heft-webpack4-plugin", @@ -1229,6 +1235,12 @@ "shouldPublish": true, "decoupledLocalDependencies": ["@rushstack/heft"] }, + { + "packageName": "@rushstack/tls-sync-vscode-shared", + "projectFolder": "vscode-extensions/tls-sync-vscode-shared", + "reviewCategory": "libraries", + "shouldPublish": false + }, { "packageName": "@rushstack/tree-pattern", "projectFolder": "libraries/tree-pattern", @@ -1249,6 +1261,12 @@ "reviewCategory": "libraries", "shouldPublish": true }, + { + "packageName": "@rushstack/vscode-shared", + "projectFolder": "vscode-extensions/vscode-shared", + "reviewCategory": "libraries", + "shouldPublish": false + }, // "repo-scripts" folder (alphabetical order) { @@ -1291,6 +1309,12 @@ "reviewCategory": "libraries", "shouldPublish": true }, + { + "packageName": "@rushstack/heft-vscode-extension-rig", + "projectFolder": "rigs/heft-vscode-extension-rig", + "reviewCategory": "libraries", + "shouldPublish": true + }, { "packageName": "@rushstack/heft-web-rig", "projectFolder": "rigs/heft-web-rig", @@ -1370,12 +1394,35 @@ { "packageName": "rushstack", "projectFolder": "vscode-extensions/rush-vscode-extension", - "reviewCategory": "vscode-extensions" + "reviewCategory": "vscode-extensions", + "tags": ["vsix"] }, { "packageName": "@rushstack/rush-vscode-command-webview", "projectFolder": "vscode-extensions/rush-vscode-command-webview", - "reviewCategory": "vscode-extensions" + "reviewCategory": "vscode-extensions", + "tags": ["vsix"] + }, + { + "packageName": "tls-sync-vscode-workspace-extension", + "projectFolder": "vscode-extensions/tls-sync-vscode-workspace-extension", + "reviewCategory": "vscode-extensions", + "tags": ["vsix"], + "versionPolicyName": "tls-sync-vscode-extensions" + }, + { + "packageName": "tls-sync-vscode-ui-extension", + "projectFolder": "vscode-extensions/tls-sync-vscode-ui-extension", + "reviewCategory": "vscode-extensions", + "tags": ["vsix"], + "versionPolicyName": "tls-sync-vscode-extensions" + }, + { + "packageName": "tls-sync-vscode-extension-pack", + "projectFolder": "vscode-extensions/tls-sync-vscode-extension-pack", + "reviewCategory": "vscode-extensions", + "tags": ["vsix"], + "versionPolicyName": "tls-sync-vscode-extensions" }, // "webpack" folder (alphabetical order) diff --git a/vscode-extensions/rush-vscode-extension/.gitignore b/vscode-extensions/rush-vscode-extension/.gitignore index a9abfdf2fa7..ec8dec70872 100644 --- a/vscode-extensions/rush-vscode-extension/.gitignore +++ b/vscode-extensions/rush-vscode-extension/.gitignore @@ -1,4 +1 @@ webview/ -.vscode-test/ -*.vsix -.vscodeignore \ No newline at end of file diff --git a/vscode-extensions/rush-vscode-extension/.npmignore b/vscode-extensions/rush-vscode-extension/.npmignore index 4724baf483e..dcf329e5ffa 100644 --- a/vscode-extensions/rush-vscode-extension/.npmignore +++ b/vscode-extensions/rush-vscode-extension/.npmignore @@ -1,20 +1,2 @@ # Ignore all files by default, to avoid accidentally publishing unintended files. -* - -# Use negative patterns to bring back the specific things we want to publish. -!/bin/** -!/lib/** -!/lib-*/** -!/dist/** -!ThirdPartyNotice.txt -!resources/** -!webview/** - -# Ignore certain patterns that should not get published. -/dist/*.stats.* -/lib/**/test/ -/lib-*/**/test/ -lib/scripts/ -lib-*/scripts/ -*.test.js -*.map +** diff --git a/vscode-extensions/rush-vscode-extension/.vscodeignore b/vscode-extensions/rush-vscode-extension/.vscodeignore new file mode 100644 index 00000000000..9231798330f --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/.vscodeignore @@ -0,0 +1,9 @@ +** +!LICENSE +!README.md +!extension.js +!package.json +!assets/rushstack-icon.png +!assets/rushstack-icon.svg +!webview/rush-command-webview/bundle.js +!webview/rush-command-webview/index.html diff --git a/vscode-extensions/rush-vscode-extension/resources/rushstack-icon.png b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.png similarity index 100% rename from vscode-extensions/rush-vscode-extension/resources/rushstack-icon.png rename to vscode-extensions/rush-vscode-extension/assets/rushstack-icon.png diff --git a/vscode-extensions/rush-vscode-extension/resources/rushstack-icon.svg b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.svg similarity index 100% rename from vscode-extensions/rush-vscode-extension/resources/rushstack-icon.svg rename to vscode-extensions/rush-vscode-extension/assets/rushstack-icon.svg diff --git a/vscode-extensions/rush-vscode-extension/config/heft.json b/vscode-extensions/rush-vscode-extension/config/heft.json index 15b954e3644..af08cae80ee 100644 --- a/vscode-extensions/rush-vscode-extension/config/heft.json +++ b/vscode-extensions/rush-vscode-extension/config/heft.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - "extends": "local-node-rig/profiles/default/config/heft.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/heft.json", "aliasesByName": { "start": { @@ -14,12 +14,6 @@ "build": { "cleanFiles": [{ "includeGlobs": ["webview"] }], "tasksByName": { - "webpack": { - "taskDependencies": ["typescript"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-webpack5-plugin" - } - }, "copy-webview": { "taskPlugin": { "pluginName": "copy-files-plugin", @@ -34,16 +28,6 @@ ] } } - }, - "generate-vscodeignore": { - "taskDependencies": ["copy-webview", "typescript", "webpack"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft", - "pluginName": "run-script-plugin", - "options": { - "scriptPath": "lib/scripts/generate-vscodeignore.js" - } - } } } } diff --git a/vscode-extensions/rush-vscode-extension/config/rig.json b/vscode-extensions/rush-vscode-extension/config/rig.json index 9d412b88354..ec33a848348 100644 --- a/vscode-extensions/rush-vscode-extension/config/rig.json +++ b/vscode-extensions/rush-vscode-extension/config/rig.json @@ -1,5 +1,5 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "local-node-rig" + "rigPackageName": "@rushstack/heft-vscode-extension-rig" } diff --git a/vscode-extensions/rush-vscode-extension/config/rush-project.json b/vscode-extensions/rush-vscode-extension/config/rush-project.json index c5042646f2c..f4ca51150ee 100644 --- a/vscode-extensions/rush-vscode-extension/config/rush-project.json +++ b/vscode-extensions/rush-vscode-extension/config/rush-project.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - "extends": "local-node-rig/profiles/default/config/rush-project.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/rush-project.json", "operationSettings": [ { "operationName": "_phase:build", diff --git a/vscode-extensions/rush-vscode-extension/eslint.config.js b/vscode-extensions/rush-vscode-extension/eslint.config.js index 3470d28356b..eac79367926 100644 --- a/vscode-extensions/rush-vscode-extension/eslint.config.js +++ b/vscode-extensions/rush-vscode-extension/eslint.config.js @@ -1,21 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); -const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const nodeTrustedToolProfile = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); -module.exports = [ - ...nodeTrustedToolProfile, - ...friendlyLocalsMixin, - { - ignores: ['out', 'dist', '**/*.d.ts'] - }, - { - files: ['**/*.ts', '**/*.tsx'], - languageOptions: { - parserOptions: { - tsconfigRootDir: __dirname - } - } - } -]; +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/rush-vscode-extension/package.json b/vscode-extensions/rush-vscode-extension/package.json index fad55c59819..3f9117a32a6 100644 --- a/vscode-extensions/rush-vscode-extension/package.json +++ b/vscode-extensions/rush-vscode-extension/package.json @@ -37,7 +37,7 @@ "color": "#f0f0f0", "theme": "light" }, - "icon": "resources/rushstack-icon.png", + "icon": "assets/rushstack-icon.png", "badges": [ { "url": "https://img.shields.io/badge/Rush-db714a", @@ -70,17 +70,14 @@ "description": "Rush Stack community support" } ], - "main": "./dist/extension.js", + "main": "./extension.js", "scripts": { "build": "heft build --clean", "build:watch": "heft build-watch", - "vscode:prepublish": "heft build --clean --production", - "deploy": "vsce publish --no-dependencies", - "package": "vsce package --no-dependencies", "start": "heft start", "pretest": "npm run build", "test": "node ./lib/test/runTest.js", - "_phase:build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", "_phase:test": "" }, "contributes": { @@ -238,7 +235,7 @@ { "id": "rushstack", "title": "Rush Stack", - "icon": "resources/rushstack-icon.svg" + "icon": "assets/rushstack-icon.svg" } ] }, @@ -264,10 +261,7 @@ }, "devDependencies": { "@microsoft/rush-lib": "workspace:*", - "@rushstack/heft-webpack5-plugin": "workspace:*", "@rushstack/heft": "workspace:*", - "@rushstack/package-extractor": "workspace:*", - "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", "@types/glob": "7.1.1", "@types/mocha": "10.0.6", "@types/vscode": "^1.63.0", @@ -275,9 +269,8 @@ "@vscode/test-electron": "^1.6.2", "eslint": "~9.25.1", "glob": "~7.0.5", - "local-node-rig": "workspace:*", - "mocha": "^10.1.0", - "vsce": "~2.14.0" + "@rushstack/heft-vscode-extension-rig": "workspace:*", + "mocha": "^10.1.0" }, "engines": { "vscode": "^1.63.0" diff --git a/vscode-extensions/rush-vscode-extension/scripts/vsce-package.js b/vscode-extensions/rush-vscode-extension/scripts/vsce-package.js deleted file mode 100644 index 07443483b20..00000000000 --- a/vscode-extensions/rush-vscode-extension/scripts/vsce-package.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-env es6 */ - -Error.stackTraceLimit = 500; -const fs = require('fs'); -const path = require('path'); -const { execSync } = require('child_process'); -// const packageJson = require('../package.json'); - -// const newPackageJson = { ...packageJson }; -// vsce package throws error if dependencies and devDependencies are present in package.json -// So, delete them here and use a new package.json for packaging -// delete newPackageJson.dependencies; -// delete newPackageJson.devDependencies; -const vscePath = path.resolve(__dirname, '../node_modules/.bin/vsce'); -// const packageJsonPath = path.resolve(__dirname, '../package.json'); - -const PACKAGE_NAME = 'rushstack'; - -const getPackageVersion = () => { - const now = new Date(); - const month = now.getMonth() + 1; - const year = now.getFullYear().toString().slice(2); - const date = now.getDate(); - const hour = now.getHours(); - const min = now.getMinutes(); - const version = `${year}_${month}_${date}_${hour}_${min}`; - return version; -}; -const PACKAGE_VERSION = getPackageVersion(); - -const disposes = []; - -if (!fs.existsSync(vscePath)) { - console.error('vsce not found'); - process.exit(1); -} - -// backup current package.json -// const backupPackageJsonPath = path.resolve(__dirname, '../package.json.backup'); -// const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8'); -// fs.writeFileSync(backupPackageJsonPath, packageJsonContent); - -console.log('packaging...'); -// mimic package.json for vsce -// fs.writeFileSync(packageJsonPath, JSON.stringify(newPackageJson, null, 2) + '\n'); -// console.log('package.json for vsce ready'); - -// disposes.push(() => { -// fs.writeFileSync(packageJsonPath, packageJsonContent); -// fs.unlinkSync(backupPackageJsonPath); -// }); - -// node_modules back and forth -// const nodeModulesPath = path.resolve(__dirname, '../node_modules'); -// const nodeModulesBackupPath = path.resolve(__dirname, '../node_modules.backup'); -// fs.renameSync(nodeModulesPath, nodeModulesBackupPath); -// disposes.push(() => { -// // fs.unlinkSync(nodeModulesPath); -// fs.renameSync(nodeModulesBackupPath, nodeModulesPath); -// }); - -const outFilename = `${PACKAGE_NAME}-${PACKAGE_VERSION}.vsix`; - -try { - execSync(`${vscePath} package --no-dependencies --out ${outFilename}`, { - stdio: 'inherit' - }); - console.log('vsce package successfully'); -} catch (err) { - if (err) { - console.error('vsce package error: ', err); - } -} finally { - disposes.forEach((fn) => fn()); -} diff --git a/vscode-extensions/rush-vscode-extension/src/scripts/generate-vscodeignore.ts b/vscode-extensions/rush-vscode-extension/src/scripts/generate-vscodeignore.ts deleted file mode 100644 index a816832a73e..00000000000 --- a/vscode-extensions/rush-vscode-extension/src/scripts/generate-vscodeignore.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import type { IRunScriptOptions } from '@rushstack/heft'; -import { FileSystem } from '@rushstack/node-core-library'; -import { PackageExtractor } from '@rushstack/package-extractor'; - -export async function runAsync({ - heftConfiguration: { buildFolderPath }, - heftTaskSession: { logger } -}: IRunScriptOptions): Promise { - const includedFilePaths: string[] = await PackageExtractor.getPackageIncludedFilesAsync(buildFolderPath); - includedFilePaths.sort(); - const vscodeIgnoreLines: string[] = ['**']; - for (const folderItemPath of includedFilePaths) { - vscodeIgnoreLines.push(`!${folderItemPath}`); - } - - const vscodeignorePath: string = `${buildFolderPath}/.vscodeignore`; - await FileSystem.writeFileAsync(vscodeignorePath, vscodeIgnoreLines.join('\n') + '\n'); -} diff --git a/vscode-extensions/rush-vscode-extension/tsconfig.json b/vscode-extensions/rush-vscode-extension/tsconfig.json index a42ac59b34b..1226387ecf8 100644 --- a/vscode-extensions/rush-vscode-extension/tsconfig.json +++ b/vscode-extensions/rush-vscode-extension/tsconfig.json @@ -1,7 +1,3 @@ { - "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", - "compilerOptions": { - "lib": ["es2015", "DOM"], - "types": ["mocha", "node", "webpack-env"] - } + "extends": "./node_modules/@rushstack/heft-vscode-extension-rig/profiles/default/tsconfig-base.json" } diff --git a/vscode-extensions/rush-vscode-extension/webpack.config.js b/vscode-extensions/rush-vscode-extension/webpack.config.js index 7e35e8bdc3f..54f783e08c3 100644 --- a/vscode-extensions/rush-vscode-extension/webpack.config.js +++ b/vscode-extensions/rush-vscode-extension/webpack.config.js @@ -3,47 +3,27 @@ 'use strict'; -const path = require('path'); -// eslint-disable-next-line @typescript-eslint/naming-convention -const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); +const { + createExtensionConfig +} = require('@rushstack/heft-vscode-extension-rig/profiles/default/webpack.config.base'); +const path = require('node:path'); -// @ts-check -/** @typedef {import('webpack').Configuration} WebpackConfig **/ +function createConfig({ production, webpack }) { + const config = createExtensionConfig({ + production, + webpack, + entry: { + extension: './lib/extension.js' + }, + outputPath: path.resolve(__dirname, 'dist', 'vsix', 'unpacked') + }); -function createExtensionConfig({ production, webpack }) { - /** @type WebpackConfig */ - const extensionConfig = { - target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ - mode: production ? 'production' : 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') + if (!config.externals) { + config.externals = {}; + } + config.externals['@microsoft/rush-lib'] = 'commonjs @microsoft/rush-lib'; - entry: './lib/extension.js', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ - output: { - // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ - path: path.resolve(__dirname, 'dist'), - filename: 'extension.js', - libraryTarget: 'commonjs2' - }, - externals: { - // eslint-disable-next-line @typescript-eslint/naming-convention - '@microsoft/rush-lib': 'commonjs @microsoft/rush-lib', - vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ - // modules added here also need to be added in the .vscodeignore file - }, - devtool: production ? 'hidden-source-map' : 'source-map', - infrastructureLogging: { - level: 'log' // enables logging required for problem matchers - }, - plugins: [ - // @ts-ignore - new PreserveDynamicRequireWebpackPlugin(), - new webpack.DefinePlugin({ - ___DEV___: JSON.stringify(!production) - }) - ], - optimization: { - minimize: false // Ensure licenses are included in the bundle - } - }; - return extensionConfig; + return config; } -module.exports = createExtensionConfig; + +module.exports = createConfig; diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/.npmignore b/vscode-extensions/tls-sync-vscode-extension-pack/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/.vscodeignore b/vscode-extensions/tls-sync-vscode-extension-pack/.vscodeignore new file mode 100644 index 00000000000..9a22e7e9769 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/.vscodeignore @@ -0,0 +1,5 @@ +** +!LICENSE +!README.md +!package.json +!assets/extension-icon.png diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/LICENSE b/vscode-extensions/tls-sync-vscode-extension-pack/LICENSE new file mode 100644 index 00000000000..a79de558c93 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/LICENSE @@ -0,0 +1,24 @@ +tls-sync-vscode-extension-pack + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/README.md b/vscode-extensions/tls-sync-vscode-extension-pack/README.md new file mode 100644 index 00000000000..fc4ddd50127 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/README.md @@ -0,0 +1,19 @@ +# TLS Sync VS Code Extension Pack + +## Sync Process + +The workspace and UI extensions work together to use `@rushstack/debug-certificate-manager` to manage TLS certificates. The UI extension manages the machine where the VS Code client is running, while the Workspace extension manages the remote workspace (WSL, Codespaces, Devcontainers, VS Code Tunnels). + +Both the UI and Workspace extensions must be installed for the sync process to work. + +1. VS Code activates the UI extension if `.tlssync` file is present in the workspace or if the user runs the Sync command. +2. The UI extension checks if the Workspace extension is available. +3. If the Workspace extension is available, it ensures that valid certificates are present in the local certificate store. If not, it generates a new certificate and stores it in the local certificate store. +4. The UI extension then sends the certificate to the Workspace extension. + +The certificate store paths and the file names can be configured in the VS Code settings. Run the `TLS Sync: Show Settings` command to view and modify the configuration. + +## Extensions + +- [TLS Sync VS Code (UI Extension)](../tls-sync-vscode-ui-extension) +- [TLS Sync VS Code (Workspace Extension)](../tls-sync-vscode-extension-pack) diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/assets/extension-icon.png b/vscode-extensions/tls-sync-vscode-extension-pack/assets/extension-icon.png new file mode 100644 index 00000000000..ee2bd331df9 Binary files /dev/null and b/vscode-extensions/tls-sync-vscode-extension-pack/assets/extension-icon.png differ diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/config/heft.json b/vscode-extensions/tls-sync-vscode-extension-pack/config/heft.json new file mode 100644 index 00000000000..e1dd458ed26 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/config/heft.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/heft.json" +} diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/config/rig.json b/vscode-extensions/tls-sync-vscode-extension-pack/config/rig.json new file mode 100644 index 00000000000..ec33a848348 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/config/rush-project.json b/vscode-extensions/tls-sync-vscode-extension-pack/config/rush-project.json new file mode 100644 index 00000000000..b2453d544bc --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/config/rush-project.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/rush-project.json" +} diff --git a/vscode-extensions/tls-sync-vscode-extension-pack/package.json b/vscode-extensions/tls-sync-vscode-extension-pack/package.json new file mode 100644 index 00000000000..3b9db955878 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-extension-pack/package.json @@ -0,0 +1,45 @@ +{ + "name": "tls-sync-vscode-extension-pack", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/tls-sync-vscode-extension-pack" + }, + "license": "MIT", + "publisher": "RushStack", + "preview": true, + "displayName": "TLS Sync", + "description": "", + "homepage": "https://github.com/microsoft/rushstack/tree/main/vscode-extensions/tls-sync-vscode-extension-pack", + "icon": "assets/extension-icon.png", + "categories": [ + "Other" + ], + "extensionPack": [ + "Rushstack.tls-sync-vscode-ui-extension", + "Rushstack.tls-sync-vscode-workspace-extension" + ], + "keywords": [], + "galleryBanner": { + "color": "#f0f0f0", + "theme": "light" + }, + "engines": { + "vscode": "^1.98.0" + }, + "scripts": { + "build": "heft build --clean", + "build:watch": "heft build-watch", + "start": "heft start", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "" + }, + "dependencies": {}, + "devDependencies": { + "@rushstack/heft-vscode-extension-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "tls-sync-vscode-ui-extension": "workspace:*", + "tls-sync-vscode-workspace-extension": "workspace:*" + } +} diff --git a/vscode-extensions/tls-sync-vscode-shared/.npmignore b/vscode-extensions/tls-sync-vscode-shared/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/tls-sync-vscode-shared/LICENSE b/vscode-extensions/tls-sync-vscode-shared/LICENSE new file mode 100644 index 00000000000..1fefe388f93 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/LICENSE @@ -0,0 +1,24 @@ +@rushstack/tls-sync-vscode-shared + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vscode-extensions/tls-sync-vscode-shared/README.md b/vscode-extensions/tls-sync-vscode-shared/README.md new file mode 100644 index 00000000000..7cbcf0522b6 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/README.md @@ -0,0 +1,3 @@ +# @rushstack/tls-sync-vscode-shared + +This library provides a set of utilities for TLS Sync VS Code extensions. diff --git a/vscode-extensions/tls-sync-vscode-shared/config/rig.json b/vscode-extensions/tls-sync-vscode-shared/config/rig.json new file mode 100644 index 00000000000..58032e098f0 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-node-rig" +} diff --git a/vscode-extensions/tls-sync-vscode-shared/eslint.config.js b/vscode-extensions/tls-sync-vscode-shared/eslint.config.js new file mode 100644 index 00000000000..006cb82d1c0 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/eslint.config.js @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/tls-sync-vscode-shared/package.json b/vscode-extensions/tls-sync-vscode-shared/package.json new file mode 100644 index 00000000000..b09528d52ac --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/package.json @@ -0,0 +1,29 @@ +{ + "name": "@rushstack/tls-sync-vscode-shared", + "version": "0.0.0", + "description": "", + "main": "lib/index.js", + "typings": "dist/index.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/tls-sync-vscode-shared" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft-node-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/vscode": "^1.63.0" + } +} diff --git a/vscode-extensions/tls-sync-vscode-shared/src/certificates.ts b/vscode-extensions/tls-sync-vscode-shared/src/certificates.ts new file mode 100644 index 00000000000..16537281730 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/src/certificates.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { getConfig } from './config'; +import { CertificateManager, CertificateStore } from '@rushstack/debug-certificate-manager'; +import type { ITerminal } from '@rushstack/terminal'; + +export function getCertificateManager( + terminal: ITerminal, + configType: 'ui' | 'workspace' +): CertificateManager { + const { caCertificateFilename, keyFilename, certificateFilename, storePath } = getConfig( + terminal, + configType + ); + const certificateManager: CertificateManager = new CertificateManager({ + caCertificateFilename, + keyFilename, + certificateFilename, + storePath + }); + + return certificateManager; +} + +export function getCertificateStore(terminal: ITerminal, configType: 'ui' | 'workspace'): CertificateStore { + const { caCertificateFilename, keyFilename, certificateFilename, storePath } = getConfig( + terminal, + configType + ); + const certificateStore: CertificateStore = new CertificateStore({ + caCertificateFilename, + keyFilename, + certificateFilename, + storePath + }); + + return certificateStore; +} diff --git a/vscode-extensions/tls-sync-vscode-shared/src/config.ts b/vscode-extensions/tls-sync-vscode-shared/src/config.ts new file mode 100644 index 00000000000..e444008c052 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/src/config.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as vscode from 'vscode'; +import * as path from 'node:path'; +import type { ITerminal } from '@rushstack/terminal'; +import type { ICertificateManagerOptions } from '@rushstack/debug-certificate-manager'; +import { + CONFIG_AUTOSYNC, + CONFIG_SECTION, + CONFIG_CA_CERTIFICATE_FILENAME, + CONFIG_CERTIFICATE_FILENAME, + CONFIG_KEY_FILENAME, + CONFIG_STORE_PATH +} from './constants'; + +type StorePaths = Record<'windows' | 'linux' | 'osx', string>; +export interface IExtensionConfig extends ICertificateManagerOptions { + autoSync: boolean; +} + +export function getConfig(terminal: ITerminal, configType: 'ui' | 'workspace'): IExtensionConfig { + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(CONFIG_SECTION); + const caCertificateFilename: string | undefined = config.get(CONFIG_CA_CERTIFICATE_FILENAME) || undefined; + const certificateFilename: string | undefined = config.get(CONFIG_CERTIFICATE_FILENAME) || undefined; + const keyFilename: string | undefined = config.get(CONFIG_KEY_FILENAME) || undefined; + const autoSync: boolean = config.get(CONFIG_AUTOSYNC) ?? false; + let storePath: string | undefined = undefined; + const storePaths: StorePaths = { + windows: config.get(`${configType}.${CONFIG_STORE_PATH}.windows`) || '', + linux: config.get(`${configType}.${CONFIG_STORE_PATH}.linux`) || '', + osx: config.get(`${configType}.${CONFIG_STORE_PATH}.osx`) || '' + }; + const platformMap: Record = { + win32: 'windows', + linux: 'linux', + darwin: 'osx' + }; + + const platformKey: keyof StorePaths = platformMap[process.platform]; + if (platformKey) { + storePath = storePaths[platformKey]; + if (storePath) { + const homeDir: string | undefined = process.env.HOME || process.env.USERPROFILE; + if (storePath[0] === '~' && homeDir) { + storePath = path.join(homeDir, storePath.slice(1)); + } + } + } else { + terminal.writeLine(`Unsupported platform: ${process.platform}`); + } + + const extensionConfig: IExtensionConfig = { + storePath, + caCertificateFilename, + certificateFilename, + keyFilename, + autoSync + }; + terminal.writeLine(`Extension config: ${JSON.stringify(extensionConfig)}`); + return extensionConfig; +} diff --git a/vscode-extensions/tls-sync-vscode-shared/src/constants.ts b/vscode-extensions/tls-sync-vscode-shared/src/constants.ts new file mode 100644 index 00000000000..55b961db633 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/src/constants.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const WORKSPACE_EXTENSION_DISPLAY_NAME: string = 'TLS Sync (Workspace Extension)'; +export const UI_EXTENSION_DISPLAY_NAME: string = 'TLS Sync (UI Extension)'; + +export const WORKSPACE_EXTENSION_ID: string = 'RushStack.tls-sync-vscode-workspace-extension'; +export const UI_EXTENSION_ID: string = 'RushStack.tls-sync-vscode-ui-extension'; + +export const WORKSPACE_COMMAND_PREFIX: string = 'tlssync.workspace'; +export const UI_COMMAND_PREFIX: string = 'tlssync.ui'; + +export const WORKSPACE_COMMAND_SYNC: string = `${WORKSPACE_COMMAND_PREFIX}.sync`; +export const WORKSPACE_COMMAND_SHOW_LOG: string = `${WORKSPACE_COMMAND_PREFIX}.showLog`; +export const WORKSPACE_COMMAND_PING: string = `${WORKSPACE_COMMAND_PREFIX}.ping`; + +export const UI_COMMAND_SYNC: string = `${UI_COMMAND_PREFIX}.sync`; +export const UI_COMMAND_ENSURE_CERTIFICATE: string = `${UI_COMMAND_PREFIX}.ensureCertificate`; +export const UI_COMMAND_UNTRUST_CERTIFICATE: string = `${UI_COMMAND_PREFIX}.untrustCertificate`; +export const UI_COMMAND_SHOW_LOG: string = `${UI_COMMAND_PREFIX}.showLog`; +export const UI_COMMAND_SHOW_WALKTHROUGH: string = `${UI_COMMAND_PREFIX}.showWalkthrough`; +export const UI_COMMAND_SHOW_SETTINGS: string = `${UI_COMMAND_PREFIX}.showSettings`; + +export const CONFIG_SECTION: string = 'tlssync'; +export const CONFIG_AUTOSYNC: string = 'autoSync'; +export const CONFIG_CA_CERTIFICATE_FILENAME: string = 'caCertificateFilename'; +export const CONFIG_CERTIFICATE_FILENAME: string = 'certificateFilename'; +export const CONFIG_KEY_FILENAME: string = 'keyFilename'; +export const CONFIG_STORE_PATH: string = 'storePath'; + +export const VSCODE_COMMAND_WORKSPACE_OPEN_SETTINGS: string = 'workbench.action.openSettings'; +export const VSCODE_COMMAND_WORKSPACE_OPEN_WALKTHROUGH: string = 'workbench.action.openWalkthrough'; + +export const UI_WALKTHROUGH_ID: string = 'sync-certificates'; diff --git a/vscode-extensions/tls-sync-vscode-shared/tsconfig.json b/vscode-extensions/tls-sync-vscode-shared/tsconfig.json new file mode 100644 index 00000000000..a114c3448ed --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-shared/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/.npmignore b/vscode-extensions/tls-sync-vscode-ui-extension/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/.vscodeignore b/vscode-extensions/tls-sync-vscode-ui-extension/.vscodeignore new file mode 100644 index 00000000000..57c6857fd22 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/.vscodeignore @@ -0,0 +1,8 @@ +** +!LICENSE +!README.md +!extension.js +!package.json +!assets/extension-icon.png +!assets/walkthrough-sync.md +!assets/walkthrough-settings.md diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/LICENSE b/vscode-extensions/tls-sync-vscode-ui-extension/LICENSE new file mode 100644 index 00000000000..4575ab4ab2c --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/LICENSE @@ -0,0 +1,24 @@ +tls-sync-vscode-ui-extension + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/README.md b/vscode-extensions/tls-sync-vscode-ui-extension/README.md new file mode 100644 index 00000000000..7fcea8962e3 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/README.md @@ -0,0 +1,7 @@ +# TLS Sync VS Code Extension (Local / UI Extension) + +This extension is designed to work with the [TLS Sync VS Code Workspace extension](../tls-sync-vscode-workspace-extension), providing a seamless experience for managing TLS certificates in a remote development environment. + +The UI extension manages the certificates on the local machine and provides an API for the Workspace extension to synchronize certificates with the remote workspace. + +See [TLS Sync VS Code Workspace extension](../tls-sync-vscode-workspace-extension) for more details on the TLS Sync extensions. diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/assets/extension-icon.png b/vscode-extensions/tls-sync-vscode-ui-extension/assets/extension-icon.png new file mode 100644 index 00000000000..ee2bd331df9 Binary files /dev/null and b/vscode-extensions/tls-sync-vscode-ui-extension/assets/extension-icon.png differ diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-settings.md b/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-settings.md new file mode 100644 index 00000000000..ebb255bcac5 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-settings.md @@ -0,0 +1 @@ +Change where TLS Sync stores and sync certificates. diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-sync.md b/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-sync.md new file mode 100644 index 00000000000..01bd1268880 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/assets/walkthrough-sync.md @@ -0,0 +1 @@ +Sync TLS certificates from your local machine to the VSCode remote workspace. diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/config/heft.json b/vscode-extensions/tls-sync-vscode-ui-extension/config/heft.json new file mode 100644 index 00000000000..e1dd458ed26 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/config/heft.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/heft.json" +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/config/rig.json b/vscode-extensions/tls-sync-vscode-ui-extension/config/rig.json new file mode 100644 index 00000000000..ec33a848348 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/config/rush-project.json b/vscode-extensions/tls-sync-vscode-ui-extension/config/rush-project.json new file mode 100644 index 00000000000..b2453d544bc --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/config/rush-project.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/rush-project.json" +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/eslint.config.js b/vscode-extensions/tls-sync-vscode-ui-extension/eslint.config.js new file mode 100644 index 00000000000..eac79367926 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/eslint.config.js @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/package.json b/vscode-extensions/tls-sync-vscode-ui-extension/package.json new file mode 100644 index 00000000000..d9fabbb2fab --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/package.json @@ -0,0 +1,178 @@ +{ + "name": "tls-sync-vscode-ui-extension", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/tls-sync-vscode-ui-extension" + }, + "license": "MIT", + "publisher": "RushStack", + "preview": true, + "displayName": "TLS Sync (UI Extension)", + "description": "", + "homepage": "https://github.com/microsoft/rushstack/tree/main/vscode-extensions/tls-sync-vscode-ui-extension", + "icon": "assets/extension-icon.png", + "extensionKind": [ + "ui" + ], + "categories": [ + "Other" + ], + "keywords": [], + "galleryBanner": { + "color": "#f0f0f0", + "theme": "light" + }, + "engines": { + "vscode": "^1.98.0" + }, + "main": "./extension.js", + "scripts": { + "build": "heft build --clean", + "build:watch": "heft build-watch", + "start": "heft start", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "" + }, + "contributes": { + "commands": [ + { + "command": "tlssync.ui.showLog", + "title": "Show Log", + "category": "TLS Sync" + }, + { + "command": "tlssync.ui.untrustCertificate", + "title": "Untrust Certificate", + "category": "TLS Sync" + }, + { + "command": "tlssync.ui.ensureCertificate", + "title": "Ensure Certificate", + "category": "TLS Sync" + }, + { + "command": "tlssync.ui.sync", + "title": "Sync TLS Certificates", + "category": "TLS Sync" + }, + { + "command": "tlssync.ui.showWalkthrough", + "title": "Show Walkthrough", + "category": "TLS Sync" + }, + { + "command": "tlssync.ui.showSettings", + "title": "Show Settings", + "category": "TLS Sync" + } + ], + "walkthroughs": [ + { + "id": "sync-certificates", + "title": "TLS Sync", + "description": "Sync your debug TLS certificates with the remote machine.", + "featuredFor": [ + ".tlssync" + ], + "steps": [ + { + "id": "runsynccommand", + "title": "Sync Certificates", + "description": "[Sync](command:tlssync.ui.sync)", + "completionEvents": [ + "onContext:tlssync.ui.sync.complete" + ], + "media": { + "markdown": "./media/walkthrough-sync.md" + } + }, + { + "id": "changetlssyncsettings", + "title": "Change Sync Settings", + "description": "[Open Settings](command:tlssync.ui.showSettings)", + "completionEvents": [], + "media": { + "markdown": "./media/walkthrough-settings.md" + } + } + ] + } + ], + "configuration": { + "title": "TLS Sync", + "properties": { + "tlssync.ui.storePath.osx": { + "type": "string", + "title": "UI Extension - TLS Sync Store Path (macOS)", + "description": "[UI Extension] Directory where TLS certificates are read and written." + }, + "tlssync.ui.storePath.windows": { + "type": "string", + "title": "UI Extension - TLS Sync Store Path (Windows)", + "description": "[UI Extension] Directory where TLS certificates are read and written." + }, + "tlssync.ui.storePath.linux": { + "type": "string", + "title": "UI Extension - TLS Sync Store Path (Linux)", + "description": "[UI Extension] Directory where TLS certificates are read and written." + }, + "tlssync.workspace.storePath.osx": { + "type": "string", + "title": "Workspace Extension - TLS Sync Store Path (macOS)", + "description": "[Workspace Extension] Directory where TLS certificates are read and written." + }, + "tlssync.workspace.storePath.windows": { + "type": "string", + "title": "Workspace Extension - TLS Sync Store Path (Windows)", + "description": "[Workspace Extension] Directory where TLS certificates are read and written." + }, + "tlssync.workspace.storePath.linux": { + "type": "string", + "title": "Workspace Extension - TLS Sync Store Path (Linux)", + "description": "[Workspace Extension] Directory where TLS certificates are read and written." + }, + "tlssync.caCertificateFilename": { + "type": "string", + "title": "CA Certificate Filename", + "description": "Filename for the CA certificate." + }, + "tlssync.certificateFilename": { + "type": "string", + "title": "Server Certificate Filename", + "description": "Filename for the server certificate." + }, + "tlssync.keyFilename": { + "type": "string", + "title": "Server Key Filename", + "description": "Filename for the server key." + }, + "tlssync.autoSync": { + "type": "boolean", + "title": "Automatically Sync Certificates", + "default": true, + "description": "Check certificates when extension is activated. Extension is automatically activated when a `.tlssync` file is present in the workspace." + } + } + } + }, + "activationEvents": [ + "workspaceContains:**/.tlssync" + ], + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/tls-sync-vscode-shared": "workspace:*", + "@rushstack/vscode-shared": "workspace:*", + "tslib": "~2.3.1" + }, + "devDependencies": { + "@rushstack/heft-vscode-extension-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/vscode": "^1.63.0", + "@types/webpack-env": "1.18.8" + } +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/src/extension.ts b/vscode-extensions/tls-sync-vscode-ui-extension/src/extension.ts new file mode 100644 index 00000000000..974034d6fbf --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/src/extension.ts @@ -0,0 +1,259 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as vscode from 'vscode'; + +import { Async } from '@rushstack/node-core-library/lib/Async'; +import { Terminal } from '@rushstack/terminal'; +import { + CertificateManager, + ICertificateValidationResult, + type ICertificate +} from '@rushstack/debug-certificate-manager'; + +import { VScodeOutputChannelTerminalProvider } from '@rushstack/vscode-shared/lib/VScodeOutputChannelTerminalProvider'; +import { getCertificateManager } from '@rushstack/tls-sync-vscode-shared/lib/certificates'; +import { getConfig } from '@rushstack/tls-sync-vscode-shared/lib/config'; +import { + UI_COMMAND_ENSURE_CERTIFICATE, + UI_COMMAND_SHOW_LOG, + UI_COMMAND_SHOW_SETTINGS, + UI_COMMAND_SHOW_WALKTHROUGH, + UI_COMMAND_SYNC, + UI_COMMAND_UNTRUST_CERTIFICATE, + UI_EXTENSION_DISPLAY_NAME, + UI_EXTENSION_ID, + UI_WALKTHROUGH_ID, + VSCODE_COMMAND_WORKSPACE_OPEN_SETTINGS, + VSCODE_COMMAND_WORKSPACE_OPEN_WALKTHROUGH, + WORKSPACE_COMMAND_PING, + WORKSPACE_COMMAND_SYNC, + WORKSPACE_EXTENSION_DISPLAY_NAME +} from '@rushstack/tls-sync-vscode-shared/lib/constants'; + +import { version } from '../package.json'; + +/* + * This extension provides commands to manage debug TLS certificates on the local machine. This capability is + * primarily intended to be called by the workspace extension counterpart. + */ + +export function activate(context: vscode.ExtensionContext): void { + const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel(UI_EXTENSION_DISPLAY_NAME); + const terminalProvider: VScodeOutputChannelTerminalProvider = new VScodeOutputChannelTerminalProvider( + outputChannel, + { + verboseEnabled: true, + debugEnabled: true + } + ); + const terminal: Terminal = new Terminal(terminalProvider); + terminal.writeLine(`${UI_EXTENSION_DISPLAY_NAME} Extension output channel initialized.`); + + function handleShowLog(): void { + outputChannel.show(); + } + + async function handleUntrustCertificate(): Promise { + try { + terminal.writeLine('Attempting to clean up certificates...'); + const certificateManager: CertificateManager = getCertificateManager(terminal, 'ui'); + await certificateManager.untrustCertificateAsync(terminal); + + const message: string = 'Certificates untrusted successfully.'; + terminal.writeLine(message); + void vscode.window.showInformationMessage(message); + } catch (err) { + const message: string = `Error cleaning up certificates: ${ + err instanceof Error ? err.message : 'Unknown error' + }`; + terminal.writeLine(message); + void vscode.window.showErrorMessage(message); + } + } + + async function handleEnsureCertificate(): Promise { + await _handleEnsureCertificateInternal(); + } + + async function _handleEnsureCertificateInternal(): Promise { + try { + terminal.writeLine('Attempting to retrieve certificates...'); + const certificateManager: CertificateManager = getCertificateManager(terminal, 'ui'); + let skipCertificateTrust: boolean = true; + let canGenerateNewCertificate: boolean = false; + + const certificateValidationResult: ICertificateValidationResult = + await certificateManager.validateCertificateAsync(terminal); + + // Prompt the user and create new certificates + if (certificateValidationResult.isValid) { + return certificateValidationResult.certificate; + } + + for (const error of certificateValidationResult.validationMessages) { + terminal.writeLine(`Certificate validation message: ${error}`); + } + terminal.writeLine('No valid certificates found. Prompting user to create new certificates.'); + const response: 'Create and Trust' | 'Create and Skip Trust' | undefined = + await vscode.window.showInformationMessage( + 'No valid certificates found. Would you like to create new certificates?', + 'Create and Trust', + 'Create and Skip Trust' + ); + + terminal.writeLine(`User response: ${response || 'No response received'}`); + + if (!response) { + const message: string = 'User cancelled certificate creation.'; + terminal.writeLine(message); + return undefined; + } + + if (response === 'Create and Skip Trust') { + skipCertificateTrust = true; + canGenerateNewCertificate = true; + } else if (response === 'Create and Trust') { + skipCertificateTrust = false; + canGenerateNewCertificate = true; + } + + const timeoutSeconds: number = skipCertificateTrust ? 10 : 30; + const certificate: ICertificate = await Async.runWithTimeoutAsync({ + action: () => + certificateManager.ensureCertificateAsync(canGenerateNewCertificate, terminal, { + skipCertificateTrust + }), + timeoutMs: timeoutSeconds * 1000, + timeoutMessage: `Certificate generation timed out after ${timeoutSeconds} seconds` + }); + + terminal.writeLine( + `Creating new certificates. Can generate new certificate: ${canGenerateNewCertificate}, Skip certificate trust: ${skipCertificateTrust}` + ); + + if (!certificate.pemCaCertificate || !certificate.pemCertificate || !certificate.pemKey) { + void vscode.window.showErrorMessage('Failed to create new certificates.'); + terminal.writeLine('Failed to create new certificates.'); + return undefined; + } + + terminal.writeLine('Certificates retrieved successfully.'); + return certificate; + } catch (err) { + const message: string = `Error retrieving certificates: ${ + err instanceof Error ? err.message : 'Unknown error' + }`; + terminal.writeLine(message); + void vscode.window.showErrorMessage(message); + } + } + + async function handleShowWalkthrough(): Promise { + await vscode.commands.executeCommand( + VSCODE_COMMAND_WORKSPACE_OPEN_WALKTHROUGH, + `${UI_EXTENSION_ID}#${UI_WALKTHROUGH_ID}`, + false + ); + } + + async function handleShowSettings(): Promise { + await vscode.commands.executeCommand(VSCODE_COMMAND_WORKSPACE_OPEN_SETTINGS, `@ext:${UI_EXTENSION_ID}`); + } + + async function waitForWorkspaceExtension(): Promise { + terminal.writeLine( + `Waiting for Workspace extension (${WORKSPACE_EXTENSION_DISPLAY_NAME}) to become active...` + ); + + const maxRetries: number = 30; + try { + await Async.runWithRetriesAsync({ + action: async (attempt: number) => { + terminal.writeLine(`Pinging Workspace extension... Attempt ${attempt + 1}/${maxRetries}`); + const { version: workspaceVersion } = await vscode.commands.executeCommand<{ version: string }>( + WORKSPACE_COMMAND_PING + ); + if (!workspaceVersion) { + terminal.writeLine('Workspace extension is not yet active. Retrying...'); + return; + } + terminal.writeLine(`Workspace extension is active. Version: ${workspaceVersion}`); + if (version !== workspaceVersion) { + terminal.writeLine( + `Warning: Workspace extension version mismatch. Expected ${version}, got ${workspaceVersion}.` + ); + void vscode.window.showWarningMessage( + `Workspace extension version mismatch. Expected ${version}, got ${workspaceVersion}. Please check that both ${WORKSPACE_EXTENSION_DISPLAY_NAME} and ${UI_EXTENSION_DISPLAY_NAME} are up to date.` + ); + throw new Error('Version mismatch'); + } + }, + maxRetries, + retryDelayMs: 1000 + }); + } catch (error) { + terminal.writeLine('UI extension did not respond within the expected time frame.'); + throw new Error('UI extension did not respond within the expected time frame.'); + } + } + + async function handleSync(): Promise { + if (!vscode.env.remoteName) { + const message: string = + 'This command is only available in remote workspaces. Please open this workspace in a remote environment.'; + terminal.writeLine(message); + void vscode.window.showErrorMessage(message); + } + + try { + await waitForWorkspaceExtension(); + terminal.writeLine('Workspace extension is active. Proceeding with certificate synchronization...'); + + const certificate: ICertificate | undefined = await _handleEnsureCertificateInternal(); + if (!certificate) { + terminal.writeLine('No valid certificates found. Synchronization aborted.'); + return; + } + + terminal.writeLine('Sending certificates to workspace extension for synchronization...'); + const isSynchronized: boolean = await vscode.commands.executeCommand( + WORKSPACE_COMMAND_SYNC, + certificate + ); + + if (isSynchronized) { + await vscode.commands.executeCommand('setContext', 'tlssync.ui.sync.complete', true); + terminal.writeLine('Certificates synchronized successfully.'); + void vscode.window.showInformationMessage('Certificates synchronized successfully.'); + } else { + terminal.writeLine('Failed to synchronize certificates.'); + void vscode.window.showErrorMessage('Failed to synchronize certificates.'); + } + } catch (err) { + const message: string = `Error synchronizing certificates: ${ + err instanceof Error ? err.message : 'Unknown error' + }`; + terminal.writeLine(message); + void vscode.window.showErrorMessage(message); + } + } + + const { autoSync } = getConfig(terminal, 'ui'); + if (autoSync && !vscode.env.remoteName) { + terminal.writeLine(`Auto-sync is enabled. Synchronizing certificates on activation...`); + void vscode.commands.executeCommand(UI_COMMAND_SYNC); + } + + context.subscriptions.push( + outputChannel, + vscode.commands.registerCommand(UI_COMMAND_SHOW_LOG, handleShowLog), + vscode.commands.registerCommand(UI_COMMAND_SHOW_SETTINGS, handleShowSettings), + vscode.commands.registerCommand(UI_COMMAND_SHOW_WALKTHROUGH, handleShowWalkthrough), + vscode.commands.registerCommand(UI_COMMAND_UNTRUST_CERTIFICATE, handleUntrustCertificate), + vscode.commands.registerCommand(UI_COMMAND_ENSURE_CERTIFICATE, handleEnsureCertificate), + vscode.commands.registerCommand(UI_COMMAND_SYNC, handleSync) + ); +} + +export function deactivate(): void {} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/tsconfig.json b/vscode-extensions/tls-sync-vscode-ui-extension/tsconfig.json new file mode 100644 index 00000000000..09607819d38 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/tsconfig.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "./node_modules/@rushstack/heft-vscode-extension-rig/profiles/default/tsconfig-base.json" +} diff --git a/vscode-extensions/tls-sync-vscode-ui-extension/webpack.config.js b/vscode-extensions/tls-sync-vscode-ui-extension/webpack.config.js new file mode 100644 index 00000000000..bc6dfe67040 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-ui-extension/webpack.config.js @@ -0,0 +1,23 @@ +// @ts-check +/* eslint-env es6 */ + +'use strict'; + +const { + createExtensionConfig +} = require('@rushstack/heft-vscode-extension-rig/profiles/default/webpack.config.base'); +const path = require('node:path'); + +function createConfig({ production, webpack }) { + const config = createExtensionConfig({ + production, + webpack, + entry: { + extension: './lib/extension.js' + }, + outputPath: path.resolve(__dirname, 'dist', 'vsix', 'unpacked') + }); + return config; +} + +module.exports = createConfig; diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/.npmignore b/vscode-extensions/tls-sync-vscode-workspace-extension/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/.vscodeignore b/vscode-extensions/tls-sync-vscode-workspace-extension/.vscodeignore new file mode 100644 index 00000000000..c905bb4b413 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/.vscodeignore @@ -0,0 +1,6 @@ +** +!LICENSE +!README.md +!extension.js +!package.json +!assets/extension-icon.png diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/LICENSE b/vscode-extensions/tls-sync-vscode-workspace-extension/LICENSE new file mode 100644 index 00000000000..cee4fe2d135 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/LICENSE @@ -0,0 +1,24 @@ +tls-sync-vscode-workspace-extension + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/README.md b/vscode-extensions/tls-sync-vscode-workspace-extension/README.md new file mode 100644 index 00000000000..eb99cbde6e9 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/README.md @@ -0,0 +1,5 @@ +# TLS Sync VS Code Extension (Remote / Workspace Extension) + +This extension is designed to work with the [TLS Sync VS Code UI extension](../tls-sync-vscode-ui-extension), providing a seamless experience for managing TLS certificates in a remote workspace environment. + +The Workspace extension gets the client's debug certificate from the UI extension and writes it to the remote workspace. diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/assets/extension-icon.png b/vscode-extensions/tls-sync-vscode-workspace-extension/assets/extension-icon.png new file mode 100644 index 00000000000..ee2bd331df9 Binary files /dev/null and b/vscode-extensions/tls-sync-vscode-workspace-extension/assets/extension-icon.png differ diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/config/heft.json b/vscode-extensions/tls-sync-vscode-workspace-extension/config/heft.json new file mode 100644 index 00000000000..e1dd458ed26 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/config/heft.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/heft.json" +} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/config/rig.json b/vscode-extensions/tls-sync-vscode-workspace-extension/config/rig.json new file mode 100644 index 00000000000..ec33a848348 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/config/rush-project.json b/vscode-extensions/tls-sync-vscode-workspace-extension/config/rush-project.json new file mode 100644 index 00000000000..b2453d544bc --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/config/rush-project.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/rush-project.json" +} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/eslint.config.js b/vscode-extensions/tls-sync-vscode-workspace-extension/eslint.config.js new file mode 100644 index 00000000000..eac79367926 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/eslint.config.js @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/package.json b/vscode-extensions/tls-sync-vscode-workspace-extension/package.json new file mode 100644 index 00000000000..5abb8235b56 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/package.json @@ -0,0 +1,67 @@ +{ + "name": "tls-sync-vscode-workspace-extension", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/tls-sync-vscode-workspace-extension" + }, + "license": "MIT", + "publisher": "RushStack", + "preview": true, + "displayName": "TLS Sync (Workspace Extension)", + "description": "", + "homepage": "https://github.com/microsoft/rushstack/tree/main/vscode-extensions/tls-sync-vscode-workspace-extension", + "icon": "assets/extension-icon.png", + "extensionKind": [ + "workspace" + ], + "categories": [ + "Other" + ], + "keywords": [], + "galleryBanner": { + "color": "#f0f0f0", + "theme": "light" + }, + "engines": { + "vscode": "^1.98.0" + }, + "main": "./extension.js", + "scripts": { + "build": "heft build --clean", + "build:watch": "heft build-watch", + "start": "heft start", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "" + }, + "contributes": { + "commands": [ + { + "command": "tlssync.workspace.showLog", + "title": "Show Log (Workspace)", + "category": "TLS Sync" + } + ] + }, + "activationEvents": [ + "onCommand:tlssync.workspace.ping", + "onCommand:tlssync.workspace.sync", + "workspaceContains:**/.tlssync" + ], + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/tls-sync-vscode-shared": "workspace:*", + "@rushstack/vscode-shared": "workspace:*", + "tslib": "~2.3.1" + }, + "devDependencies": { + "@rushstack/heft-vscode-extension-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/vscode": "^1.63.0", + "@types/webpack-env": "1.18.8" + } +} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/src/extension.ts b/vscode-extensions/tls-sync-vscode-workspace-extension/src/extension.ts new file mode 100644 index 00000000000..30e18838981 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/src/extension.ts @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as vscode from 'vscode'; + +import { CertificateStore, type ICertificate } from '@rushstack/debug-certificate-manager'; +import { Terminal } from '@rushstack/terminal'; + +import { VScodeOutputChannelTerminalProvider } from '@rushstack/vscode-shared/lib/VScodeOutputChannelTerminalProvider'; +import { getCertificateStore } from '@rushstack/tls-sync-vscode-shared/lib/certificates'; +import { + WORKSPACE_COMMAND_PING, + WORKSPACE_COMMAND_SHOW_LOG, + WORKSPACE_COMMAND_SYNC, + WORKSPACE_EXTENSION_DISPLAY_NAME +} from '@rushstack/tls-sync-vscode-shared/lib/constants'; + +import { version } from '../package.json'; + +/* + * This extension provides commands to sync debug TLS certificates with the UI extension. This allows for VS Code + * remotes to use the same certificates as the local machine. + */ + +export function activate(context: vscode.ExtensionContext): void { + const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel( + WORKSPACE_EXTENSION_DISPLAY_NAME + ); + const terminalProvider: VScodeOutputChannelTerminalProvider = new VScodeOutputChannelTerminalProvider( + outputChannel, + { + verboseEnabled: true, + debugEnabled: true + } + ); + const terminal: Terminal = new Terminal(terminalProvider); + terminal.writeLine(`${WORKSPACE_EXTENSION_DISPLAY_NAME} output channel initialized.`); + + async function handleShowLog(): Promise { + outputChannel.show(); + } + + async function handleSyncCertificates(certificatesFromUI: ICertificate): Promise { + const certificateStore: CertificateStore = getCertificateStore(terminal, 'workspace'); + + void vscode.window.showInformationMessage(`Synchronizing TLS certificates.`); + terminal.writeLine('Starting certificate synchronization...'); + try { + if (!certificatesFromUI) { + void vscode.window.showErrorMessage( + 'No certificates found in the UI extension. Please ensure the UI extension is installed and configured.' + ); + terminal.writeLine('No certificates found in the UI extension. Synchronization aborted.'); + return false; + } + + let isSynchronized: boolean = false; + isSynchronized = + certificateStore.caCertificateData === certificatesFromUI.pemCaCertificate && + certificateStore.certificateData === certificatesFromUI.pemCertificate && + certificateStore.keyData === certificatesFromUI.pemKey; + if (isSynchronized) { + void vscode.window.showInformationMessage( + 'Local certificates are already synchronized with UI certificates.' + ); + return true; + } + + certificateStore.caCertificateData = certificatesFromUI.pemCaCertificate; + terminal.writeLine(`Writing CA certificate to ${certificateStore.caCertificatePath}...`); + + certificateStore.certificateData = certificatesFromUI.pemCertificate; + terminal.writeLine(`Writing TLS server certificates to ${certificateStore.certificateData}...`); + + certificateStore.keyData = certificatesFromUI.pemKey; + terminal.writeLine(`Writing TLS private key to ${certificateStore.keyPath}...`); + + terminal.writeLine(`Certificates synchronized successfully.`); + return true; + } catch (err) { + const message: string = `Error synchronizing certificates: ${ + err instanceof Error ? err.message : 'Unknown error' + }`; + terminal.writeLine(message); + void vscode.window.showErrorMessage(message); + return false; + } + } + + function handlePing(): { version: string } { + return { + version + }; + } + + context.subscriptions.push( + outputChannel, + vscode.commands.registerCommand(WORKSPACE_COMMAND_PING, handlePing), + vscode.commands.registerCommand(WORKSPACE_COMMAND_SHOW_LOG, handleShowLog), + vscode.commands.registerCommand(WORKSPACE_COMMAND_SYNC, handleSyncCertificates) + ); +} + +export function deactivate(): void {} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/tsconfig.json b/vscode-extensions/tls-sync-vscode-workspace-extension/tsconfig.json new file mode 100644 index 00000000000..1226387ecf8 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-vscode-extension-rig/profiles/default/tsconfig-base.json" +} diff --git a/vscode-extensions/tls-sync-vscode-workspace-extension/webpack.config.js b/vscode-extensions/tls-sync-vscode-workspace-extension/webpack.config.js new file mode 100644 index 00000000000..bc6dfe67040 --- /dev/null +++ b/vscode-extensions/tls-sync-vscode-workspace-extension/webpack.config.js @@ -0,0 +1,23 @@ +// @ts-check +/* eslint-env es6 */ + +'use strict'; + +const { + createExtensionConfig +} = require('@rushstack/heft-vscode-extension-rig/profiles/default/webpack.config.base'); +const path = require('node:path'); + +function createConfig({ production, webpack }) { + const config = createExtensionConfig({ + production, + webpack, + entry: { + extension: './lib/extension.js' + }, + outputPath: path.resolve(__dirname, 'dist', 'vsix', 'unpacked') + }); + return config; +} + +module.exports = createConfig; diff --git a/vscode-extensions/vscode-shared/.npmignore b/vscode-extensions/vscode-shared/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/vscode-shared/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/vscode-shared/LICENSE b/vscode-extensions/vscode-shared/LICENSE new file mode 100644 index 00000000000..a29fce499b9 --- /dev/null +++ b/vscode-extensions/vscode-shared/LICENSE @@ -0,0 +1,24 @@ +@rushstack/vscode-shared + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vscode-extensions/vscode-shared/README.md b/vscode-extensions/vscode-shared/README.md new file mode 100644 index 00000000000..1adc0a9c7aa --- /dev/null +++ b/vscode-extensions/vscode-shared/README.md @@ -0,0 +1,3 @@ +# @rushstack/vscode-shared + +This library provides a set of utilities for VS Code extensions. diff --git a/vscode-extensions/vscode-shared/config/rig.json b/vscode-extensions/vscode-shared/config/rig.json new file mode 100644 index 00000000000..58032e098f0 --- /dev/null +++ b/vscode-extensions/vscode-shared/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-node-rig" +} diff --git a/vscode-extensions/vscode-shared/eslint.config.js b/vscode-extensions/vscode-shared/eslint.config.js new file mode 100644 index 00000000000..006cb82d1c0 --- /dev/null +++ b/vscode-extensions/vscode-shared/eslint.config.js @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/vscode-shared/package.json b/vscode-extensions/vscode-shared/package.json new file mode 100644 index 00000000000..b7bac7806c7 --- /dev/null +++ b/vscode-extensions/vscode-shared/package.json @@ -0,0 +1,28 @@ +{ + "name": "@rushstack/vscode-shared", + "version": "0.0.0", + "description": "", + "main": "lib/index.js", + "typings": "dist/index.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/vscode-shared" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft-node-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/vscode": "^1.63.0" + } +} diff --git a/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.ts b/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.ts new file mode 100644 index 00000000000..6fc6cc2e605 --- /dev/null +++ b/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.ts @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Text } from '@rushstack/node-core-library'; +import type { ITerminalProvider, TerminalProviderSeverity } from '@rushstack/terminal'; +import type * as vscode from 'vscode'; + +/** + * Options to be provided to a {@link VScodeOutputChannelTerminalProvider} + * + * @beta + */ +export interface IVScodeOutputChannelTerminalProviderOptions { + /** + * If true, print verbose logging messages. + */ + verboseEnabled: boolean; + + /** + * If true, print debug logging messages. Note that "verbose" and "debug" are considered + * separate message filters; if you want debug to imply verbose, it is up to your + * application code to enforce that. + */ + debugEnabled: boolean; +} + +/** + * Terminal provider that prints to STDOUT (for log- and verbose-level messages) and + * STDERR (for warning- and error-level messages). + * + * @beta + */ +export class VScodeOutputChannelTerminalProvider implements ITerminalProvider { + private readonly _outputChannel: vscode.OutputChannel; + public static readonly supportsColor: boolean = false; + + /** + * If true, verbose-level messages should be written to the console. + */ + public verboseEnabled: boolean; + + /** + * If true, debug-level messages should be written to the console. + */ + public debugEnabled: boolean; + + /** + * {@inheritDoc ITerminalProvider.supportsColor} + */ + public readonly supportsColor: boolean = VScodeOutputChannelTerminalProvider.supportsColor; + + public constructor( + outputChannel: vscode.OutputChannel, + options: Partial = {} + ) { + this.verboseEnabled = !!options.verboseEnabled; + this.debugEnabled = !!options.debugEnabled; + this._outputChannel = outputChannel; + } + + /** + * {@inheritDoc ITerminalProvider.write} + */ + public write(data: string, severity: TerminalProviderSeverity): void { + const outputChannel: vscode.OutputChannel = this._outputChannel; + for (const line of Text.readLinesFromIterable(data)) { + outputChannel.appendLine(line); + } + } + + /** + * {@inheritDoc ITerminalProvider.eolCharacter} + */ + public get eolCharacter(): string { + return '\n'; + } +} diff --git a/vscode-extensions/vscode-shared/tsconfig.json b/vscode-extensions/vscode-shared/tsconfig.json new file mode 100644 index 00000000000..a114c3448ed --- /dev/null +++ b/vscode-extensions/vscode-shared/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json" +}