From 11563091cd0bf739b62350b80fc07138e7640199 Mon Sep 17 00:00:00 2001 From: Konstantin Konstantinov Date: Fri, 16 Jan 2026 23:57:47 +0200 Subject: [PATCH 1/3] feat: OSS SAST set up --- .github/workflows/main.yml | 7 +- .gitignore | 1 + common/vitest-config/package.json | 3 +- common/vitest-config/vitest.config.js | 17 +++ examples/shared/package.json | 1 + package.json | 5 +- packages/client/package.json | 1 + packages/core/package.json | 1 + packages/middleware/express/package.json | 1 + packages/middleware/hono/package.json | 1 + packages/middleware/node/package.json | 1 + packages/server/package.json | 1 + pnpm-lock.yaml | 127 +++++++++++++++++++++++ pnpm-workspace.yaml | 1 + sonar-project.properties | 26 +++++ test/integration/package.json | 1 + vitest.config.js | 32 ++++++ vitest.workspace.js | 6 +- 18 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 sonar-project.properties create mode 100644 vitest.config.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 495ca5581..dbae89cbf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,12 @@ jobs: - run: pnpm install - - run: pnpm test:all + - run: pnpm test:coverage:all + + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} publish: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 4690b14d1..0ada37544 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ lib-cov # Coverage directory used by tools like istanbul coverage +reports *.lcov # nyc test coverage diff --git a/common/vitest-config/package.json b/common/vitest-config/package.json index 3ae59937e..94707ba88 100644 --- a/common/vitest-config/package.json +++ b/common/vitest-config/package.json @@ -23,6 +23,7 @@ "version": "2.0.0", "devDependencies": { "@modelcontextprotocol/tsconfig": "workspace:^", - "vite-tsconfig-paths": "catalog:devTools" + "vite-tsconfig-paths": "catalog:devTools", + "vitest-sonar-reporter": "^3.0.0" } } diff --git a/common/vitest-config/vitest.config.js b/common/vitest-config/vitest.config.js index 71e0d71f6..105adfe6b 100644 --- a/common/vitest-config/vitest.config.js +++ b/common/vitest-config/vitest.config.js @@ -6,15 +6,32 @@ import url from 'node:url'; const ignorePatterns = ['**/dist/**']; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); +const reporters = ['default']; +const outputFile = {}; + +if (process.env.GITHUB_ACTIONS === 'true') { + reporters.push([import.meta.resolve('vitest-sonar-reporter'), { silent: true }], 'github-actions'); + outputFile['vitest-sonar-reporter'] = 'reports/sonar-report.xml'; +} + export default defineConfig({ test: { globals: true, environment: 'node', include: ['test/**/*.test.ts'], exclude: ignorePatterns, + reporters, + outputFile, deps: { moduleDirectories: ['node_modules', path.resolve(__dirname, '../../packages'), path.resolve(__dirname, '../../common')] }, + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html', 'lcov'], + reportsDirectory: './coverage', + include: ['src/**/*.ts'], + exclude: ['**/dist/**', '**/node_modules/**', '**/*.test.ts', '**/*.spec.ts'], + }, }, poolOptions: { threads: { diff --git a/examples/shared/package.json b/examples/shared/package.json index 3d3e7410a..41e032642 100644 --- a/examples/shared/package.json +++ b/examples/shared/package.json @@ -28,6 +28,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/package.json b/package.json index bb5154716..b6abd72f6 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "lint:fix:all": "pnpm -r lint:fix", "check:all": "pnpm -r typecheck && pnpm -r lint", "test:all": "pnpm -r test", + "test:coverage:all": "vitest run --coverage", "test:conformance:client": "conformance client --command 'npx tsx src/conformance/everything-client.ts'", "test:conformance:client:all": "conformance client --command 'npx tsx src/conformance/everything-client.ts' --suite all", "test:conformance:client:run": "npx tsx src/conformance/everything-client.ts", @@ -45,8 +46,9 @@ "@eslint/js": "catalog:devTools", "@modelcontextprotocol/client": "workspace:^", "@modelcontextprotocol/conformance": "0.1.9", - "@modelcontextprotocol/server": "workspace:^", "@modelcontextprotocol/node": "workspace:^", + "@modelcontextprotocol/server": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", "@types/content-type": "catalog:devTools", "@types/cors": "catalog:devTools", "@types/cross-spawn": "catalog:devTools", @@ -57,6 +59,7 @@ "@types/supertest": "catalog:devTools", "@types/ws": "catalog:devTools", "@typescript/native-preview": "catalog:devTools", + "@vitest/coverage-v8": "catalog:devTools", "cors": "catalog:runtimeServerOnly", "eslint": "catalog:devTools", "eslint-config-prettier": "catalog:devTools", diff --git a/packages/client/package.json b/packages/client/package.json index 0b02a42e8..ea8fe19bf 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -39,6 +39,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/packages/core/package.json b/packages/core/package.json index 33bfe54ed..97fc178ec 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -28,6 +28,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/packages/middleware/express/package.json b/packages/middleware/express/package.json index 408cf446a..545cffad5 100644 --- a/packages/middleware/express/package.json +++ b/packages/middleware/express/package.json @@ -41,6 +41,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest" }, "dependencies": {}, diff --git a/packages/middleware/hono/package.json b/packages/middleware/hono/package.json index 3377c5fb4..5996a026d 100644 --- a/packages/middleware/hono/package.json +++ b/packages/middleware/hono/package.json @@ -41,6 +41,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest" }, "dependencies": {}, diff --git a/packages/middleware/node/package.json b/packages/middleware/node/package.json index 766346613..f95990818 100644 --- a/packages/middleware/node/package.json +++ b/packages/middleware/node/package.json @@ -40,6 +40,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/packages/server/package.json b/packages/server/package.json index d6c78541a..3277b3aee 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -39,6 +39,7 @@ "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66600384f..5483f1eef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ catalogs: '@typescript/native-preview': specifier: ^7.0.0-dev.20251217.1 version: 7.0.0-dev.20260105.1 + '@vitest/coverage-v8': + specifier: ^4.0.16 + version: 4.0.16 eslint: specifier: ^9.8.0 version: 9.39.2 @@ -152,6 +155,9 @@ importers: '@modelcontextprotocol/server': specifier: workspace:^ version: link:packages/server + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:common/vitest-config '@types/content-type': specifier: catalog:devTools version: 1.1.9 @@ -182,6 +188,9 @@ importers: '@typescript/native-preview': specifier: catalog:devTools version: 7.0.0-dev.20260105.1 + '@vitest/coverage-v8': + specifier: catalog:devTools + version: 4.0.16(vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0)) cors: specifier: catalog:runtimeServerOnly version: 2.8.5 @@ -277,6 +286,9 @@ importers: vite-tsconfig-paths: specifier: catalog:devTools version: 5.1.4(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(tsx@4.21.0)) + vitest-sonar-reporter: + specifier: ^3.0.0 + version: 3.0.0(vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0)) examples/client: dependencies: @@ -917,6 +929,10 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@better-auth/core@1.4.7': resolution: {integrity: sha512-rNfj8aNFwPwAMYo+ahoWDsqKrV7svD3jhHSC6+A77xxKodbgV0UgH+RO21GMaZ0PPAibEl851nw5e3bsNslW/w==} peerDependencies: @@ -1905,6 +1921,15 @@ packages: cpu: [x64] os: [win32] + '@vitest/coverage-v8@4.0.16': + resolution: {integrity: sha512-2rNdjEIsPRzsdu6/9Eq0AYAzYdpP6Bx9cje9tL3FE5XzXRQF1fNU9pe/1yE8fCrS0HD+fBtt6gLPh6LI57tX7A==} + peerDependencies: + '@vitest/browser': 4.0.16 + vitest: 4.0.16 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@4.0.16': resolution: {integrity: sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==} @@ -2023,6 +2048,9 @@ packages: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} + ast-v8-to-istanbul@0.3.10: + resolution: {integrity: sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -2759,6 +2787,9 @@ packages: hookable@6.0.1: resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -2928,9 +2959,28 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + jose@6.1.3: resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true @@ -2994,6 +3044,13 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -3774,6 +3831,12 @@ packages: yaml: optional: true + vitest-sonar-reporter@3.0.0: + resolution: {integrity: sha512-QRT5m9Z/3Kt0WVDVcFHm5LC9Ba89yDP4twlX2QUAJ9PdqfJBkLAh/kXj7m6U3i0k6GxnIEiwCc295bmAYokmZg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + vitest: '>=3' + vitest@4.0.16: resolution: {integrity: sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -3899,6 +3962,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@1.0.2': {} + '@better-auth/core@1.4.7(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.5(zod@4.3.5))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0)': dependencies: '@better-auth/utils': 0.3.0 @@ -4797,6 +4862,23 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vitest/coverage-v8@4.0.16(vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0))': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.0.16 + ast-v8-to-istanbul: 0.3.10 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magicast: 0.5.1 + obug: 2.1.1 + std-env: 3.10.0 + tinyrainbow: 3.0.3 + vitest: 4.0.16(@types/node@24.10.4)(tsx@4.21.0) + transitivePeerDependencies: + - supports-color + '@vitest/expect@4.0.16': dependencies: '@standard-schema/spec': 1.1.0 @@ -4942,6 +5024,12 @@ snapshots: '@babel/parser': 7.28.5 pathe: 2.0.3 + ast-v8-to-istanbul@0.3.10: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 9.0.1 + async-function@1.0.0: {} asynckit@0.4.0: {} @@ -5759,6 +5847,8 @@ snapshots: hookable@6.0.1: {} + html-escaper@2.0.2: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -5924,8 +6014,31 @@ snapshots: isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + jose@6.1.3: {} + js-tokens@9.0.1: {} + js-yaml@3.14.2: dependencies: argparse: 1.0.10 @@ -5982,6 +6095,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.5.1: + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.3 + math-intrinsics@1.1.0: {} media-typer@1.1.0: {} @@ -6832,6 +6955,10 @@ snapshots: fsevents: 2.3.3 tsx: 4.21.0 + vitest-sonar-reporter@3.0.0(vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0)): + dependencies: + vitest: 4.0.16(@types/node@24.10.4)(tsx@4.21.0) + vitest@4.0.16(@types/node@24.10.4)(tsx@4.21.0): dependencies: '@vitest/expect': 4.0.16 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 61f34ddb3..98d0849d6 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -16,6 +16,7 @@ catalogs: '@types/supertest': ^6.0.2 '@types/ws': ^8.5.12 '@typescript/native-preview': ^7.0.0-dev.20251217.1 + '@vitest/coverage-v8': ^4.0.16 eslint: ^9.8.0 eslint-config-prettier: ^10.1.8 eslint-plugin-n: ^17.23.1 diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 000000000..bab2d287d --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,26 @@ +sonar.projectKey=modelcontextprotocol_typescript-sdk +sonar.organization=modelcontextprotocol + + +# This is the name and version displayed in the SonarCloud UI. +sonar.projectName=typescript-sdk +sonar.projectVersion=2.0.0-alpha.0 + +sonar.javascript.lcov.reportPaths=./coverage/lcov.info +sonar.testExecutionReportPaths=./reports/sonar-report.xml + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +sonar.sources=packages/ +sonar.tests=packages/ +sonar.inclusions=packages/**/src/** +sonar.exclusions=packages/**/test/**, **/node_modules/**, *.d.ts, *.tsbuildinfo, **/build/** +sonar.test.inclusions=packages/**/test/** +sonar.test.exclusions=packages/**/src/** +sonar.coverage.exclusions=packages/**/src/**/index.ts, packages/**/src/**/*.json + +# Encoding of the source code. Default is default system encoding +sonar.sourceEncoding=UTF-8 + +sonar.javascript.allowTsParserJsFiles=false +sonar.typescript.tsconfigPaths=packages/**/src/tsconfig.json +#sonar.verbose=true diff --git a/test/integration/package.json b/test/integration/package.json index 8b6022d26..73d444a90 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -26,6 +26,7 @@ "lint:fix": "eslint test/ --fix && prettier --ignore-path ../../.prettierignore --write .", "check": "npm run typecheck && npm run lint", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:watch": "vitest", "start": "npm run server", "server": "tsx watch --clear-screen=false scripts/cli.ts server", diff --git a/vitest.config.js b/vitest.config.js new file mode 100644 index 000000000..223cd34b7 --- /dev/null +++ b/vitest.config.js @@ -0,0 +1,32 @@ +import { defineConfig, mergeConfig } from 'vitest/config'; +import baseConfig from '@modelcontextprotocol/vitest-config'; + +/** + * Root vitest config for workspace-level settings. + * This config is used when running `vitest run --coverage` from the root. + * Extends from @modelcontextprotocol/vitest-config with root-specific overrides. + */ +export default mergeConfig(baseConfig, defineConfig({ + test: { + // Exclude dist directories and non-test packages from test discovery + exclude: [ + '**/dist/**', + '**/node_modules/**', + 'common/tsconfig/**', + 'common/vitest-config/**', + 'common/eslint-config/**', + ], + coverage: { + // Override coverage paths for root-level merged report + include: ['packages/**/src/**/*.ts', 'examples/**/src/**/*.ts'], + exclude: [ + '**/dist/**', + '**/node_modules/**', + '**/*.test.ts', + '**/*.spec.ts', + 'common/**', + 'test/**', + ], + }, + }, +})); diff --git a/vitest.workspace.js b/vitest.workspace.js index b09f1f1fd..14b5ea211 100644 --- a/vitest.workspace.js +++ b/vitest.workspace.js @@ -1,3 +1,7 @@ import { defineWorkspace } from 'vitest/config'; -export default defineWorkspace(['packages/**/vitest.config.js']); +export default defineWorkspace([ + 'packages/**/vitest.config.js', + 'examples/**/vitest.config.js', + 'test/**/vitest.config.js', +]); From 2ca013781e4d0bd82b05a31d168dbdc29e26c94b Mon Sep 17 00:00:00 2001 From: Konstantin Konstantinov Date: Sat, 17 Jan 2026 00:08:05 +0200 Subject: [PATCH 2/3] split sast step out of test matrix --- .github/workflows/main.yml | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dbae89cbf..17c13b923 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,12 +56,31 @@ jobs: - run: pnpm install - - run: pnpm test:coverage:all - - - name: SonarQube Scan - uses: SonarSource/sonarqube-scan-action@v6 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - run: pnpm test:all + + sast: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + id: pnpm-install + with: + run_install: false + - uses: actions/setup-node@v6 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - run: pnpm install + - run: pnpm test:coverage:all + + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} publish: runs-on: ubuntu-latest From 481337f7f736b7855891a2508222ec02d2032653 Mon Sep 17 00:00:00 2001 From: Konstantin Konstantinov Date: Sat, 17 Jan 2026 00:18:29 +0200 Subject: [PATCH 3/3] sast step run only on upstream repo --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 17c13b923..051fce4e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,6 +60,7 @@ jobs: sast: runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository steps: - uses: actions/checkout@v6