From ee2914995828d266295e0fb2e60767f91575dac4 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 25 Sep 2025 16:16:17 +0200 Subject: [PATCH 1/7] fix: snyk will now scan vscode project Earlier snyk was never scanning the vscode project because of the combination of project auto-detection and the presence of .vscode-test folder which contains several directories with package.json files. This commit disables the auto-detection so that snyk run tests on the current project. Additionally the current project was having a problem with a package declaring optional dependencies. These optional dependencies were platform specific so for any platform, all the optional dependencies will never be installed, only the ones that are platform compatible. Snyk requires what is declared in package-lock.json to be also present in node_modules folder which is why it would've failed. In the same commit, we added a pre and post test hook to remove the identified problematic optional dependencies from package-lock file before running the test and then restore it when the test is finished. --- scripts/snyk-test.js | 109 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 20 deletions(-) diff --git a/scripts/snyk-test.js b/scripts/snyk-test.js index 688ce15d6..038548560 100644 --- a/scripts/snyk-test.js +++ b/scripts/snyk-test.js @@ -6,6 +6,67 @@ const { glob } = require('glob'); const { promisify } = require('util'); const execFile = promisify(childProcess.execFile); +const PACKAGE_LOCK_PATH = path.join(__dirname, '..', 'package-lock.json'); + +/** + * "node_modules/@vscode/vsce-sign" package which is a dev dependency used for + * publishing extension declares platform specific optionalDependencies, namely + * the following: + * - "@vscode/vsce-sign-alpine-arm64" + * - "@vscode/vsce-sign-alpine-x64" + * - "@vscode/vsce-sign-darwin-arm64" + * - "@vscode/vsce-sign-darwin-x64" + * - "@vscode/vsce-sign-linux-arm" + * - "@vscode/vsce-sign-linux-arm64" + * - "@vscode/vsce-sign-linux-x64" + * - "@vscode/vsce-sign-win32-arm64" + * - "@vscode/vsce-sign-win32-x64" + * + * Snyk requires what is declared in package-lock.json to be also present in + * installed node_modules but this will never happen because for any platform, + * other platform specific deps will always be missing which means Snyk will + * always fail in this case. + * + * Because we always install with `npm ci --omit=optional`, with this method we + * try to remove these identified problematic optionalDependencies before + * running the Snyk tests and once the tests are finished, we restore the + * original state back. + */ +async function removeProblematicOptionalDepsFromPackageLock() { + const TEMP_PACKAGE_LOCK_PATH = path.join( + __dirname, + '..', + 'original-package-lock.json', + ); + + const packageLockContent = JSON.parse( + await fs.readFile(PACKAGE_LOCK_PATH, 'utf-8'), + ); + + if ( + !packageLockContent.packages?.['node_modules/@vscode/vsce-sign']?.[ + 'optionalDependencies' + ] + ) { + console.info('No problematic optional dependencies to fix'); + return; + } + + packageLockContent.packages['node_modules/@vscode/vsce-sign'][ + 'optionalDependencies' + ] = {}; + + await fs.rename(PACKAGE_LOCK_PATH, TEMP_PACKAGE_LOCK_PATH); + await fs.writeFile( + PACKAGE_LOCK_PATH, + JSON.stringify(packageLockContent, null, 2), + ); + + return async function restoreOriginalPackageLock() { + return await fs.rename(TEMP_PACKAGE_LOCK_PATH, PACKAGE_LOCK_PATH); + }; +} + async function snykTest(cwd) { const tmpPath = path.join(os.tmpdir(), 'tempfile-' + Date.now()); @@ -17,9 +78,8 @@ async function snykTest(cwd) { await execFile( 'npx', [ - 'snyk', + 'snyk@latest', 'test', - '--all-projects', '--severity-threshold=low', '--dev', `--json-file-output=${tmpPath}`, @@ -45,26 +105,35 @@ async function snykTest(cwd) { } async function main() { - const rootPath = path.resolve(__dirname, '..'); - await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true }); - const results = await snykTest(rootPath); + let revertPackageLockChanges; + try { + const rootPath = path.resolve(__dirname, '..'); + await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true }); + revertPackageLockChanges = + await removeProblematicOptionalDepsFromPackageLock(); + const results = await snykTest(rootPath); - await fs.writeFile( - path.join(rootPath, `.sbom/snyk-test-result.json`), - JSON.stringify(results, null, 2), - ); + await fs.writeFile( + path.join(rootPath, `.sbom/snyk-test-result.json`), + JSON.stringify(results, null, 2), + ); - await execFile( - 'npx', - [ - 'snyk-to-html', - '-i', - path.join(rootPath, '.sbom/snyk-test-result.json'), - '-o', - path.join(rootPath, `.sbom/snyk-test-result.html`), - ], - { cwd: rootPath }, - ); + await execFile( + 'npx', + [ + 'snyk-to-html', + '-i', + path.join(rootPath, '.sbom/snyk-test-result.json'), + '-o', + path.join(rootPath, `.sbom/snyk-test-result.html`), + ], + { cwd: rootPath }, + ); + } finally { + if (revertPackageLockChanges) { + await revertPackageLockChanges(); + } + } } main(); From d33dce8d5e3a5e0ef9c4db25dcfa2994e0426b89 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 25 Sep 2025 16:29:21 +0200 Subject: [PATCH 2/7] chore: use npm hooks for backup and restore --- package.json | 2 ++ scripts/snyk-test.js | 74 +++++++++++++++++--------------------------- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index f9a7c2308..ad28554d1 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,9 @@ "check-vsix-size": "ts-node ./scripts/check-vsix-size.ts", "release-draft": "node ./scripts/release-draft.js", "reformat": "prettier --write .", + "presnyk-test": "echo \"Creating backup for package-lock.json.\"; cp package-lock.json original-package-lock.json", "snyk-test": "node scripts/snyk-test.js", + "postsnyk-test": "echo \"Restoring original package-lock.json.\"; mv original-package-lock.json package-lock.json", "generate-icon-font": "ts-node ./scripts/generate-icon-font.ts", "generate-vulnerability-report": "mongodb-sbom-tools generate-vulnerability-report --snyk-reports=.sbom/snyk-test-result.json --dependencies=.sbom/dependencies.json --fail-on=high", "create-vulnerability-tickets": "mongodb-sbom-tools generate-vulnerability-report --snyk-reports=.sbom/snyk-test-result.json --dependencies=.sbom/dependencies.json --create-jira-issues", diff --git a/scripts/snyk-test.js b/scripts/snyk-test.js index 038548560..9878c1e78 100644 --- a/scripts/snyk-test.js +++ b/scripts/snyk-test.js @@ -33,38 +33,27 @@ const PACKAGE_LOCK_PATH = path.join(__dirname, '..', 'package-lock.json'); * original state back. */ async function removeProblematicOptionalDepsFromPackageLock() { - const TEMP_PACKAGE_LOCK_PATH = path.join( - __dirname, - '..', - 'original-package-lock.json', - ); - const packageLockContent = JSON.parse( await fs.readFile(PACKAGE_LOCK_PATH, 'utf-8'), ); - if ( - !packageLockContent.packages?.['node_modules/@vscode/vsce-sign']?.[ - 'optionalDependencies' - ] - ) { + const vsceSignPackage = + packageLockContent.packages?.['node_modules/@vscode/vsce-sign']; + + if (!vsceSignPackage || !vsceSignPackage.optionalDependencies) { console.info('No problematic optional dependencies to fix'); return; } - packageLockContent.packages['node_modules/@vscode/vsce-sign'][ - 'optionalDependencies' - ] = {}; + // Temporarily remove the optional dependencies + vsceSignPackage['optionalDependencies'] = {}; - await fs.rename(PACKAGE_LOCK_PATH, TEMP_PACKAGE_LOCK_PATH); + // We write the actual package-lock path but restoring of the original file is + // handled by npm hooks. await fs.writeFile( PACKAGE_LOCK_PATH, JSON.stringify(packageLockContent, null, 2), ); - - return async function restoreOriginalPackageLock() { - return await fs.rename(TEMP_PACKAGE_LOCK_PATH, PACKAGE_LOCK_PATH); - }; } async function snykTest(cwd) { @@ -105,35 +94,28 @@ async function snykTest(cwd) { } async function main() { - let revertPackageLockChanges; - try { - const rootPath = path.resolve(__dirname, '..'); - await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true }); - revertPackageLockChanges = - await removeProblematicOptionalDepsFromPackageLock(); - const results = await snykTest(rootPath); + const rootPath = path.resolve(__dirname, '..'); + await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true }); + revertPackageLockChanges = + await removeProblematicOptionalDepsFromPackageLock(); + const results = await snykTest(rootPath); - await fs.writeFile( - path.join(rootPath, `.sbom/snyk-test-result.json`), - JSON.stringify(results, null, 2), - ); + await fs.writeFile( + path.join(rootPath, `.sbom/snyk-test-result.json`), + JSON.stringify(results, null, 2), + ); - await execFile( - 'npx', - [ - 'snyk-to-html', - '-i', - path.join(rootPath, '.sbom/snyk-test-result.json'), - '-o', - path.join(rootPath, `.sbom/snyk-test-result.html`), - ], - { cwd: rootPath }, - ); - } finally { - if (revertPackageLockChanges) { - await revertPackageLockChanges(); - } - } + await execFile( + 'npx', + [ + 'snyk-to-html', + '-i', + path.join(rootPath, '.sbom/snyk-test-result.json'), + '-o', + path.join(rootPath, `.sbom/snyk-test-result.html`), + ], + { cwd: rootPath }, + ); } main(); From 5f988537b606c191e3f5a7ff29a61a8c21d7b1cd Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 25 Sep 2025 16:31:34 +0200 Subject: [PATCH 3/7] chore: fix the method call --- scripts/snyk-test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/snyk-test.js b/scripts/snyk-test.js index 9878c1e78..47743cd63 100644 --- a/scripts/snyk-test.js +++ b/scripts/snyk-test.js @@ -30,7 +30,7 @@ const PACKAGE_LOCK_PATH = path.join(__dirname, '..', 'package-lock.json'); * Because we always install with `npm ci --omit=optional`, with this method we * try to remove these identified problematic optionalDependencies before * running the Snyk tests and once the tests are finished, we restore the - * original state back. + * original state back using npm hooks. */ async function removeProblematicOptionalDepsFromPackageLock() { const packageLockContent = JSON.parse( @@ -96,8 +96,7 @@ async function snykTest(cwd) { async function main() { const rootPath = path.resolve(__dirname, '..'); await fs.mkdir(path.join(rootPath, `.sbom`), { recursive: true }); - revertPackageLockChanges = - await removeProblematicOptionalDepsFromPackageLock(); + await removeProblematicOptionalDepsFromPackageLock(); const results = await snykTest(rootPath); await fs.writeFile( From 95acccee6ccaf0218b29369663aeabadf05b4c7b Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 24 Sep 2025 12:41:37 +0200 Subject: [PATCH 4/7] chore: reorganise GA to check and build once Earlier we were running check, build and tests on each OS in our matrix which did not allow us to test whether a build on ubuntu would work fine on Windows / MacOS or not. With this commit we are re-organising to check and build once on ubuntu and use the final artifact later in the test job to run tests against. Accordingly the test-and-build-from-fork and draft-release workflows have been modified to adapt the same change. --- .github/workflows/draft-release.yaml | 108 +++++++++++++++--- .../workflows/test-and-build-from-fork.yaml | 53 ++++++--- .github/workflows/test-and-build.yaml | 45 ++++++-- 3 files changed, 166 insertions(+), 40 deletions(-) diff --git a/.github/workflows/draft-release.yaml b/.github/workflows/draft-release.yaml index 70c290198..b64d31a28 100644 --- a/.github/workflows/draft-release.yaml +++ b/.github/workflows/draft-release.yaml @@ -1,34 +1,35 @@ +# Run manually to prepare a draft release for the next version of the extension. +# The workflow will create a draft github release where the .vsix can be +# downloaded and manually tested before publishing. To release the version, +# publish the draft release, which will trigger the publish-release workflow. name: Draft release on: workflow_dispatch: inputs: versionBump: - description: 'Version bump' + description: "Version bump" type: choice required: true - default: 'patch' + default: "patch" options: - - patch - - minor - - major - - exact-version + - patch + - minor + - major + - exact-version exactVersion: description: 'Exact version: (Only effective selecting "exact-version" as version bump)' required: false -description: | - Run manually to prepare a draft release for the next version of the extension. The workflow will create a draft - github release where the .vsix can be downloaded and manually tested before publishing. To release the version, - publish the draft release, which will trigger the publish-release workflow. - permissions: contents: write jobs: prepare-release: runs-on: ubuntu-latest + outputs: + release-tag: ${{ steps.set-tag.outputs.release-tag }} steps: - name: Checkout uses: actions/checkout@v4 @@ -85,8 +86,40 @@ jobs: exit 1 fi - - name: Run tests and build - uses: ./.github/workflows/actions/test-and-build + - name: Set release tag output + id: set-tag + run: echo "release-tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + + - name: Upload updated package.json + uses: actions/upload-artifact@v4 + with: + name: updated-package-json + path: package.json + + build-and-package: + name: Check, Build and Package + runs-on: ubuntu-latest + needs: prepare-release + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download updated package.json + uses: actions/download-artifact@v4 + with: + name: updated-package-json + + - name: Setup Node.js Environment + uses: actions/setup-node@v4 + with: + node-version: 22.15.1 + cache: npm + + - name: Check, build and package + uses: ./.github/workflows/actions/build-and-package with: SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} ARTIFACTORY_HOST: ${{ secrets.ARTIFACTORY_HOST }} @@ -97,9 +130,57 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + test: + name: Test + needs: build-and-package + + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download updated package.json + uses: actions/download-artifact@v4 + with: + name: updated-package-json + + - name: Setup Node.js Environment + uses: actions/setup-node@v4 + with: + node-version: 22.15.1 + cache: npm + + - name: Run tests + uses: ./.github/workflows/actions/run-tests + with: + SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} + + create-draft-release: + name: Create Draft Release + runs-on: ubuntu-latest + needs: [prepare-release, test] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: VSIX Package + - name: Create Draft Release run: | set -e + RELEASE_TAG="${{ needs.prepare-release.outputs.release-tag }}" echo Creating draft release for: "${RELEASE_TAG}" ls *.vsix ls *.vsix.sig @@ -114,4 +195,3 @@ jobs: shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.github/workflows/test-and-build-from-fork.yaml b/.github/workflows/test-and-build-from-fork.yaml index 91bb7345b..bbb1d792a 100644 --- a/.github/workflows/test-and-build-from-fork.yaml +++ b/.github/workflows/test-and-build-from-fork.yaml @@ -8,8 +8,40 @@ permissions: pull-requests: write jobs: - test-and-build: - name: Test and Build + build-and-package: + name: Check, Build and Package + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.head.repo.full_name != github.repository + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} + + - name: Setup Node.js Environment + uses: actions/setup-node@v4 + with: + node-version: 22.15.1 + cache: npm + + - name: Check, build and package + uses: ./.github/workflows/actions/build-and-package + with: + SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_DEV }} + ARTIFACTORY_HOST: ${{ secrets.ARTIFACTORY_HOST }} + ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} + ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} + GARASIGN_PASSWORD: ${{ secrets.GARASIGN_PASSWORD }} + GARASIGN_USERNAME: ${{ secrets.GARASIGN_USERNAME }} + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + test: + name: Test + needs: build-and-package if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.head.repo.full_name != github.repository strategy: @@ -33,25 +65,16 @@ jobs: node-version: 22.15.1 cache: npm - - name: Install Dependencies - run: npm ci --omit=optional - - - name: Run Checks - run: npm run check - # the glob here just fails - if: ${{ runner.os != 'Windows' }} - - - name: Run Tests - env: - NODE_OPTIONS: "--max_old_space_size=4096" + - name: Run tests + uses: ./.github/workflows/actions/run-tests + with: SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_DEV }} - run: npm run test merge-dependabot-pr: name: Merge Dependabot PR runs-on: ubuntu-latest needs: - - test-and-build + - test if: github.event.pull_request.user.login == 'dependabot[bot]' steps: - name: Enable auto-merge for Dependabot PRs diff --git a/.github/workflows/test-and-build.yaml b/.github/workflows/test-and-build.yaml index 5399eef5f..d8a3ee9c4 100644 --- a/.github/workflows/test-and-build.yaml +++ b/.github/workflows/test-and-build.yaml @@ -14,17 +14,11 @@ permissions: contents: read jobs: - test-and-build: - name: Test and Build + build-and-package: + name: Check, Build and Package + runs-on: ubuntu-latest if: github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - fail-fast: false - - runs-on: ${{ matrix.os }} - steps: - name: Checkout uses: actions/checkout@v4 @@ -37,8 +31,8 @@ jobs: node-version: 22.15.1 cache: npm - - name: Run tests and build - uses: ./.github/workflows/actions/test-and-build + - name: Check, build and package + uses: ./.github/workflows/actions/build-and-package with: SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} ARTIFACTORY_HOST: ${{ secrets.ARTIFACTORY_HOST }} @@ -48,3 +42,32 @@ jobs: GARASIGN_USERNAME: ${{ secrets.GARASIGN_USERNAME }} SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + test: + name: Test + needs: build-and-package + if: github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository + + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js Environment + uses: actions/setup-node@v4 + with: + node-version: 22.15.1 + cache: npm + + - name: Run tests + uses: ./.github/workflows/actions/run-tests + with: + SEGMENT_KEY: ${{ secrets.SEGMENT_KEY_PROD }} From 73b1244f305d24e40a202fc6c3b00d9e6c3553be Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 24 Sep 2025 12:45:46 +0200 Subject: [PATCH 5/7] chore: add missing actions --- .../actions/build-and-package/action.yaml | 140 ++++++++++++++++++ .../workflows/actions/run-tests/action.yaml | 80 ++++++++++ 2 files changed, 220 insertions(+) create mode 100644 .github/workflows/actions/build-and-package/action.yaml create mode 100644 .github/workflows/actions/run-tests/action.yaml diff --git a/.github/workflows/actions/build-and-package/action.yaml b/.github/workflows/actions/build-and-package/action.yaml new file mode 100644 index 000000000..4fc38e34f --- /dev/null +++ b/.github/workflows/actions/build-and-package/action.yaml @@ -0,0 +1,140 @@ +name: Check Build and Package +description: Run checks, build and package VSIX, sign it, and run security scans (Ubuntu only) +inputs: + SEGMENT_KEY: + description: Segment analytics key + required: true + ARTIFACTORY_HOST: + description: Artifactory host for signing + required: true + ARTIFACTORY_PASSWORD: + description: Artifactory password for signing + required: true + ARTIFACTORY_USERNAME: + description: Artifactory username for signing + required: true + GARASIGN_PASSWORD: + description: Garasign password for signing + required: true + GARASIGN_USERNAME: + description: Garasign username for signing + required: true + SNYK_TOKEN: + description: Snyk token for security scanning + required: true + JIRA_API_TOKEN: + description: Jira API token for vulnerability tickets + required: true + +runs: + using: "composite" + steps: + - name: Install Deps Ubuntu + run: sudo apt-get update -y && sudo apt-get -y install libkrb5-dev libsecret-1-dev net-tools libstdc++6 gnome-keyring + shell: bash + + # Default Python (3.12) doesn't have support for distutils because of + # which the dep install fails constantly on macos + # https://github.com/nodejs/node-gyp/issues/2869 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Run node-gyp bug workaround script + run: | + curl -sSfLO https://raw.githubusercontent.com/mongodb-js/compass/42e6142ae08be6fec944b80ff6289e6bcd11badf/.evergreen/node-gyp-bug-workaround.sh && bash node-gyp-bug-workaround.sh + shell: bash + + - name: Set SEGMENT_KEY + env: + SEGMENT_KEY: ${{ inputs.SEGMENT_KEY }} + run: | + echo "SEGMENT_KEY=${SEGMENT_KEY}" >> $GITHUB_ENV + shell: bash + + - name: Validate SEGMENT_KEY + run: | + if [ -z "${SEGMENT_KEY}" ]; then + echo "SEGMENT_KEY is not set or is empty" + exit 1 + fi + shell: bash + + - name: Install Dependencies + shell: bash + run: | + npm ci --omit=optional + + - name: Run Checks + run: npm run check + shell: bash + + - name: Build .vsix + env: + NODE_OPTIONS: "--require ./scripts/no-npm-list-fail.js --max_old_space_size=4096" + # NOTE: --githubBranch is "The GitHub branch used to infer relative links in README.md." + run: | + npx vsce package --githubBranch main + shell: bash + + - name: Check .vsix filesize + run: npm run check-vsix-size + shell: bash + + - name: Sign .vsix + env: + ARTIFACTORY_PASSWORD: ${{ inputs.ARTIFACTORY_PASSWORD }} + ARTIFACTORY_USERNAME: ${{ inputs.ARTIFACTORY_USERNAME }} + GARASIGN_PASSWORD: ${{ inputs.GARASIGN_PASSWORD }} + GARASIGN_USERNAME: ${{ inputs.GARASIGN_USERNAME }} + run: | + set -e + FILE_TO_SIGN=$(find . -maxdepth 1 -name '*.vsix' -print -quit) + if [ -z "$FILE_TO_SIGN" ]; then + echo "Error: No .vsix file found in the current directory." >&2 + exit 1 + fi + node scripts/sign-vsix.js "${FILE_TO_SIGN}" + ls *.vsix.sig + shell: bash + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: VSIX Package + path: | + *.vsix + *.vsix.sig + + - name: Run Snyk Test + shell: bash + env: + SNYK_TOKEN: ${{ inputs.SNYK_TOKEN }} + run: | + npm run snyk-test > /dev/null 2>&1 + + - name: Create Jira Tickets + if: > + ( + github.event_name == 'push' && github.ref == 'refs/heads/main' || + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' + ) + shell: bash + env: + JIRA_API_TOKEN: ${{ inputs.JIRA_API_TOKEN }} + JIRA_BASE_URL: "https://jira.mongodb.org" + JIRA_PROJECT: "VSCODE" + JIRA_VULNERABILITY_BUILD_INFO: "- [GitHub Run|https://github.com/mongodb-js/vscode/actions/runs/${{github.run_id}}/jobs/${{github.job}}]" + run: | + npm run create-vulnerability-tickets > /dev/null + + - name: Generate Vulnerability Report (Fail on >= High) + continue-on-error: ${{ github.event_name == 'pull_request' }} + shell: bash + run: | + # The standard output is suppressed since Github Actions logs are + # available for everyone with read access to the repo, which is everyone that is + # logged in for public repos. + # This command is only here to fail on failures for `main` and tags. + npm run generate-vulnerability-report > /dev/null diff --git a/.github/workflows/actions/run-tests/action.yaml b/.github/workflows/actions/run-tests/action.yaml new file mode 100644 index 000000000..df1cf5ece --- /dev/null +++ b/.github/workflows/actions/run-tests/action.yaml @@ -0,0 +1,80 @@ +name: Run Tests +description: Run checks, tests, and install tests on the VSIX package +inputs: + SEGMENT_KEY: + description: Segment analytics key + required: true + +runs: + using: "composite" + steps: + - name: Install Deps Ubuntu + if: ${{ runner.os == 'Linux' }} + run: sudo apt-get update -y && sudo apt-get -y install libkrb5-dev libsecret-1-dev net-tools libstdc++6 gnome-keyring + shell: bash + + # Default Python (3.12) doesn't have support for distutils because of + # which the dep install fails constantly on macos + # https://github.com/nodejs/node-gyp/issues/2869 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Run node-gyp bug workaround script + run: | + curl -sSfLO https://raw.githubusercontent.com/mongodb-js/compass/42e6142ae08be6fec944b80ff6289e6bcd11badf/.evergreen/node-gyp-bug-workaround.sh && bash node-gyp-bug-workaround.sh + shell: bash + + - name: Set SEGMENT_KEY + env: + SEGMENT_KEY: ${{ inputs.SEGMENT_KEY }} + run: | + echo "SEGMENT_KEY=${SEGMENT_KEY}" >> $GITHUB_ENV + shell: bash + + - name: Validate SEGMENT_KEY + run: | + if [ -z "${SEGMENT_KEY}" ]; then + echo "SEGMENT_KEY is not set or is empty" + exit 1 + fi + shell: bash + + - name: Install Dependencies + shell: bash + run: | + npm ci --omit=optional + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: VSIX Package + + - name: Run Tests + env: + NODE_OPTIONS: "--max_old_space_size=4096" + run: | + npm run test + shell: bash + + - name: Install VSIX and Test + shell: bash + run: | + # Find the VSIX file + VSIX_FILE=$(find . -maxdepth 1 -name '*.vsix' -print -quit) + if [ -z "$VSIX_FILE" ]; then + echo "Error: No .vsix file found" >&2 + exit 1 + fi + + echo "Found VSIX file: $VSIX_FILE" + + # For now, just verify the file exists and is readable + # Next, this will include actual VS Code installation tests + if [ ! -r "$VSIX_FILE" ]; then + echo "Error: VSIX file is not readable" >&2 + exit 1 + fi + + echo "VSIX file validation passed" + ls -la "$VSIX_FILE" From 5238fda7bca90d2851d750ef255059f714834d61 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 24 Sep 2025 13:58:12 +0200 Subject: [PATCH 6/7] chore: debug snyk tests --- .github/workflows/actions/build-and-package/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/actions/build-and-package/action.yaml b/.github/workflows/actions/build-and-package/action.yaml index 4fc38e34f..ce5dc486f 100644 --- a/.github/workflows/actions/build-and-package/action.yaml +++ b/.github/workflows/actions/build-and-package/action.yaml @@ -111,7 +111,7 @@ runs: env: SNYK_TOKEN: ${{ inputs.SNYK_TOKEN }} run: | - npm run snyk-test > /dev/null 2>&1 + npm run snyk-test - name: Create Jira Tickets if: > From de363299b4ef393fc543e6798d424db595d1fe65 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 24 Sep 2025 17:04:49 +0200 Subject: [PATCH 7/7] chore: compile before the rest --- .github/workflows/actions/build-and-package/action.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/actions/build-and-package/action.yaml b/.github/workflows/actions/build-and-package/action.yaml index ce5dc486f..0f36d0947 100644 --- a/.github/workflows/actions/build-and-package/action.yaml +++ b/.github/workflows/actions/build-and-package/action.yaml @@ -61,9 +61,12 @@ runs: shell: bash - name: Install Dependencies + run: npm ci --omit=optional + shell: bash + + - name: Compile + run: npm run compile shell: bash - run: | - npm ci --omit=optional - name: Run Checks run: npm run check