From 887fa0997c7fd67ab73878b2372270cdfeb2fe5b Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:00:32 -0700 Subject: [PATCH 1/3] GitOps Account - improved API access verification --- npm-shrinkwrap.json | 416 ++++++++++++---------------- package.json | 4 +- src/external/switcher-api-facade.js | 11 + src/routers/gitops.js | 58 +++- src/services/gitops/index.js | 26 +- tests/client-api.test.js | 12 +- tests/fixtures/db_client.js | 11 +- tests/gitops-account.test.js | 102 ++++++- 8 files changed, 378 insertions(+), 262 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 85633ac..2103325 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -22,8 +22,8 @@ "helmet": "^8.0.0", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", - "mongodb": "^6.9.0", - "mongoose": "^8.7.2", + "mongodb": "^6.10.0", + "mongoose": "^8.7.3", "pino": "^9.5.0", "pino-pretty": "^11.3.0", "swagger-ui-express": "^5.0.1", @@ -55,12 +55,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", + "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", "dev": true, "dependencies": { - "@babel/highlight": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -68,30 +69,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", + "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.8", - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.8", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -107,12 +108,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", + "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", "dev": true, "dependencies": { - "@babel/types": "^7.25.7", + "@babel/parser": "^7.26.0", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -122,13 +124,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -138,28 +140,27 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -169,160 +170,61 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "version": "7.26.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", + "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", "dev": true, "dependencies": { - "@babel/types": "^7.25.8" + "@babel/types": "^7.26.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -383,12 +285,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", - "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -422,12 +324,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", - "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -539,12 +441,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", - "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -554,30 +456,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -595,14 +497,13 @@ } }, "node_modules/@babel/types": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -615,16 +516,19 @@ "dev": true }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -642,9 +546,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.2.tgz", + "integrity": "sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1353,12 +1257,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", + "version": "22.8.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz", + "integrity": "sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==", "dev": true, "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.19.8" } }, "node_modules/@types/stack-utils": { @@ -1811,9 +1715,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -1830,10 +1734,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -1852,9 +1756,9 @@ } }, "node_modules/bson": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", - "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz", + "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==", "engines": { "node": ">=16.20.1" } @@ -1938,9 +1842,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001671", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001671.tgz", + "integrity": "sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A==", "dev": true, "funding": [ { @@ -2366,9 +2270,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.41", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", - "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", + "version": "1.5.47", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz", + "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==", "dev": true }, "node_modules/emittery": { @@ -4636,9 +4540,9 @@ } }, "node_modules/mongodb": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", - "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz", + "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==", "dependencies": { "@mongodb-js/saslprep": "^1.1.5", "bson": "^6.7.0", @@ -4690,9 +4594,9 @@ } }, "node_modules/mongoose": { - "version": "8.7.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.2.tgz", - "integrity": "sha512-Ok4VzMds9p5G3ZSUhmvBm1GdxanbzhS29jpSn02SPj+IXEVFnIdfwAlHHXWkyNscZKlcn8GuMi68FH++jo0flg==", + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.3.tgz", + "integrity": "sha512-Xl6+dzU5ZpEcDoJ8/AyrIdAwTY099QwpolvV73PIytpK13XqwllLq/9XeVzzLEQgmyvwBVGVgjmMrKbuezxrIA==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", @@ -4710,6 +4614,51 @@ "url": "https://opencollective.com/mongoose" } }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", + "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", @@ -4762,9 +4711,9 @@ } }, "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.3.tgz", - "integrity": "sha512-golm/Sc4CqLV/ZalIP14Nre7zPgd8xG/S3nHULMTBHMX0llyTNhE1O6nrgbfvLX2o0y849CnLKdu8OE05Ztiiw==", + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.4.tgz", + "integrity": "sha512-wpUq+QiKxrWk7U2pdvNSY9fNX62/k+7eEdlQMO0A3rU8tQ+vvzY/WzBhMz+GbQlATXZlXWYQqFWNFcn1SVvThA==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -6050,15 +5999,6 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 7bf4923..949bffd 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "helmet": "^8.0.0", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", - "mongodb": "^6.9.0", - "mongoose": "^8.7.2", + "mongodb": "^6.10.0", + "mongoose": "^8.7.3", "pino": "^9.5.0", "pino-pretty": "^11.3.0", "swagger-ui-express": "^5.0.1", diff --git a/src/external/switcher-api-facade.js b/src/external/switcher-api-facade.js index 4bd5803..a1caab6 100644 --- a/src/external/switcher-api-facade.js +++ b/src/external/switcher-api-facade.js @@ -27,6 +27,7 @@ export const SwitcherKeys = Object.freeze({ ACCOUNT_OUT_NOTIFY: 'ACCOUNT_OUT_NOTIFY', SLACK_INTEGRATION: 'SLACK_INTEGRATION', GITOPS_INTEGRATION: 'GITOPS_INTEGRATION', + GITOPS_SUBSCRIPTION: 'GITOPS_SUBSCRIPTION', RATE_LIMIT: 'RATE_LIMIT', HTTPS_AGENT: 'HTTPS_AGENT' }); @@ -214,6 +215,16 @@ export async function checkGitopsIntegration(value) { switcherFlagResult(featureFlag, 'GitOps Integration is not available.'); } +export function notifyGitopsSubscription(action) { + if (process.env.SWITCHER_API_ENABLE != 'true') { + return; + } + + Client.getSwitcher(SwitcherKeys.GITOPS_SUBSCRIPTION) + .checkValue(action) + .isItOn(); +} + export function notifyAcCreation(adminid) { if (process.env.SWITCHER_API_ENABLE != 'true') { return; diff --git a/src/routers/gitops.js b/src/routers/gitops.js index 40eeeea..7de53e5 100644 --- a/src/routers/gitops.js +++ b/src/routers/gitops.js @@ -4,13 +4,21 @@ import { responseExceptionSilent } from '../exceptions/index.js'; import { auth, gitopsAuth } from '../middleware/auth.js'; import { validate } from '../middleware/validators.js'; import { featureFlag, validateChanges } from '../middleware/gitops.js'; +import { notifyGitopsSubscription } from '../external/switcher-api-facade.js'; import * as Service from '../services/gitops/index.js'; +import { verifyOwnership } from '../helpers/index.js'; +import { ActionTypes, RouterTypes } from '../models/permission.js'; const router = new express.Router(); -const regex = new RegExp(/^\d+[smh]$/); + +// Allow only values like 1s, 1m, 1h +const regexWindowInterval = new RegExp(/^\d+[smh]$/); + +// Allow slash, alphanumeric, hyphen, underscore, dot only +const regexPath = new RegExp(/^[a-zA-Z0-9/_\-.]+$/); const windowValidation = (value) => { - if (!regex.test(value)) { + if (!regexWindowInterval.test(value)) { throw new Error('Invalid window value'); } @@ -25,11 +33,25 @@ const windowValidation = (value) => { return true; }; +const pathValidation = (value) => { + if (value) { + if (value.startsWith('/') || value.endsWith('/') || value.includes('//')) { + throw new Error('Invalid path value - cannot start or end with / or contain //'); + } + + if (!regexPath.test(value)) { + throw new Error('Invalid path value - only alphanumeric characters and / are allowed'); + } + } + + return true; +}; + const accountValidators = [ body('token').isString().optional(), body('repository').isURL().withMessage('Invalid repository URL'), body('branch').isString().withMessage('Invalid branch name'), - body('path').isString().optional().withMessage('Invalid path'), + body('path').isString().optional().custom(pathValidation), body('environment').isString().withMessage('Invalid environment name'), body('domain.id').isMongoId().withMessage('Invalid domain ID'), body('domain.name').isString().withMessage('Invalid domain name'), @@ -38,6 +60,16 @@ const accountValidators = [ body('settings.forceprune').isBoolean().withMessage('Invalid forceprune flag'), ]; +const verifyOwnershipMiddleware = async (req, res, next) => { + try { + const domainId = req.body?.domain.id || req.params.domain; + await verifyOwnership(req.admin, domainId, domainId, ActionTypes.UPDATE, RouterTypes.ADMIN); + next(); + } catch (e) { + responseExceptionSilent(res, e, 403, 'Permission denied'); + } +}; + router.post('/gitops/v1/push', gitopsAuth, featureFlag, [ body('environment').isString(), body('changes').isArray(), @@ -58,9 +90,11 @@ router.post('/gitops/v1/push', gitopsAuth, featureFlag, [ }); router.post('/gitops/v1/account/subscribe', auth, accountValidators, validate, - featureFlag, async (req, res) => { + featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { const account = await Service.subscribeAccount(req.body); + notifyGitopsSubscription('subscribe'); + res.status(201).send(account); } catch (e) { responseExceptionSilent(res, e, 500, 'Account subscription failed'); @@ -70,9 +104,11 @@ router.post('/gitops/v1/account/subscribe', auth, accountValidators, validate, router.post('/gitops/v1/account/unsubscribe', auth, [ body('environment').isString(), body('domain.id').isMongoId().withMessage('Invalid domain ID'), -], validate, featureFlag, async (req, res) => { +], validate, featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { await Service.unsubscribeAccount(req.body); + notifyGitopsSubscription('unsubscribe'); + res.status(200).send(); } catch (e) { responseExceptionSilent(res, e, 500, 'Account unsubscription failed'); @@ -80,7 +116,7 @@ router.post('/gitops/v1/account/unsubscribe', auth, [ }); router.put('/gitops/v1/account', auth, accountValidators, validate, - featureFlag, async (req, res) => { + featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { const account = await Service.updateAccount(req.body); res.status(200).send(account); @@ -93,10 +129,10 @@ router.put('/gitops/v1/account/tokens', auth, [ body('token').isString(), body('environments').isArray(), body('domain.id').isMongoId().withMessage('Invalid domain ID'), -], validate, featureFlag, async (req, res) => { +], validate, featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { - const account = await Service.updateAccountTokens(req.body); - res.status(200).send(account); + const result = await Service.updateAccountTokens(req.body); + res.status(200).send(result); } catch (e) { responseExceptionSilent(res, e, 500, 'Account token update failed'); } @@ -105,7 +141,7 @@ router.put('/gitops/v1/account/tokens', auth, [ router.put('/gitops/v1/account/forcesync', auth, [ body('environment').isString(), body('domain.id').isMongoId().withMessage('Invalid domain ID'), -], validate, featureFlag, async (req, res) => { +], validate, featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { const account = await Service.forceSyncAccount(req.body); res.status(200).send(account); @@ -117,7 +153,7 @@ router.put('/gitops/v1/account/forcesync', auth, [ router.get('/gitops/v1/account/:domain', auth, [ check('domain').isMongoId().withMessage('Invalid domain ID'), check('environment').optional().isString(), -], validate, featureFlag, async (req, res) => { +], validate, featureFlag, verifyOwnershipMiddleware, async (req, res) => { try { const accounts = await Service.fetchAccounts(req.params.domain, req.query.environment || null); res.status(200).send(accounts); diff --git a/src/services/gitops/index.js b/src/services/gitops/index.js index 08228b8..270400a 100644 --- a/src/services/gitops/index.js +++ b/src/services/gitops/index.js @@ -30,11 +30,33 @@ export async function pushChanges(domainId, environment, changes) { } export async function subscribeAccount(account) { - return GitOpsFacade.createAccount(account); + return GitOpsFacade.createAccount({ + repository: account.repository, + environment: account.environment, + branch: account.branch, + token: account.token, + path: account.path, + settings: account.settings, + domain: { + id: account.domain.id, + name: account.domain.name + } + }); } export async function updateAccount(account) { - return GitOpsFacade.updateAccount(account); + return GitOpsFacade.updateAccount({ + repository: account.repository, + environment: account.environment, + branch: account.branch, + token: account.token, + path: account.path, + settings: account.settings, + domain: { + id: account.domain.id, + name: account.domain.name + } + }); } export async function updateAccountTokens(account) { diff --git a/tests/client-api.test.js b/tests/client-api.test.js index 865204b..16a325a 100644 --- a/tests/client-api.test.js +++ b/tests/client-api.test.js @@ -262,6 +262,11 @@ describe('Testing domain [Adm-GraphQL] ', () => { expect(req.statusCode).toBe(200); expect(JSON.parse(req.text)).toMatchObject(JSON.parse(graphqlUtils.expected111)); }); +}); + +describe('Testing domain [Adm-GraphQL] - Permission', () => { + + afterAll(setupDatabase); test('CLIENT_SUITE - Should return list of Groups permissions', async () => { const req = await request(app) @@ -366,11 +371,6 @@ describe('Testing domain [Adm-GraphQL] ', () => { expect(JSON.parse(req.text)).not.toBe(null); expect(JSON.parse(req.text).data.permission).toStrictEqual([]); }); -}); - -describe('Testing domain [Adm-GraphQL] - Permission', () => { - - afterAll(setupDatabase); test('CLIENT_SUITE - Should return domain partial structure based on permission', async () => { // Given @@ -393,7 +393,7 @@ describe('Testing domain [Adm-GraphQL] - Permission', () => { expect(JSON.parse(req.text)).toMatchObject(JSON.parse(graphqlUtils.expected1071)); }); - test('CLIENT_SUITE - Should NOT return complete domain structure - no valid COnfig permission', async () => { + test('CLIENT_SUITE - Should NOT return complete domain structure - no valid Config permission', async () => { // Given const admin = await Admin.findById(adminAccountId).exec(); await setPermissionsToTeam(admin.teams[0], { diff --git a/tests/fixtures/db_client.js b/tests/fixtures/db_client.js index 0b49c99..698a0fb 100644 --- a/tests/fixtures/db_client.js +++ b/tests/fixtures/db_client.js @@ -182,13 +182,21 @@ export const permissionConfigs2 = { environments: [EnvType.DEFAULT] }; +export const permissionAdminId = new mongoose.Types.ObjectId(); +export const permissionAdmin = { + _id: permissionAdminId, + action: ActionTypes.UPDATE, + active: true, + router: RouterTypes.ADMIN +}; + export const teamId = new mongoose.Types.ObjectId(); export const team = { _id: teamId, domain: domainId, name: 'Team Dev', active: true, - permissions: [permissionConfigsId, permissionConfigs2Id] + permissions: [permissionConfigsId, permissionConfigs2Id, permissionAdminId] }; export const slack = { @@ -229,6 +237,7 @@ export const setupDatabase = async () => { await new Team(team).save(); await new Permission(permissionConfigs).save(); await new Permission(permissionConfigs2).save(); + await new Permission(permissionAdmin).save(); await new GroupConfig(groupConfigDocument).save(); await new Config(configDocument).save(); diff --git a/tests/gitops-account.test.js b/tests/gitops-account.test.js index 45cc0d4..acc73a8 100644 --- a/tests/gitops-account.test.js +++ b/tests/gitops-account.test.js @@ -4,11 +4,14 @@ import sinon from 'sinon'; import request from 'supertest'; import { Client } from 'switcher-client'; import app from '../src/app'; +import { Permission } from '../src/models/permission'; import { EnvType } from '../src/models/environment'; import { setupDatabase, domainId, - adminMasterAccountToken + adminMasterAccountToken, + adminAccountToken, + permissionAdminId } from './fixtures/db_client'; afterAll(async () => { @@ -61,6 +64,50 @@ describe('GitOps Account - Feature Toggle', () => { }); }); +describe('GitOps Account - Forbidden', () => { + beforeAll(async () => { + await setupDatabase(); + + // diable team permissions + const permission = await Permission.findById(permissionAdminId); + permission.active = false; + await permission.save(); + }); + + test('GITOPS_ACCOUNT_SUITE - Should not subscribe account - body.domain', async () => { + const req = await request(app) + .post('/gitops/v1/account/subscribe') + .set('Authorization', `Bearer ${adminAccountToken}`) + .send({ + repository: 'https://github.com/switcherapi/switcher-gitops-fixture', + token: '{{github_pat}}', + branch: 'main', + environment: EnvType.DEFAULT, + domain: { + id: String(domainId), + name: 'Test Domain' + }, + settings: { + active: true, + window: '30s', + forceprune: true + } + }) + .expect(403); + + expect(req.body.error).toBe('Permission denied'); + }); + + test('GITOPS_ACCOUNT_SUITE - Should not fetch all accounts by Domain ID - param.domain', async () => { + const req = await request(app) + .get(`/gitops/v1/account/${domainId}`) + .set('Authorization', `Bearer ${adminAccountToken}`) + .expect(403); + + expect(req.body.error).toBe('Permission denied'); + }); +}); + describe('GitOps Account - Subscribe', () => { beforeAll(setupDatabase); @@ -81,6 +128,10 @@ describe('GitOps Account - Subscribe', () => { }; test('GITOPS_ACCOUNT_SUITE - Should subscribe account', async () => { + process.env.SWITCHER_API_ENABLE = true; + Client.assume('GITOPS_INTEGRATION').true(); + Client.assume('GITOPS_SUBSCRIPTION').true(); + // given const expectedResponse = JSON.parse(JSON.stringify(VALID_SUBSCRIPTION_REQUEST)); expectedResponse.token = '...123'; @@ -93,13 +144,17 @@ describe('GitOps Account - Subscribe', () => { // test const req = await request(app) .post('/gitops/v1/account/subscribe') - .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .set('Authorization', `Bearer ${adminAccountToken}`) .send(VALID_SUBSCRIPTION_REQUEST) .expect(201); // assert expect(req.body).toMatchObject(expectedResponse); + postStub.restore(); + process.env.SWITCHER_API_ENABLE = false; + Client.forget('GITOPS_INTEGRATION'); + Client.forget('GITOPS_SUBSCRIPTION'); }); test('GITOPS_ACCOUNT_SUITE - Should return error - error creating account', async () => { @@ -305,6 +360,49 @@ describe('GitOps Account - Update', () => { expect(req.body.errors[0].msg).toBe('Invalid domain ID'); }); + + test('GITOPS_ACCOUNT_SUITE - Should return error - path uses invalid slashes', async () => { + const payload = JSON.parse(JSON.stringify(VALID_UPDATE_REQUEST)); + + // start with '/' + payload.path = '/path/to/file'; + await request(app) + .put('/gitops/v1/account') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(payload) + .expect(422); + + // end with '/' + payload.path = 'path/to/file/'; + await request(app) + .put('/gitops/v1/account') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(payload) + .expect(422); + + // contains '//' + payload.path = 'path//to/file'; + const req = await request(app) + .put('/gitops/v1/account') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(payload) + .expect(422); + + expect(req.body.errors[0].msg).toBe('Invalid path value - cannot start or end with / or contain //'); + }); + + test('GITOPS_ACCOUNT_SUITE - Should return error - path contains invalid characters', async () => { + const payload = JSON.parse(JSON.stringify(VALID_UPDATE_REQUEST)); + payload.path = 'path/to/file#'; + + const req = await request(app) + .put('/gitops/v1/account') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(payload) + .expect(422); + + expect(req.body.errors[0].msg).toBe('Invalid path value - only alphanumeric characters and / are allowed'); + }); }) From 6dc5e84738177787c9eb7dfd969bfd14fe9974f7 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:07:30 -0700 Subject: [PATCH 2/3] chore: removed unnecessary check for path --- src/routers/gitops.js | 14 ++++++-------- tests/gitops-account.test.js | 1 - 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/routers/gitops.js b/src/routers/gitops.js index 7de53e5..a970452 100644 --- a/src/routers/gitops.js +++ b/src/routers/gitops.js @@ -34,14 +34,12 @@ const windowValidation = (value) => { }; const pathValidation = (value) => { - if (value) { - if (value.startsWith('/') || value.endsWith('/') || value.includes('//')) { - throw new Error('Invalid path value - cannot start or end with / or contain //'); - } - - if (!regexPath.test(value)) { - throw new Error('Invalid path value - only alphanumeric characters and / are allowed'); - } + if (value.startsWith('/') || value.endsWith('/') || value.includes('//')) { + throw new Error('Invalid path value - cannot start or end with / or contain //'); + } + + if (!regexPath.test(value)) { + throw new Error('Invalid path value - only alphanumeric characters and / are allowed'); } return true; diff --git a/tests/gitops-account.test.js b/tests/gitops-account.test.js index acc73a8..da040af 100644 --- a/tests/gitops-account.test.js +++ b/tests/gitops-account.test.js @@ -272,7 +272,6 @@ describe('GitOps Account - Update', () => { repository: 'https://github.com/switcherapi/switcher-gitops-fixture', branch: 'main', environment: EnvType.DEFAULT, - path: 'path/to/file', domain: { id: String(domainId), name: 'Test Domain' From 12ec00bc714817759e162ceca674a8aa7ec70676 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:13:22 -0700 Subject: [PATCH 3/3] chore: fixes test fixture --- tests/gitops-account.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/gitops-account.test.js b/tests/gitops-account.test.js index da040af..acc73a8 100644 --- a/tests/gitops-account.test.js +++ b/tests/gitops-account.test.js @@ -272,6 +272,7 @@ describe('GitOps Account - Update', () => { repository: 'https://github.com/switcherapi/switcher-gitops-fixture', branch: 'main', environment: EnvType.DEFAULT, + path: 'path/to/file', domain: { id: String(domainId), name: 'Test Domain'