From a5b23450e8895556c7f48594771947f779945290 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Wed, 17 Jan 2024 18:02:55 +0100 Subject: [PATCH 01/30] Theia IDE files shall be ignored #2445 --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c22f570628..53f14a4885 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,9 @@ src-gen/ # vscode parts .vscode/ +# theia parts +.theia/ + # gradle parts .gradle/ From 90f57664a1f9f2ff1688c681f06005f60116b3fe Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Wed, 17 Jan 2024 18:06:59 +0100 Subject: [PATCH 02/30] Updated dependencies and versioning #2447 --- github-actions/scan/package-lock.json | 230 +++++++++++++++++--------- 1 file changed, 151 insertions(+), 79 deletions(-) diff --git a/github-actions/scan/package-lock.json b/github-actions/scan/package-lock.json index 093c67ca10..807c29d1a2 100644 --- a/github-actions/scan/package-lock.json +++ b/github-actions/scan/package-lock.json @@ -68,17 +68,89 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/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/code-frame/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/code-frame/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/code-frame/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/code-frame/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/code-frame/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/code-frame/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/compat-data": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", @@ -128,9 +200,9 @@ "peer": true }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -138,13 +210,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz", - "integrity": "sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "peer": true, "dependencies": { - "@babel/types": "^7.21.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -189,9 +261,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -199,9 +271,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "peer": true, "engines": { @@ -209,27 +281,27 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "peer": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "peer": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -292,22 +364,22 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "peer": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "peer": true, "engines": { @@ -315,9 +387,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -349,13 +421,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -434,9 +506,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", - "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "peer": true, "bin": { @@ -638,36 +710,36 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "peer": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.2.tgz", - "integrity": "sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "peer": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.2", - "@babel/types": "^7.21.2", - "debug": "^4.1.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -685,14 +757,14 @@ } }, "node_modules/@babel/types": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", - "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "peer": true, "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3050,9 +3122,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -3850,9 +3922,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -4485,9 +4557,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5002,9 +5074,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" From f9cb276102ab92ac13043b34cc421a6da49047b6 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Wed, 17 Jan 2024 18:23:38 +0100 Subject: [PATCH 03/30] Updated versions #2447 --- github-actions/scan/package-lock.json | 8 ++++---- github-actions/scan/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/github-actions/scan/package-lock.json b/github-actions/scan/package-lock.json index 807c29d1a2..1a3492803c 100644 --- a/github-actions/scan/package-lock.json +++ b/github-actions/scan/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@actions/artifact": "^1.1.0", - "@actions/core": "^1.8.2", + "@actions/core": "^1.10.1", "shelljs": "^0.8.5" }, "devDependencies": { @@ -37,9 +37,9 @@ } }, "node_modules/@actions/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", + "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", "dependencies": { "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" diff --git a/github-actions/scan/package.json b/github-actions/scan/package.json index ec315764e8..8910487430 100644 --- a/github-actions/scan/package.json +++ b/github-actions/scan/package.json @@ -12,7 +12,7 @@ "license": "MIT", "dependencies": { "@actions/artifact": "^1.1.0", - "@actions/core": "^1.8.2", + "@actions/core": "^1.10.1", "shelljs": "^0.8.5" }, "devDependencies": { From f1559cf570b9c3167d62f38dfbcf144d495fe237 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Wed, 17 Jan 2024 18:30:00 +0100 Subject: [PATCH 04/30] Simplified github actions build #2830 --- .../scan/__test__/init-scan.test.ts | 4 +- .../__test__/log-helper.test.ts | 0 .../scan/__test__/post-scan.test.ts | 6 +- .../__test__/report-format.test.ts | 0 github-actions/scan/dist/index.js | 10133 +--------------- .../{shared => scan}/src/action-helper.ts | 0 .../{shared => scan}/src/cli-helper.ts | 0 .../{shared => scan}/src/fs-helper.ts | 0 github-actions/scan/src/init-scan.ts | 4 +- .../{shared => scan}/src/log-helper.ts | 0 github-actions/scan/src/main.ts | 10 +- github-actions/scan/src/post-scan.ts | 6 +- .../{shared => scan}/src/report-formats.ts | 0 .../{shared => scan}/src/sechub-cli.ts | 0 .../{shared => scan}/src/sechub.json | 0 github-actions/scan/src/types.ts | 14 + github-actions/shared/.eslintrc.json | 34 - github-actions/shared/.prettierrc.json | 6 - github-actions/shared/jest.config.js | 7 - github-actions/shared/package-lock.json | 5078 -------- github-actions/shared/package.json | 27 - github-actions/shared/src/settings.json | 5 - github-actions/shared/src/types.ts | 15 - github-actions/shared/tsconfig.json | 10 - 24 files changed, 101 insertions(+), 15258 deletions(-) rename github-actions/{shared => scan}/__test__/log-helper.test.ts (100%) rename github-actions/{shared => scan}/__test__/report-format.test.ts (100%) rename github-actions/{shared => scan}/src/action-helper.ts (100%) rename github-actions/{shared => scan}/src/cli-helper.ts (100%) rename github-actions/{shared => scan}/src/fs-helper.ts (100%) rename github-actions/{shared => scan}/src/log-helper.ts (100%) rename github-actions/{shared => scan}/src/report-formats.ts (100%) rename github-actions/{shared => scan}/src/sechub-cli.ts (100%) rename github-actions/{shared => scan}/src/sechub.json (100%) delete mode 100644 github-actions/shared/.eslintrc.json delete mode 100644 github-actions/shared/.prettierrc.json delete mode 100644 github-actions/shared/jest.config.js delete mode 100644 github-actions/shared/package-lock.json delete mode 100644 github-actions/shared/package.json delete mode 100644 github-actions/shared/src/settings.json delete mode 100644 github-actions/shared/src/types.ts delete mode 100644 github-actions/shared/tsconfig.json diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts index 8616beceaf..065e9255d2 100644 --- a/github-actions/scan/__test__/init-scan.test.ts +++ b/github-actions/scan/__test__/init-scan.test.ts @@ -2,8 +2,8 @@ import {initReportFormats, initSecHubJson} from "../src/init-scan"; -jest.mock('../../shared/src/cli-helper'); -import {createSecHubJsonFile} from '../../shared/src/cli-helper'; +jest.mock('./../src/cli-helper'); +import {createSecHubJsonFile} from '../src/cli-helper'; describe('initSecHubJson', function () { it('returns parameter if configPath is set', function () { diff --git a/github-actions/shared/__test__/log-helper.test.ts b/github-actions/scan/__test__/log-helper.test.ts similarity index 100% rename from github-actions/shared/__test__/log-helper.test.ts rename to github-actions/scan/__test__/log-helper.test.ts diff --git a/github-actions/scan/__test__/post-scan.test.ts b/github-actions/scan/__test__/post-scan.test.ts index bdef9fe7e9..fba381a087 100644 --- a/github-actions/scan/__test__/post-scan.test.ts +++ b/github-actions/scan/__test__/post-scan.test.ts @@ -2,12 +2,12 @@ import * as core from '@actions/core'; import { downloadReports, reportOutputs } from '../src/post-scan'; -import { getReport } from '../../shared/src/sechub-cli'; +import { getReport } from '../src/sechub-cli'; jest.mock('@actions/core'); const mockedCore = core as jest.Mocked; -jest.mock('../../shared/src/sechub-cli'); +jest.mock('../src/sechub-cli'); const mockedGetReport = getReport as jest.MockedFunction; describe('downloadReports', function () { afterEach(() => { @@ -27,7 +27,7 @@ describe('downloadReports', function () { const sampleJson = {'test': 'test'}; const actualJson = downloadReports(formats); - expect(mockedCore.info).toHaveBeenCalledTimes(2); // Assumes 3 formats, adjust based on the number of formats in the array + expect(mockedCore.info).toHaveBeenCalledTimes(4); // Assumes 3 formats, adjust based on the number of formats in the array expect(mockedGetReport).toHaveBeenCalledTimes(2); expect(actualJson).toEqual(sampleJson); }); diff --git a/github-actions/shared/__test__/report-format.test.ts b/github-actions/scan/__test__/report-format.test.ts similarity index 100% rename from github-actions/shared/__test__/report-format.test.ts rename to github-actions/scan/__test__/report-format.test.ts diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index f437ad0e60..bc161a14c5 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -2750,7 +2750,7 @@ class OidcClient { .catch(error => { throw new Error(`Failed to get ID Token. \n Error Code : ${error.statusCode}\n - Error Message: ${error.result.message}`); + Error Message: ${error.message}`); }); const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; if (!id_token) { @@ -3312,7 +3312,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; const http = __importStar(__nccwpck_require__(3685)); const https = __importStar(__nccwpck_require__(5687)); -const pm = __importStar(__nccwpck_require__(1846)); +const pm = __importStar(__nccwpck_require__(9835)); const tunnel = __importStar(__nccwpck_require__(4294)); var HttpCodes; (function (HttpCodes) { @@ -3886,7 +3886,7 @@ const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCa /***/ }), -/***/ 1846: +/***/ 9835: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -13388,10010 +13388,27 @@ function wrappy (fn, cb) { /***/ }), -/***/ 3013: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { +/***/ 9491: +/***/ ((module) => { "use strict"; +module.exports = require("assert"); -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.issue = exports.issueCommand = void 0; -const os = __importStar(__nccwpck_require__(2037)); -const utils_1 = __nccwpck_require__(5125); -/** - * Commands - * - * Command Format: - * ::name key=value,key=value::message - * - * Examples: - * ::warning::This is the message - * ::set-env name=MY_VAR::some value - */ -function issueCommand(command, properties, message) { - const cmd = new Command(command, properties, message); - process.stdout.write(cmd.toString() + os.EOL); -} -exports.issueCommand = issueCommand; -function issue(name, message = '') { - issueCommand(name, {}, message); -} -exports.issue = issue; -const CMD_STRING = '::'; -class Command { - constructor(command, properties, message) { - if (!command) { - command = 'missing.command'; - } - this.command = command; - this.properties = properties; - this.message = message; - } - toString() { - let cmdStr = CMD_STRING + this.command; - if (this.properties && Object.keys(this.properties).length > 0) { - cmdStr += ' '; - let first = true; - for (const key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - const val = this.properties[key]; - if (val) { - if (first) { - first = false; - } - else { - cmdStr += ','; - } - cmdStr += `${key}=${escapeProperty(val)}`; - } - } - } - } - cmdStr += `${CMD_STRING}${escapeData(this.message)}`; - return cmdStr; - } -} -function escapeData(s) { - return utils_1.toCommandValue(s) - .replace(/%/g, '%25') - .replace(/\r/g, '%0D') - .replace(/\n/g, '%0A'); -} -function escapeProperty(s) { - return utils_1.toCommandValue(s) - .replace(/%/g, '%25') - .replace(/\r/g, '%0D') - .replace(/\n/g, '%0A') - .replace(/:/g, '%3A') - .replace(/,/g, '%2C'); -} -//# sourceMappingURL=command.js.map +/***/ }), + +/***/ 2081: +/***/ ((module) => { + +"use strict"; +module.exports = require("child_process"); /***/ }), -/***/ 3471: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { +/***/ 6113: +/***/ ((module) => { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; -const command_1 = __nccwpck_require__(3013); -const file_command_1 = __nccwpck_require__(2246); -const utils_1 = __nccwpck_require__(5125); -const os = __importStar(__nccwpck_require__(2037)); -const path = __importStar(__nccwpck_require__(1017)); -const oidc_utils_1 = __nccwpck_require__(2847); -/** - * The code to exit an action - */ -var ExitCode; -(function (ExitCode) { - /** - * A code indicating that the action was successful - */ - ExitCode[ExitCode["Success"] = 0] = "Success"; - /** - * A code indicating that the action was a failure - */ - ExitCode[ExitCode["Failure"] = 1] = "Failure"; -})(ExitCode = exports.ExitCode || (exports.ExitCode = {})); -//----------------------------------------------------------------------- -// Variables -//----------------------------------------------------------------------- -/** - * Sets env variable for this action and future actions in the job - * @param name the name of the variable to set - * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function exportVariable(name, val) { - const convertedVal = utils_1.toCommandValue(val); - process.env[name] = convertedVal; - const filePath = process.env['GITHUB_ENV'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val)); - } - command_1.issueCommand('set-env', { name }, convertedVal); -} -exports.exportVariable = exportVariable; -/** - * Registers a secret which will get masked from logs - * @param secret value of the secret - */ -function setSecret(secret) { - command_1.issueCommand('add-mask', {}, secret); -} -exports.setSecret = setSecret; -/** - * Prepends inputPath to the PATH (for this action and future actions) - * @param inputPath - */ -function addPath(inputPath) { - const filePath = process.env['GITHUB_PATH'] || ''; - if (filePath) { - file_command_1.issueFileCommand('PATH', inputPath); - } - else { - command_1.issueCommand('add-path', {}, inputPath); - } - process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; -} -exports.addPath = addPath; -/** - * Gets the value of an input. - * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. - * Returns an empty string if the value is not defined. - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns string - */ -function getInput(name, options) { - const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; - if (options && options.required && !val) { - throw new Error(`Input required and not supplied: ${name}`); - } - if (options && options.trimWhitespace === false) { - return val; - } - return val.trim(); -} -exports.getInput = getInput; -/** - * Gets the values of an multiline input. Each value is also trimmed. - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns string[] - * - */ -function getMultilineInput(name, options) { - const inputs = getInput(name, options) - .split('\n') - .filter(x => x !== ''); - if (options && options.trimWhitespace === false) { - return inputs; - } - return inputs.map(input => input.trim()); -} -exports.getMultilineInput = getMultilineInput; -/** - * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. - * Support boolean input list: `true | True | TRUE | false | False | FALSE` . - * The return value is also in boolean type. - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns boolean - */ -function getBooleanInput(name, options) { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - const val = getInput(name, options); - if (trueValue.includes(val)) - return true; - if (falseValue.includes(val)) - return false; - throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + - `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); -} -exports.getBooleanInput = getBooleanInput; -/** - * Sets the value of an output. - * - * @param name name of the output to set - * @param value value to store. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function setOutput(name, value) { - const filePath = process.env['GITHUB_OUTPUT'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value)); - } - process.stdout.write(os.EOL); - command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value)); -} -exports.setOutput = setOutput; -/** - * Enables or disables the echoing of commands into stdout for the rest of the step. - * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. - * - */ -function setCommandEcho(enabled) { - command_1.issue('echo', enabled ? 'on' : 'off'); -} -exports.setCommandEcho = setCommandEcho; -//----------------------------------------------------------------------- -// Results -//----------------------------------------------------------------------- -/** - * Sets the action status to failed. - * When the action exits it will be with an exit code of 1 - * @param message add error issue message - */ -function setFailed(message) { - process.exitCode = ExitCode.Failure; - error(message); -} -exports.setFailed = setFailed; -//----------------------------------------------------------------------- -// Logging Commands -//----------------------------------------------------------------------- -/** - * Gets whether Actions Step Debug is on or not - */ -function isDebug() { - return process.env['RUNNER_DEBUG'] === '1'; -} -exports.isDebug = isDebug; -/** - * Writes debug message to user log - * @param message debug message - */ -function debug(message) { - command_1.issueCommand('debug', {}, message); -} -exports.debug = debug; -/** - * Adds an error issue - * @param message error issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function error(message, properties = {}) { - command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.error = error; -/** - * Adds a warning issue - * @param message warning issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function warning(message, properties = {}) { - command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.warning = warning; -/** - * Adds a notice issue - * @param message notice issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function notice(message, properties = {}) { - command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.notice = notice; -/** - * Writes info to log with console.log. - * @param message info message - */ -function info(message) { - process.stdout.write(message + os.EOL); -} -exports.info = info; -/** - * Begin an output group. - * - * Output until the next `groupEnd` will be foldable in this group - * - * @param name The name of the output group - */ -function startGroup(name) { - command_1.issue('group', name); -} -exports.startGroup = startGroup; -/** - * End an output group. - */ -function endGroup() { - command_1.issue('endgroup'); -} -exports.endGroup = endGroup; -/** - * Wrap an asynchronous function call in a group. - * - * Returns the same type as the function itself. - * - * @param name The name of the group - * @param fn The function to wrap in the group - */ -function group(name, fn) { - return __awaiter(this, void 0, void 0, function* () { - startGroup(name); - let result; - try { - result = yield fn(); - } - finally { - endGroup(); - } - return result; - }); -} -exports.group = group; -//----------------------------------------------------------------------- -// Wrapper action state -//----------------------------------------------------------------------- -/** - * Saves state for current action, the state can only be retrieved by this action's post job execution. - * - * @param name name of the state to store - * @param value value to store. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function saveState(name, value) { - const filePath = process.env['GITHUB_STATE'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value)); - } - command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value)); -} -exports.saveState = saveState; -/** - * Gets the value of an state set by this action's main execution. - * - * @param name name of the state to get - * @returns string - */ -function getState(name) { - return process.env[`STATE_${name}`] || ''; -} -exports.getState = getState; -function getIDToken(aud) { - return __awaiter(this, void 0, void 0, function* () { - return yield oidc_utils_1.OidcClient.getIDToken(aud); - }); -} -exports.getIDToken = getIDToken; -/** - * Summary exports - */ -var summary_1 = __nccwpck_require__(456); -Object.defineProperty(exports, "summary", ({ enumerable: true, get: function () { return summary_1.summary; } })); -/** - * @deprecated use core.summary - */ -var summary_2 = __nccwpck_require__(456); -Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return summary_2.markdownSummary; } })); -/** - * Path exports - */ -var path_utils_1 = __nccwpck_require__(7761); -Object.defineProperty(exports, "toPosixPath", ({ enumerable: true, get: function () { return path_utils_1.toPosixPath; } })); -Object.defineProperty(exports, "toWin32Path", ({ enumerable: true, get: function () { return path_utils_1.toWin32Path; } })); -Object.defineProperty(exports, "toPlatformPath", ({ enumerable: true, get: function () { return path_utils_1.toPlatformPath; } })); -//# sourceMappingURL=core.js.map - -/***/ }), - -/***/ 2246: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -// For internal use, subject to change. -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.prepareKeyValueMessage = exports.issueFileCommand = void 0; -// We use any as a valid input type -/* eslint-disable @typescript-eslint/no-explicit-any */ -const fs = __importStar(__nccwpck_require__(7147)); -const os = __importStar(__nccwpck_require__(2037)); -const uuid_1 = __nccwpck_require__(8077); -const utils_1 = __nccwpck_require__(5125); -function issueFileCommand(command, message) { - const filePath = process.env[`GITHUB_${command}`]; - if (!filePath) { - throw new Error(`Unable to find environment variable for file command ${command}`); - } - if (!fs.existsSync(filePath)) { - throw new Error(`Missing file at path: ${filePath}`); - } - fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { - encoding: 'utf8' - }); -} -exports.issueFileCommand = issueFileCommand; -function prepareKeyValueMessage(key, value) { - const delimiter = `ghadelimiter_${uuid_1.v4()}`; - const convertedValue = utils_1.toCommandValue(value); - // These should realistically never happen, but just in case someone finds a - // way to exploit uuid generation let's not allow keys or values that contain - // the delimiter. - if (key.includes(delimiter)) { - throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`); - } - if (convertedValue.includes(delimiter)) { - throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`); - } - return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`; -} -exports.prepareKeyValueMessage = prepareKeyValueMessage; -//# sourceMappingURL=file-command.js.map - -/***/ }), - -/***/ 2847: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.OidcClient = void 0; -const http_client_1 = __nccwpck_require__(1779); -const auth_1 = __nccwpck_require__(6133); -const core_1 = __nccwpck_require__(3471); -class OidcClient { - static createHttpClient(allowRetry = true, maxRetry = 10) { - const requestOptions = { - allowRetries: allowRetry, - maxRetries: maxRetry - }; - return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions); - } - static getRequestToken() { - const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']; - if (!token) { - throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'); - } - return token; - } - static getIDTokenUrl() { - const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']; - if (!runtimeUrl) { - throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'); - } - return runtimeUrl; - } - static getCall(id_token_url) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const httpclient = OidcClient.createHttpClient(); - const res = yield httpclient - .getJson(id_token_url) - .catch(error => { - throw new Error(`Failed to get ID Token. \n - Error Code : ${error.statusCode}\n - Error Message: ${error.result.message}`); - }); - const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; - if (!id_token) { - throw new Error('Response json body do not have ID Token field'); - } - return id_token; - }); - } - static getIDToken(audience) { - return __awaiter(this, void 0, void 0, function* () { - try { - // New ID Token is requested from action service - let id_token_url = OidcClient.getIDTokenUrl(); - if (audience) { - const encodedAudience = encodeURIComponent(audience); - id_token_url = `${id_token_url}&audience=${encodedAudience}`; - } - core_1.debug(`ID token url is ${id_token_url}`); - const id_token = yield OidcClient.getCall(id_token_url); - core_1.setSecret(id_token); - return id_token; - } - catch (error) { - throw new Error(`Error message: ${error.message}`); - } - }); - } -} -exports.OidcClient = OidcClient; -//# sourceMappingURL=oidc-utils.js.map - -/***/ }), - -/***/ 7761: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0; -const path = __importStar(__nccwpck_require__(1017)); -/** - * toPosixPath converts the given path to the posix form. On Windows, \\ will be - * replaced with /. - * - * @param pth. Path to transform. - * @return string Posix path. - */ -function toPosixPath(pth) { - return pth.replace(/[\\]/g, '/'); -} -exports.toPosixPath = toPosixPath; -/** - * toWin32Path converts the given path to the win32 form. On Linux, / will be - * replaced with \\. - * - * @param pth. Path to transform. - * @return string Win32 path. - */ -function toWin32Path(pth) { - return pth.replace(/[/]/g, '\\'); -} -exports.toWin32Path = toWin32Path; -/** - * toPlatformPath converts the given path to a platform-specific path. It does - * this by replacing instances of / and \ with the platform-specific path - * separator. - * - * @param pth The path to platformize. - * @return string The platform-specific path. - */ -function toPlatformPath(pth) { - return pth.replace(/[/\\]/g, path.sep); -} -exports.toPlatformPath = toPlatformPath; -//# sourceMappingURL=path-utils.js.map - -/***/ }), - -/***/ 456: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.summary = exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0; -const os_1 = __nccwpck_require__(2037); -const fs_1 = __nccwpck_require__(7147); -const { access, appendFile, writeFile } = fs_1.promises; -exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'; -exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary'; -class Summary { - constructor() { - this._buffer = ''; - } - /** - * Finds the summary file path from the environment, rejects if env var is not found or file does not exist - * Also checks r/w permissions. - * - * @returns step summary file path - */ - filePath() { - return __awaiter(this, void 0, void 0, function* () { - if (this._filePath) { - return this._filePath; - } - const pathFromEnv = process.env[exports.SUMMARY_ENV_VAR]; - if (!pathFromEnv) { - throw new Error(`Unable to find environment variable for $${exports.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`); - } - try { - yield access(pathFromEnv, fs_1.constants.R_OK | fs_1.constants.W_OK); - } - catch (_a) { - throw new Error(`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`); - } - this._filePath = pathFromEnv; - return this._filePath; - }); - } - /** - * Wraps content in an HTML tag, adding any HTML attributes - * - * @param {string} tag HTML tag to wrap - * @param {string | null} content content within the tag - * @param {[attribute: string]: string} attrs key-value list of HTML attributes to add - * - * @returns {string} content wrapped in HTML element - */ - wrap(tag, content, attrs = {}) { - const htmlAttrs = Object.entries(attrs) - .map(([key, value]) => ` ${key}="${value}"`) - .join(''); - if (!content) { - return `<${tag}${htmlAttrs}>`; - } - return `<${tag}${htmlAttrs}>${content}`; - } - /** - * Writes text in the buffer to the summary buffer file and empties buffer. Will append by default. - * - * @param {SummaryWriteOptions} [options] (optional) options for write operation - * - * @returns {Promise} summary instance - */ - write(options) { - return __awaiter(this, void 0, void 0, function* () { - const overwrite = !!(options === null || options === void 0 ? void 0 : options.overwrite); - const filePath = yield this.filePath(); - const writeFunc = overwrite ? writeFile : appendFile; - yield writeFunc(filePath, this._buffer, { encoding: 'utf8' }); - return this.emptyBuffer(); - }); - } - /** - * Clears the summary buffer and wipes the summary file - * - * @returns {Summary} summary instance - */ - clear() { - return __awaiter(this, void 0, void 0, function* () { - return this.emptyBuffer().write({ overwrite: true }); - }); - } - /** - * Returns the current summary buffer as a string - * - * @returns {string} string of summary buffer - */ - stringify() { - return this._buffer; - } - /** - * If the summary buffer is empty - * - * @returns {boolen} true if the buffer is empty - */ - isEmptyBuffer() { - return this._buffer.length === 0; - } - /** - * Resets the summary buffer without writing to summary file - * - * @returns {Summary} summary instance - */ - emptyBuffer() { - this._buffer = ''; - return this; - } - /** - * Adds raw text to the summary buffer - * - * @param {string} text content to add - * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false) - * - * @returns {Summary} summary instance - */ - addRaw(text, addEOL = false) { - this._buffer += text; - return addEOL ? this.addEOL() : this; - } - /** - * Adds the operating system-specific end-of-line marker to the buffer - * - * @returns {Summary} summary instance - */ - addEOL() { - return this.addRaw(os_1.EOL); - } - /** - * Adds an HTML codeblock to the summary buffer - * - * @param {string} code content to render within fenced code block - * @param {string} lang (optional) language to syntax highlight code - * - * @returns {Summary} summary instance - */ - addCodeBlock(code, lang) { - const attrs = Object.assign({}, (lang && { lang })); - const element = this.wrap('pre', this.wrap('code', code), attrs); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML list to the summary buffer - * - * @param {string[]} items list of items to render - * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false) - * - * @returns {Summary} summary instance - */ - addList(items, ordered = false) { - const tag = ordered ? 'ol' : 'ul'; - const listItems = items.map(item => this.wrap('li', item)).join(''); - const element = this.wrap(tag, listItems); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML table to the summary buffer - * - * @param {SummaryTableCell[]} rows table rows - * - * @returns {Summary} summary instance - */ - addTable(rows) { - const tableBody = rows - .map(row => { - const cells = row - .map(cell => { - if (typeof cell === 'string') { - return this.wrap('td', cell); - } - const { header, data, colspan, rowspan } = cell; - const tag = header ? 'th' : 'td'; - const attrs = Object.assign(Object.assign({}, (colspan && { colspan })), (rowspan && { rowspan })); - return this.wrap(tag, data, attrs); - }) - .join(''); - return this.wrap('tr', cells); - }) - .join(''); - const element = this.wrap('table', tableBody); - return this.addRaw(element).addEOL(); - } - /** - * Adds a collapsable HTML details element to the summary buffer - * - * @param {string} label text for the closed state - * @param {string} content collapsable content - * - * @returns {Summary} summary instance - */ - addDetails(label, content) { - const element = this.wrap('details', this.wrap('summary', label) + content); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML image tag to the summary buffer - * - * @param {string} src path to the image you to embed - * @param {string} alt text description of the image - * @param {SummaryImageOptions} options (optional) addition image attributes - * - * @returns {Summary} summary instance - */ - addImage(src, alt, options) { - const { width, height } = options || {}; - const attrs = Object.assign(Object.assign({}, (width && { width })), (height && { height })); - const element = this.wrap('img', null, Object.assign({ src, alt }, attrs)); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML section heading element - * - * @param {string} text heading text - * @param {number | string} [level=1] (optional) the heading level, default: 1 - * - * @returns {Summary} summary instance - */ - addHeading(text, level) { - const tag = `h${level}`; - const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag) - ? tag - : 'h1'; - const element = this.wrap(allowedTag, text); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML thematic break (
) to the summary buffer - * - * @returns {Summary} summary instance - */ - addSeparator() { - const element = this.wrap('hr', null); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML line break (
) to the summary buffer - * - * @returns {Summary} summary instance - */ - addBreak() { - const element = this.wrap('br', null); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML blockquote to the summary buffer - * - * @param {string} text quote text - * @param {string} cite (optional) citation url - * - * @returns {Summary} summary instance - */ - addQuote(text, cite) { - const attrs = Object.assign({}, (cite && { cite })); - const element = this.wrap('blockquote', text, attrs); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML anchor tag to the summary buffer - * - * @param {string} text link text/content - * @param {string} href hyperlink - * - * @returns {Summary} summary instance - */ - addLink(text, href) { - const element = this.wrap('a', text, { href }); - return this.addRaw(element).addEOL(); - } -} -const _summary = new Summary(); -/** - * @deprecated use `core.summary` - */ -exports.markdownSummary = _summary; -exports.summary = _summary; -//# sourceMappingURL=summary.js.map - -/***/ }), - -/***/ 5125: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -// We use any as a valid input type -/* eslint-disable @typescript-eslint/no-explicit-any */ -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.toCommandProperties = exports.toCommandValue = void 0; -/** - * Sanitizes an input into a string so it can be passed into issueCommand safely - * @param input input to sanitize into a string - */ -function toCommandValue(input) { - if (input === null || input === undefined) { - return ''; - } - else if (typeof input === 'string' || input instanceof String) { - return input; - } - return JSON.stringify(input); -} -exports.toCommandValue = toCommandValue; -/** - * - * @param annotationProperties - * @returns The command properties to send with the actual annotation command - * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646 - */ -function toCommandProperties(annotationProperties) { - if (!Object.keys(annotationProperties).length) { - return {}; - } - return { - title: annotationProperties.title, - file: annotationProperties.file, - line: annotationProperties.startLine, - endLine: annotationProperties.endLine, - col: annotationProperties.startColumn, - endColumn: annotationProperties.endColumn - }; -} -exports.toCommandProperties = toCommandProperties; -//# sourceMappingURL=utils.js.map - -/***/ }), - -/***/ 6133: -/***/ (function(__unused_webpack_module, exports) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0; -class BasicCredentialHandler { - constructor(username, password) { - this.username = username; - this.password = password; - } - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.BasicCredentialHandler = BasicCredentialHandler; -class BearerCredentialHandler { - constructor(token) { - this.token = token; - } - // currently implements pre-authorization - // TODO: support preAuth = false where it hooks on 401 - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Bearer ${this.token}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.BearerCredentialHandler = BearerCredentialHandler; -class PersonalAccessTokenCredentialHandler { - constructor(token) { - this.token = token; - } - // currently implements pre-authorization - // TODO: support preAuth = false where it hooks on 401 - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; -//# sourceMappingURL=auth.js.map - -/***/ }), - -/***/ 1779: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -/* eslint-disable @typescript-eslint/no-explicit-any */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; -const http = __importStar(__nccwpck_require__(3685)); -const https = __importStar(__nccwpck_require__(5687)); -const pm = __importStar(__nccwpck_require__(8093)); -const tunnel = __importStar(__nccwpck_require__(2986)); -var HttpCodes; -(function (HttpCodes) { - HttpCodes[HttpCodes["OK"] = 200] = "OK"; - HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; - HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; - HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; - HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; - HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; - HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; - HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; - HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; - HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; - HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; - HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; - HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; - HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; - HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; - HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; - HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; - HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; - HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; - HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; - HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; - HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; - HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; - HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; - HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; - HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; - HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; -})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {})); -var Headers; -(function (Headers) { - Headers["Accept"] = "accept"; - Headers["ContentType"] = "content-type"; -})(Headers = exports.Headers || (exports.Headers = {})); -var MediaTypes; -(function (MediaTypes) { - MediaTypes["ApplicationJson"] = "application/json"; -})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {})); -/** - * Returns the proxy URL, depending upon the supplied url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ -function getProxyUrl(serverUrl) { - const proxyUrl = pm.getProxyUrl(new URL(serverUrl)); - return proxyUrl ? proxyUrl.href : ''; -} -exports.getProxyUrl = getProxyUrl; -const HttpRedirectCodes = [ - HttpCodes.MovedPermanently, - HttpCodes.ResourceMoved, - HttpCodes.SeeOther, - HttpCodes.TemporaryRedirect, - HttpCodes.PermanentRedirect -]; -const HttpResponseRetryCodes = [ - HttpCodes.BadGateway, - HttpCodes.ServiceUnavailable, - HttpCodes.GatewayTimeout -]; -const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; -const ExponentialBackoffCeiling = 10; -const ExponentialBackoffTimeSlice = 5; -class HttpClientError extends Error { - constructor(message, statusCode) { - super(message); - this.name = 'HttpClientError'; - this.statusCode = statusCode; - Object.setPrototypeOf(this, HttpClientError.prototype); - } -} -exports.HttpClientError = HttpClientError; -class HttpClientResponse { - constructor(message) { - this.message = message; - } - readBody() { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { - let output = Buffer.alloc(0); - this.message.on('data', (chunk) => { - output = Buffer.concat([output, chunk]); - }); - this.message.on('end', () => { - resolve(output.toString()); - }); - })); - }); - } -} -exports.HttpClientResponse = HttpClientResponse; -function isHttps(requestUrl) { - const parsedUrl = new URL(requestUrl); - return parsedUrl.protocol === 'https:'; -} -exports.isHttps = isHttps; -class HttpClient { - constructor(userAgent, handlers, requestOptions) { - this._ignoreSslError = false; - this._allowRedirects = true; - this._allowRedirectDowngrade = false; - this._maxRedirects = 50; - this._allowRetries = false; - this._maxRetries = 1; - this._keepAlive = false; - this._disposed = false; - this.userAgent = userAgent; - this.handlers = handlers || []; - this.requestOptions = requestOptions; - if (requestOptions) { - if (requestOptions.ignoreSslError != null) { - this._ignoreSslError = requestOptions.ignoreSslError; - } - this._socketTimeout = requestOptions.socketTimeout; - if (requestOptions.allowRedirects != null) { - this._allowRedirects = requestOptions.allowRedirects; - } - if (requestOptions.allowRedirectDowngrade != null) { - this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; - } - if (requestOptions.maxRedirects != null) { - this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); - } - if (requestOptions.keepAlive != null) { - this._keepAlive = requestOptions.keepAlive; - } - if (requestOptions.allowRetries != null) { - this._allowRetries = requestOptions.allowRetries; - } - if (requestOptions.maxRetries != null) { - this._maxRetries = requestOptions.maxRetries; - } - } - } - options(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); - }); - } - get(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('GET', requestUrl, null, additionalHeaders || {}); - }); - } - del(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('DELETE', requestUrl, null, additionalHeaders || {}); - }); - } - post(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('POST', requestUrl, data, additionalHeaders || {}); - }); - } - patch(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PATCH', requestUrl, data, additionalHeaders || {}); - }); - } - put(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PUT', requestUrl, data, additionalHeaders || {}); - }); - } - head(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('HEAD', requestUrl, null, additionalHeaders || {}); - }); - } - sendStream(verb, requestUrl, stream, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request(verb, requestUrl, stream, additionalHeaders); - }); - } - /** - * Gets a typed object from an endpoint - * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise - */ - getJson(requestUrl, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - const res = yield this.get(requestUrl, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - postJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.post(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - putJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.put(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - patchJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.patch(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - /** - * Makes a raw http request. - * All other methods such as get, post, patch, and request ultimately call this. - * Prefer get, del, post and patch - */ - request(verb, requestUrl, data, headers) { - return __awaiter(this, void 0, void 0, function* () { - if (this._disposed) { - throw new Error('Client has already been disposed.'); - } - const parsedUrl = new URL(requestUrl); - let info = this._prepareRequest(verb, parsedUrl, headers); - // Only perform retries on reads since writes may not be idempotent. - const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) - ? this._maxRetries + 1 - : 1; - let numTries = 0; - let response; - do { - response = yield this.requestRaw(info, data); - // Check if it's an authentication challenge - if (response && - response.message && - response.message.statusCode === HttpCodes.Unauthorized) { - let authenticationHandler; - for (const handler of this.handlers) { - if (handler.canHandleAuthentication(response)) { - authenticationHandler = handler; - break; - } - } - if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info, data); - } - else { - // We have received an unauthorized response but have no handlers to handle it. - // Let the response return to the caller. - return response; - } - } - let redirectsRemaining = this._maxRedirects; - while (response.message.statusCode && - HttpRedirectCodes.includes(response.message.statusCode) && - this._allowRedirects && - redirectsRemaining > 0) { - const redirectUrl = response.message.headers['location']; - if (!redirectUrl) { - // if there's no location to redirect to, we won't - break; - } - const parsedRedirectUrl = new URL(redirectUrl); - if (parsedUrl.protocol === 'https:' && - parsedUrl.protocol !== parsedRedirectUrl.protocol && - !this._allowRedirectDowngrade) { - throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); - } - // we need to finish reading the response before reassigning response - // which will leak the open socket. - yield response.readBody(); - // strip authorization header if redirected to a different hostname - if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { - for (const header in headers) { - // header names are case insensitive - if (header.toLowerCase() === 'authorization') { - delete headers[header]; - } - } - } - // let's make the request with the new redirectUrl - info = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info, data); - redirectsRemaining--; - } - if (!response.message.statusCode || - !HttpResponseRetryCodes.includes(response.message.statusCode)) { - // If not a retry code, return immediately instead of retrying - return response; - } - numTries += 1; - if (numTries < maxTries) { - yield response.readBody(); - yield this._performExponentialBackoff(numTries); - } - } while (numTries < maxTries); - return response; - }); - } - /** - * Needs to be called if keepAlive is set to true in request options. - */ - dispose() { - if (this._agent) { - this._agent.destroy(); - } - this._disposed = true; - } - /** - * Raw request. - * @param info - * @param data - */ - requestRaw(info, data) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - function callbackForResult(err, res) { - if (err) { - reject(err); - } - else if (!res) { - // If `err` is not passed, then `res` must be passed. - reject(new Error('Unknown error')); - } - else { - resolve(res); - } - } - this.requestRawWithCallback(info, data, callbackForResult); - }); - }); - } - /** - * Raw request with callback. - * @param info - * @param data - * @param onResult - */ - requestRawWithCallback(info, data, onResult) { - if (typeof data === 'string') { - if (!info.options.headers) { - info.options.headers = {}; - } - info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); - } - let callbackCalled = false; - function handleResult(err, res) { - if (!callbackCalled) { - callbackCalled = true; - onResult(err, res); - } - } - const req = info.httpModule.request(info.options, (msg) => { - const res = new HttpClientResponse(msg); - handleResult(undefined, res); - }); - let socket; - req.on('socket', sock => { - socket = sock; - }); - // If we ever get disconnected, we want the socket to timeout eventually - req.setTimeout(this._socketTimeout || 3 * 60000, () => { - if (socket) { - socket.end(); - } - handleResult(new Error(`Request timeout: ${info.options.path}`)); - }); - req.on('error', function (err) { - // err has statusCode property - // res should have headers - handleResult(err); - }); - if (data && typeof data === 'string') { - req.write(data, 'utf8'); - } - if (data && typeof data !== 'string') { - data.on('close', function () { - req.end(); - }); - data.pipe(req); - } - else { - req.end(); - } - } - /** - * Gets an http agent. This function is useful when you need an http agent that handles - * routing through a proxy server - depending upon the url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ - getAgent(serverUrl) { - const parsedUrl = new URL(serverUrl); - return this._getAgent(parsedUrl); - } - _prepareRequest(method, requestUrl, headers) { - const info = {}; - info.parsedUrl = requestUrl; - const usingSsl = info.parsedUrl.protocol === 'https:'; - info.httpModule = usingSsl ? https : http; - const defaultPort = usingSsl ? 443 : 80; - info.options = {}; - info.options.host = info.parsedUrl.hostname; - info.options.port = info.parsedUrl.port - ? parseInt(info.parsedUrl.port) - : defaultPort; - info.options.path = - (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); - info.options.method = method; - info.options.headers = this._mergeHeaders(headers); - if (this.userAgent != null) { - info.options.headers['user-agent'] = this.userAgent; - } - info.options.agent = this._getAgent(info.parsedUrl); - // gives handlers an opportunity to participate - if (this.handlers) { - for (const handler of this.handlers) { - handler.prepareRequest(info.options); - } - } - return info; - } - _mergeHeaders(headers) { - if (this.requestOptions && this.requestOptions.headers) { - return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {})); - } - return lowercaseKeys(headers || {}); - } - _getExistingOrDefaultHeader(additionalHeaders, header, _default) { - let clientHeader; - if (this.requestOptions && this.requestOptions.headers) { - clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; - } - return additionalHeaders[header] || clientHeader || _default; - } - _getAgent(parsedUrl) { - let agent; - const proxyUrl = pm.getProxyUrl(parsedUrl); - const useProxy = proxyUrl && proxyUrl.hostname; - if (this._keepAlive && useProxy) { - agent = this._proxyAgent; - } - if (this._keepAlive && !useProxy) { - agent = this._agent; - } - // if agent is already assigned use that agent. - if (agent) { - return agent; - } - const usingSsl = parsedUrl.protocol === 'https:'; - let maxSockets = 100; - if (this.requestOptions) { - maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; - } - // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. - if (proxyUrl && proxyUrl.hostname) { - const agentOptions = { - maxSockets, - keepAlive: this._keepAlive, - proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && { - proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` - })), { host: proxyUrl.hostname, port: proxyUrl.port }) - }; - let tunnelAgent; - const overHttps = proxyUrl.protocol === 'https:'; - if (usingSsl) { - tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; - } - else { - tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; - } - agent = tunnelAgent(agentOptions); - this._proxyAgent = agent; - } - // if reusing agent across request and tunneling agent isn't assigned create a new agent - if (this._keepAlive && !agent) { - const options = { keepAlive: this._keepAlive, maxSockets }; - agent = usingSsl ? new https.Agent(options) : new http.Agent(options); - this._agent = agent; - } - // if not using private agent and tunnel agent isn't setup then use global agent - if (!agent) { - agent = usingSsl ? https.globalAgent : http.globalAgent; - } - if (usingSsl && this._ignoreSslError) { - // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process - // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options - // we have to cast it to any and change it directly - agent.options = Object.assign(agent.options || {}, { - rejectUnauthorized: false - }); - } - return agent; - } - _performExponentialBackoff(retryNumber) { - return __awaiter(this, void 0, void 0, function* () { - retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); - const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); - return new Promise(resolve => setTimeout(() => resolve(), ms)); - }); - } - _processResponse(res, options) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { - const statusCode = res.message.statusCode || 0; - const response = { - statusCode, - result: null, - headers: {} - }; - // not found leads to null obj returned - if (statusCode === HttpCodes.NotFound) { - resolve(response); - } - // get the result from the body - function dateTimeDeserializer(key, value) { - if (typeof value === 'string') { - const a = new Date(value); - if (!isNaN(a.valueOf())) { - return a; - } - } - return value; - } - let obj; - let contents; - try { - contents = yield res.readBody(); - if (contents && contents.length > 0) { - if (options && options.deserializeDates) { - obj = JSON.parse(contents, dateTimeDeserializer); - } - else { - obj = JSON.parse(contents); - } - response.result = obj; - } - response.headers = res.message.headers; - } - catch (err) { - // Invalid resource (contents not json); leaving result obj null - } - // note that 3xx redirects are handled by the http layer. - if (statusCode > 299) { - let msg; - // if exception/error in body, attempt to get better error - if (obj && obj.message) { - msg = obj.message; - } - else if (contents && contents.length > 0) { - // it may be the case that the exception is in the body message as string - msg = contents; - } - else { - msg = `Failed request: (${statusCode})`; - } - const err = new HttpClientError(msg, statusCode); - err.result = response.result; - reject(err); - } - else { - resolve(response); - } - })); - }); - } -} -exports.HttpClient = HttpClient; -const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); -//# sourceMappingURL=index.js.map - -/***/ }), - -/***/ 8093: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.checkBypass = exports.getProxyUrl = void 0; -function getProxyUrl(reqUrl) { - const usingSsl = reqUrl.protocol === 'https:'; - if (checkBypass(reqUrl)) { - return undefined; - } - const proxyVar = (() => { - if (usingSsl) { - return process.env['https_proxy'] || process.env['HTTPS_PROXY']; - } - else { - return process.env['http_proxy'] || process.env['HTTP_PROXY']; - } - })(); - if (proxyVar) { - return new URL(proxyVar); - } - else { - return undefined; - } -} -exports.getProxyUrl = getProxyUrl; -function checkBypass(reqUrl) { - if (!reqUrl.hostname) { - return false; - } - const reqHost = reqUrl.hostname; - if (isLoopbackAddress(reqHost)) { - return true; - } - const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; - if (!noProxy) { - return false; - } - // Determine the request port - let reqPort; - if (reqUrl.port) { - reqPort = Number(reqUrl.port); - } - else if (reqUrl.protocol === 'http:') { - reqPort = 80; - } - else if (reqUrl.protocol === 'https:') { - reqPort = 443; - } - // Format the request hostname and hostname with port - const upperReqHosts = [reqUrl.hostname.toUpperCase()]; - if (typeof reqPort === 'number') { - upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`); - } - // Compare request host against noproxy - for (const upperNoProxyItem of noProxy - .split(',') - .map(x => x.trim().toUpperCase()) - .filter(x => x)) { - if (upperNoProxyItem === '*' || - upperReqHosts.some(x => x === upperNoProxyItem || - x.endsWith(`.${upperNoProxyItem}`) || - (upperNoProxyItem.startsWith('.') && - x.endsWith(`${upperNoProxyItem}`)))) { - return true; - } - } - return false; -} -exports.checkBypass = checkBypass; -function isLoopbackAddress(host) { - const hostLower = host.toLowerCase(); - return (hostLower === 'localhost' || - hostLower.startsWith('127.') || - hostLower.startsWith('[::1]') || - hostLower.startsWith('[0:0:0:0:0:0:0:1]')); -} -//# sourceMappingURL=proxy.js.map - -/***/ }), - -/***/ 7564: -/***/ ((module) => { - -"use strict"; - -module.exports = balanced; -function balanced(a, b, str) { - if (a instanceof RegExp) a = maybeMatch(a, str); - if (b instanceof RegExp) b = maybeMatch(b, str); - - var r = range(a, b, str); - - return r && { - start: r[0], - end: r[1], - pre: str.slice(0, r[0]), - body: str.slice(r[0] + a.length, r[1]), - post: str.slice(r[1] + b.length) - }; -} - -function maybeMatch(reg, str) { - var m = str.match(reg); - return m ? m[0] : null; -} - -balanced.range = range; -function range(a, b, str) { - var begs, beg, left, right, result; - var ai = str.indexOf(a); - var bi = str.indexOf(b, ai + 1); - var i = ai; - - if (ai >= 0 && bi > 0) { - if(a===b) { - return [ai, bi]; - } - begs = []; - left = str.length; - - while (i >= 0 && !result) { - if (i == ai) { - begs.push(i); - ai = str.indexOf(a, i + 1); - } else if (begs.length == 1) { - result = [ begs.pop(), bi ]; - } else { - beg = begs.pop(); - if (beg < left) { - left = beg; - right = bi; - } - - bi = str.indexOf(b, i + 1); - } - - i = ai < bi && ai >= 0 ? ai : bi; - } - - if (begs.length) { - result = [ left, right ]; - } - } - - return result; -} - - -/***/ }), - -/***/ 4642: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var concatMap = __nccwpck_require__(4872); -var balanced = __nccwpck_require__(7564); - -module.exports = expandTop; - -var escSlash = '\0SLASH'+Math.random()+'\0'; -var escOpen = '\0OPEN'+Math.random()+'\0'; -var escClose = '\0CLOSE'+Math.random()+'\0'; -var escComma = '\0COMMA'+Math.random()+'\0'; -var escPeriod = '\0PERIOD'+Math.random()+'\0'; - -function numeric(str) { - return parseInt(str, 10) == str - ? parseInt(str, 10) - : str.charCodeAt(0); -} - -function escapeBraces(str) { - return str.split('\\\\').join(escSlash) - .split('\\{').join(escOpen) - .split('\\}').join(escClose) - .split('\\,').join(escComma) - .split('\\.').join(escPeriod); -} - -function unescapeBraces(str) { - return str.split(escSlash).join('\\') - .split(escOpen).join('{') - .split(escClose).join('}') - .split(escComma).join(',') - .split(escPeriod).join('.'); -} - - -// Basically just str.split(","), but handling cases -// where we have nested braced sections, which should be -// treated as individual members, like {a,{b,c},d} -function parseCommaParts(str) { - if (!str) - return ['']; - - var parts = []; - var m = balanced('{', '}', str); - - if (!m) - return str.split(','); - - var pre = m.pre; - var body = m.body; - var post = m.post; - var p = pre.split(','); - - p[p.length-1] += '{' + body + '}'; - var postParts = parseCommaParts(post); - if (post.length) { - p[p.length-1] += postParts.shift(); - p.push.apply(p, postParts); - } - - parts.push.apply(parts, p); - - return parts; -} - -function expandTop(str) { - if (!str) - return []; - - // I don't know why Bash 4.3 does this, but it does. - // Anything starting with {} will have the first two bytes preserved - // but *only* at the top level, so {},a}b will not expand to anything, - // but a{},b}c will be expanded to [a}c,abc]. - // One could argue that this is a bug in Bash, but since the goal of - // this module is to match Bash's rules, we escape a leading {} - if (str.substr(0, 2) === '{}') { - str = '\\{\\}' + str.substr(2); - } - - return expand(escapeBraces(str), true).map(unescapeBraces); -} - -function identity(e) { - return e; -} - -function embrace(str) { - return '{' + str + '}'; -} -function isPadded(el) { - return /^-?0\d/.test(el); -} - -function lte(i, y) { - return i <= y; -} -function gte(i, y) { - return i >= y; -} - -function expand(str, isTop) { - var expansions = []; - - var m = balanced('{', '}', str); - if (!m || /\$$/.test(m.pre)) return [str]; - - var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); - var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); - var isSequence = isNumericSequence || isAlphaSequence; - var isOptions = m.body.indexOf(',') >= 0; - if (!isSequence && !isOptions) { - // {a},b} - if (m.post.match(/,.*\}/)) { - str = m.pre + '{' + m.body + escClose + m.post; - return expand(str); - } - return [str]; - } - - var n; - if (isSequence) { - n = m.body.split(/\.\./); - } else { - n = parseCommaParts(m.body); - if (n.length === 1) { - // x{{a,b}}y ==> x{a}y x{b}y - n = expand(n[0], false).map(embrace); - if (n.length === 1) { - var post = m.post.length - ? expand(m.post, false) - : ['']; - return post.map(function(p) { - return m.pre + n[0] + p; - }); - } - } - } - - // at this point, n is the parts, and we know it's not a comma set - // with a single entry. - - // no need to expand pre, since it is guaranteed to be free of brace-sets - var pre = m.pre; - var post = m.post.length - ? expand(m.post, false) - : ['']; - - var N; - - if (isSequence) { - var x = numeric(n[0]); - var y = numeric(n[1]); - var width = Math.max(n[0].length, n[1].length) - var incr = n.length == 3 - ? Math.abs(numeric(n[2])) - : 1; - var test = lte; - var reverse = y < x; - if (reverse) { - incr *= -1; - test = gte; - } - var pad = n.some(isPadded); - - N = []; - - for (var i = x; test(i, y); i += incr) { - var c; - if (isAlphaSequence) { - c = String.fromCharCode(i); - if (c === '\\') - c = ''; - } else { - c = String(i); - if (pad) { - var need = width - c.length; - if (need > 0) { - var z = new Array(need + 1).join('0'); - if (i < 0) - c = '-' + z + c.slice(1); - else - c = z + c; - } - } - } - N.push(c); - } - } else { - N = concatMap(n, function(el) { return expand(el, false) }); - } - - for (var j = 0; j < N.length; j++) { - for (var k = 0; k < post.length; k++) { - var expansion = pre + N[j] + post[k]; - if (!isTop || isSequence || expansion) - expansions.push(expansion); - } - } - - return expansions; -} - - - -/***/ }), - -/***/ 4872: -/***/ ((module) => { - -module.exports = function (xs, fn) { - var res = []; - for (var i = 0; i < xs.length; i++) { - var x = fn(xs[i], i); - if (isArray(x)) res.push.apply(res, x); - else res.push(x); - } - return res; -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - - -/***/ }), - -/***/ 6835: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -module.exports = realpath -realpath.realpath = realpath -realpath.sync = realpathSync -realpath.realpathSync = realpathSync -realpath.monkeypatch = monkeypatch -realpath.unmonkeypatch = unmonkeypatch - -var fs = __nccwpck_require__(7147) -var origRealpath = fs.realpath -var origRealpathSync = fs.realpathSync - -var version = process.version -var ok = /^v[0-5]\./.test(version) -var old = __nccwpck_require__(526) - -function newError (er) { - return er && er.syscall === 'realpath' && ( - er.code === 'ELOOP' || - er.code === 'ENOMEM' || - er.code === 'ENAMETOOLONG' - ) -} - -function realpath (p, cache, cb) { - if (ok) { - return origRealpath(p, cache, cb) - } - - if (typeof cache === 'function') { - cb = cache - cache = null - } - origRealpath(p, cache, function (er, result) { - if (newError(er)) { - old.realpath(p, cache, cb) - } else { - cb(er, result) - } - }) -} - -function realpathSync (p, cache) { - if (ok) { - return origRealpathSync(p, cache) - } - - try { - return origRealpathSync(p, cache) - } catch (er) { - if (newError(er)) { - return old.realpathSync(p, cache) - } else { - throw er - } - } -} - -function monkeypatch () { - fs.realpath = realpath - fs.realpathSync = realpathSync -} - -function unmonkeypatch () { - fs.realpath = origRealpath - fs.realpathSync = origRealpathSync -} - - -/***/ }), - -/***/ 526: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var pathModule = __nccwpck_require__(1017); -var isWindows = process.platform === 'win32'; -var fs = __nccwpck_require__(7147); - -// JavaScript implementation of realpath, ported from node pre-v6 - -var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); - -function rethrow() { - // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and - // is fairly slow to generate. - var callback; - if (DEBUG) { - var backtrace = new Error; - callback = debugCallback; - } else - callback = missingCallback; - - return callback; - - function debugCallback(err) { - if (err) { - backtrace.message = err.message; - err = backtrace; - missingCallback(err); - } - } - - function missingCallback(err) { - if (err) { - if (process.throwDeprecation) - throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs - else if (!process.noDeprecation) { - var msg = 'fs: missing callback ' + (err.stack || err.message); - if (process.traceDeprecation) - console.trace(msg); - else - console.error(msg); - } - } - } -} - -function maybeCallback(cb) { - return typeof cb === 'function' ? cb : rethrow(); -} - -var normalize = pathModule.normalize; - -// Regexp that finds the next partion of a (partial) path -// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] -if (isWindows) { - var nextPartRe = /(.*?)(?:[\/\\]+|$)/g; -} else { - var nextPartRe = /(.*?)(?:[\/]+|$)/g; -} - -// Regex to find the device root, including trailing slash. E.g. 'c:\\'. -if (isWindows) { - var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/; -} else { - var splitRootRe = /^[\/]*/; -} - -exports.realpathSync = function realpathSync(p, cache) { - // make p is absolute - p = pathModule.resolve(p); - - if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { - return cache[p]; - } - - var original = p, - seenLinks = {}, - knownHard = {}; - - // current character position in p - var pos; - // the partial path so far, including a trailing slash if any - var current; - // the partial path without a trailing slash (except when pointing at a root) - var base; - // the partial path scanned in the previous round, with slash - var previous; - - start(); - - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; - - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstatSync(base); - knownHard[base] = true; - } - } - - // walk down the path, swapping out linked pathparts for their real - // values - // NB: p.length changes. - while (pos < p.length) { - // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); - previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; - - // continue if not a symlink - if (knownHard[base] || (cache && cache[base] === base)) { - continue; - } - - var resolvedLink; - if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { - // some known symbolic link. no need to stat again. - resolvedLink = cache[base]; - } else { - var stat = fs.lstatSync(base); - if (!stat.isSymbolicLink()) { - knownHard[base] = true; - if (cache) cache[base] = base; - continue; - } - - // read the link if it wasn't read before - // dev/ino always return 0 on windows, so skip the check. - var linkTarget = null; - if (!isWindows) { - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (seenLinks.hasOwnProperty(id)) { - linkTarget = seenLinks[id]; - } - } - if (linkTarget === null) { - fs.statSync(base); - linkTarget = fs.readlinkSync(base); - } - resolvedLink = pathModule.resolve(previous, linkTarget); - // track this, if given a cache. - if (cache) cache[base] = resolvedLink; - if (!isWindows) seenLinks[id] = linkTarget; - } - - // resolve the link, then start over - p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); - } - - if (cache) cache[original] = p; - - return p; -}; - - -exports.realpath = function realpath(p, cache, cb) { - if (typeof cb !== 'function') { - cb = maybeCallback(cache); - cache = null; - } - - // make p is absolute - p = pathModule.resolve(p); - - if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { - return process.nextTick(cb.bind(null, null, cache[p])); - } - - var original = p, - seenLinks = {}, - knownHard = {}; - - // current character position in p - var pos; - // the partial path so far, including a trailing slash if any - var current; - // the partial path without a trailing slash (except when pointing at a root) - var base; - // the partial path scanned in the previous round, with slash - var previous; - - start(); - - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; - - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstat(base, function(err) { - if (err) return cb(err); - knownHard[base] = true; - LOOP(); - }); - } else { - process.nextTick(LOOP); - } - } - - // walk down the path, swapping out linked pathparts for their real - // values - function LOOP() { - // stop if scanned past end of path - if (pos >= p.length) { - if (cache) cache[original] = p; - return cb(null, p); - } - - // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); - previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; - - // continue if not a symlink - if (knownHard[base] || (cache && cache[base] === base)) { - return process.nextTick(LOOP); - } - - if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { - // known symbolic link. no need to stat again. - return gotResolvedLink(cache[base]); - } - - return fs.lstat(base, gotStat); - } - - function gotStat(err, stat) { - if (err) return cb(err); - - // if not a symlink, skip to the next path part - if (!stat.isSymbolicLink()) { - knownHard[base] = true; - if (cache) cache[base] = base; - return process.nextTick(LOOP); - } - - // stat & read the link if not read before - // call gotTarget as soon as the link target is known - // dev/ino always return 0 on windows, so skip the check. - if (!isWindows) { - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (seenLinks.hasOwnProperty(id)) { - return gotTarget(null, seenLinks[id], base); - } - } - fs.stat(base, function(err) { - if (err) return cb(err); - - fs.readlink(base, function(err, target) { - if (!isWindows) seenLinks[id] = target; - gotTarget(err, target); - }); - }); - } - - function gotTarget(err, target, base) { - if (err) return cb(err); - - var resolvedLink = pathModule.resolve(previous, target); - if (cache) cache[base] = resolvedLink; - gotResolvedLink(resolvedLink); - } - - function gotResolvedLink(resolvedLink) { - // resolve the link, then start over - p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); - } -}; - - -/***/ }), - -/***/ 8297: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -exports.setopts = setopts -exports.ownProp = ownProp -exports.makeAbs = makeAbs -exports.finish = finish -exports.mark = mark -exports.isIgnored = isIgnored -exports.childrenIgnored = childrenIgnored - -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} - -var fs = __nccwpck_require__(7147) -var path = __nccwpck_require__(1017) -var minimatch = __nccwpck_require__(9595) -var isAbsolute = __nccwpck_require__(6872) -var Minimatch = minimatch.Minimatch - -function alphasort (a, b) { - return a.localeCompare(b, 'en') -} - -function setupIgnores (self, options) { - self.ignore = options.ignore || [] - - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] - - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) - } -} - -// ignore patterns are always in dot:true mode. -function ignoreMap (pattern) { - var gmatcher = null - if (pattern.slice(-3) === '/**') { - var gpattern = pattern.replace(/(\/\*\*)+$/, '') - gmatcher = new Minimatch(gpattern, { dot: true }) - } - - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher - } -} - -function setopts (self, pattern, options) { - if (!options) - options = {} - - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") - } - pattern = "**/" + pattern - } - - self.silent = !!options.silent - self.pattern = pattern - self.strict = options.strict !== false - self.realpath = !!options.realpath - self.realpathCache = options.realpathCache || Object.create(null) - self.follow = !!options.follow - self.dot = !!options.dot - self.mark = !!options.mark - self.nodir = !!options.nodir - if (self.nodir) - self.mark = true - self.sync = !!options.sync - self.nounique = !!options.nounique - self.nonull = !!options.nonull - self.nosort = !!options.nosort - self.nocase = !!options.nocase - self.stat = !!options.stat - self.noprocess = !!options.noprocess - self.absolute = !!options.absolute - self.fs = options.fs || fs - - self.maxLength = options.maxLength || Infinity - self.cache = options.cache || Object.create(null) - self.statCache = options.statCache || Object.create(null) - self.symlinks = options.symlinks || Object.create(null) - - setupIgnores(self, options) - - self.changedCwd = false - var cwd = process.cwd() - if (!ownProp(options, "cwd")) - self.cwd = cwd - else { - self.cwd = path.resolve(options.cwd) - self.changedCwd = self.cwd !== cwd - } - - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") - - // TODO: is an absolute `cwd` supposed to be resolved against `root`? - // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') - self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) - if (process.platform === "win32") - self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") - self.nomount = !!options.nomount - - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true - // always treat \ in patterns as escapes, not path separators - options.allowWindowsEscape = false - - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} - -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) - - for (var i = 0, l = self.matches.length; i < l; i ++) { - var matches = self.matches[i] - if (!matches || Object.keys(matches).length === 0) { - if (self.nonull) { - // do like the shell, and spit out the literal glob - var literal = self.minimatch.globSet[i] - if (nou) - all.push(literal) - else - all[literal] = true - } - } else { - // had matches - var m = Object.keys(matches) - if (nou) - all.push.apply(all, m) - else - m.forEach(function (m) { - all[m] = true - }) - } - } - - if (!nou) - all = Object.keys(all) - - if (!self.nosort) - all = all.sort(alphasort) - - // at *some* point we statted all of these - if (self.mark) { - for (var i = 0; i < all.length; i++) { - all[i] = self._mark(all[i]) - } - if (self.nodir) { - all = all.filter(function (e) { - var notDir = !(/\/$/.test(e)) - var c = self.cache[e] || self.cache[makeAbs(self, e)] - if (notDir && c) - notDir = c !== 'DIR' && !Array.isArray(c) - return notDir - }) - } - } - - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) - - self.found = all -} - -function mark (self, p) { - var abs = makeAbs(self, p) - var c = self.cache[abs] - var m = p - if (c) { - var isDir = c === 'DIR' || Array.isArray(c) - var slash = p.slice(-1) === '/' - - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) - - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] - } - } - - return m -} - -// lotta situps... -function makeAbs (self, f) { - var abs = f - if (f.charAt(0) === '/') { - abs = path.join(self.root, f) - } else if (isAbsolute(f) || f === '') { - abs = f - } else if (self.changedCwd) { - abs = path.resolve(self.cwd, f) - } else { - abs = path.resolve(f) - } - - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') - - return abs -} - - -// Return true, if pattern ends with globstar '**', for the accompanying parent directory. -// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents -function isIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) -} - -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) -} - - -/***/ }), - -/***/ 8928: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -// Approach: -// -// 1. Get the minimatch set -// 2. For each pattern in the set, PROCESS(pattern, false) -// 3. Store matches per-set, then uniq them -// -// PROCESS(pattern, inGlobStar) -// Get the first [n] items from pattern that are all strings -// Join these together. This is PREFIX. -// If there is no more remaining, then stat(PREFIX) and -// add to matches if it succeeds. END. -// -// If inGlobStar and PREFIX is symlink and points to dir -// set ENTRIES = [] -// else readdir(PREFIX) as ENTRIES -// If fail, END -// -// with ENTRIES -// If pattern[n] is GLOBSTAR -// // handle the case where the globstar match is empty -// // by pruning it out, and testing the resulting pattern -// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) -// // handle other cases. -// for ENTRY in ENTRIES (not dotfiles) -// // attach globstar + tail onto the entry -// // Mark that this entry is a globstar match -// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) -// -// else // not globstar -// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) -// Test ENTRY against pattern[n] -// If fails, continue -// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) -// -// Caveat: -// Cache all stats and readdirs results to minimize syscall. Since all -// we ever care about is existence and directory-ness, we can just keep -// `true` for files, and [children,...] for directories, or `false` for -// things that don't exist. - -module.exports = glob - -var rp = __nccwpck_require__(6835) -var minimatch = __nccwpck_require__(9595) -var Minimatch = minimatch.Minimatch -var inherits = __nccwpck_require__(614) -var EE = (__nccwpck_require__(2361).EventEmitter) -var path = __nccwpck_require__(1017) -var assert = __nccwpck_require__(9491) -var isAbsolute = __nccwpck_require__(6872) -var globSync = __nccwpck_require__(744) -var common = __nccwpck_require__(8297) -var setopts = common.setopts -var ownProp = common.ownProp -var inflight = __nccwpck_require__(3461) -var util = __nccwpck_require__(3837) -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored - -var once = __nccwpck_require__(2367) - -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} - - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } - - return new Glob(pattern, options, cb) -} - -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync - -// old api surface -glob.glob = glob - -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } - - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin -} - -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true - - var g = new Glob(pattern, options) - var set = g.minimatch.set - - if (!pattern) - return false - - if (set.length > 1) - return true - - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - return true - } - - return false -} - -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } - - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } - - if (!(this instanceof Glob)) - return new Glob(pattern, options, cb) - - setopts(this, pattern, options) - this._didRealPath = false - - // process each pattern in the minimatch set - var n = this.minimatch.set.length - - // The matches are stored as {: true,...} so that - // duplicates are automagically pruned. - // Later, we do an Object.keys() on these. - // Keep them as a list so we can fill in when nonull is set. - this.matches = new Array(n) - - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } - - var self = this - this._processing = 0 - - this._emitQueue = [] - this._processQueue = [] - this.paused = false - - if (this.noprocess) - return this - - if (n === 0) - return done() - - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) - } - sync = false - - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } - } - } -} - -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return - - if (this.realpath && !this._didRealpath) - return this._realpath() - - common.finish(this) - this.emit('end', this.found) -} - -Glob.prototype._realpath = function () { - if (this._didRealpath) - return - - this._didRealpath = true - - var n = this.matches.length - if (n === 0) - return this._finish() - - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) - - function next () { - if (--n === 0) - self._finish() - } -} - -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() - - var found = Object.keys(matchset) - var self = this - var n = found.length - - if (n === 0) - return cb() - - var set = this.matches[index] = Object.create(null) - found.forEach(function (p, i) { - // If there's a problem with the stat, then it means that - // one or more of the links in the realpath couldn't be - // resolved. just return the abs value in that case. - p = self._makeAbs(p) - rp.realpath(p, self.realpathCache, function (er, real) { - if (!er) - set[real] = true - else if (er.syscall === 'stat') - set[p] = true - else - self.emit('error', er) // srsly wtf right here - - if (--n === 0) { - self.matches[index] = set - cb() - } - }) - }) -} - -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} - -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} - -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') - } -} - -Glob.prototype.resume = function () { - if (this.paused) { - this.emit('resume') - this.paused = false - if (this._emitQueue.length) { - var eq = this._emitQueue.slice(0) - this._emitQueue.length = 0 - for (var i = 0; i < eq.length; i ++) { - var e = eq[i] - this._emitMatch(e[0], e[1]) - } - } - if (this._processQueue.length) { - var pq = this._processQueue.slice(0) - this._processQueue.length = 0 - for (var i = 0; i < pq.length; i ++) { - var p = pq[i] - this._processing-- - this._process(p[0], p[1], p[2], p[3]) - } - } - } -} - -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') - - if (this.aborted) - return - - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return - } - - //console.error('PROCESS %d', this._processing, pattern) - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. - - // see if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index, cb) - return - - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } - - var remain = pattern.slice(n) - - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || - isAbsolute(pattern.map(function (p) { - return typeof p === 'string' ? p : '[*]' - }).join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - - var abs = this._makeAbs(read) - - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() - - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) -} - -Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} - -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - - // if the abs isn't a dir, then nothing can match! - if (!entries) - return cb() - - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' - - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) - } - } - - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return cb() - - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. - - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) - } - // This was the last one, and no stats were needed - return cb() - } - - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - this._process([e].concat(remain), index, inGlobStar, cb) - } - cb() -} - -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return - - if (isIgnored(this, e)) - return - - if (this.paused) { - this._emitQueue.push([index, e]) - return - } - - var abs = isAbsolute(e) ? e : this._makeAbs(e) - - if (this.mark) - e = this._mark(e) - - if (this.absolute) - e = abs - - if (this.matches[index][e]) - return - - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } - - this.matches[index][e] = true - - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) - - this.emit('match', e) -} - -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return - - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, cb) - - var lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) - - if (lstatcb) - self.fs.lstat(abs, lstatcb) - - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() - - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym - - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) { - self.cache[abs] = 'FILE' - cb() - } else - self._readdir(abs, false, cb) - } -} - -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return - - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return - - //console.error('RD %j %j', +inGlobStar, abs) - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs, cb) - - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return cb() - - if (Array.isArray(c)) - return cb(null, c) - } - - var self = this - self.fs.readdir(abs, readdirCb(this, abs, cb)) -} - -function readdirCb (self, abs, cb) { - return function (er, entries) { - if (er) - self._readdirError(abs, er, cb) - else - self._readdirEntries(abs, entries, cb) - } -} - -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return - - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } - } - - this.cache[abs] = entries - return cb(null, entries) -} - -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return - - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - this.emit('error', error) - this.abort() - } - break - - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break - - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) { - this.emit('error', er) - // If the error is handled, then we abort - // if not, we threw out of here - this.abort() - } - if (!this.silent) - console.error('glob error', er) - break - } - - return cb() -} - -Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} - - -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) - - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() - - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) - - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false, cb) - - var isSym = this.symlinks[abs] - var len = entries.length - - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return cb() - - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue - - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true, cb) - - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) - } - - cb() -} - -Glob.prototype._processSimple = function (prefix, index, cb) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var self = this - this._stat(prefix, function (er, exists) { - self._processSimple2(prefix, index, er, exists, cb) - }) -} -Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { - - //console.error('ps2', prefix, exists) - - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return cb() - - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } - - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') - - // Mark this as a match - this._emitMatch(index, prefix) - cb() -} - -// Returns either 'DIR', 'FILE', or false -Glob.prototype._stat = function (f, cb) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - - if (f.length > this.maxLength) - return cb() - - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - - if (Array.isArray(c)) - c = 'DIR' - - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) - - if (needDir && c === 'FILE') - return cb() - - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } - - var exists - var stat = this.statCache[abs] - if (stat !== undefined) { - if (stat === false) - return cb(null, stat) - else { - var type = stat.isDirectory() ? 'DIR' : 'FILE' - if (needDir && type === 'FILE') - return cb() - else - return cb(null, type, stat) - } - } - - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - self.fs.lstat(abs, statcb) - - function lstatcb_ (er, lstat) { - if (lstat && lstat.isSymbolicLink()) { - // If it's a symlink, then treat it as the target, unless - // the target does not exist, then treat it as a file. - return self.fs.stat(abs, function (er, stat) { - if (er) - self._stat2(f, abs, null, lstat, cb) - else - self._stat2(f, abs, er, stat, cb) - }) - } else { - self._stat2(f, abs, er, lstat, cb) - } - } -} - -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() - } - - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat - - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) - - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c - - if (needDir && c === 'FILE') - return cb() - - return cb(null, c, stat) -} - - -/***/ }), - -/***/ 744: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -module.exports = globSync -globSync.GlobSync = GlobSync - -var rp = __nccwpck_require__(6835) -var minimatch = __nccwpck_require__(9595) -var Minimatch = minimatch.Minimatch -var Glob = (__nccwpck_require__(8928).Glob) -var util = __nccwpck_require__(3837) -var path = __nccwpck_require__(1017) -var assert = __nccwpck_require__(9491) -var isAbsolute = __nccwpck_require__(6872) -var common = __nccwpck_require__(8297) -var setopts = common.setopts -var ownProp = common.ownProp -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored - -function globSync (pattern, options) { - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') - - return new GlobSync(pattern, options).found -} - -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') - - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') - - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) - - setopts(this, pattern, options) - - if (this.noprocess) - return this - - var n = this.minimatch.set.length - this.matches = new Array(n) - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false) - } - this._finish() -} - -GlobSync.prototype._finish = function () { - assert.ok(this instanceof GlobSync) - if (this.realpath) { - var self = this - this.matches.forEach(function (matchset, index) { - var set = self.matches[index] = Object.create(null) - for (var p in matchset) { - try { - p = self._makeAbs(p) - var real = rp.realpathSync(p, self.realpathCache) - set[real] = true - } catch (er) { - if (er.syscall === 'stat') - set[self._makeAbs(p)] = true - else - throw er - } - } - }) - } - common.finish(this) -} - - -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert.ok(this instanceof GlobSync) - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. - - // See if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index) - return - - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } - - var remain = pattern.slice(n) - - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || - isAbsolute(pattern.map(function (p) { - return typeof p === 'string' ? p : '[*]' - }).join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - - var abs = this._makeAbs(read) - - //if ignored, skip processing - if (childrenIgnored(this, read)) - return - - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar) -} - - -GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) - - // if the abs isn't a dir, then nothing can match! - if (!entries) - return - - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' - - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) - } - } - - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return - - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. - - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) - } - // This was the last one, and no stats were needed - return - } - - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) - newPattern = [prefix, e] - else - newPattern = [e] - this._process(newPattern.concat(remain), index, inGlobStar) - } -} - - -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return - - var abs = this._makeAbs(e) - - if (this.mark) - e = this._mark(e) - - if (this.absolute) { - e = abs - } - - if (this.matches[index][e]) - return - - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } - - this.matches[index][e] = true - - if (this.stat) - this._stat(e) -} - - -GlobSync.prototype._readdirInGlobStar = function (abs) { - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false) - - var entries - var lstat - var stat - try { - lstat = this.fs.lstatSync(abs) - } catch (er) { - if (er.code === 'ENOENT') { - // lstat failed, doesn't exist - return null - } - } - - var isSym = lstat && lstat.isSymbolicLink() - this.symlinks[abs] = isSym - - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) - this.cache[abs] = 'FILE' - else - entries = this._readdir(abs, false) - - return entries -} - -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries - - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) - - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null - - if (Array.isArray(c)) - return c - } - - try { - return this._readdirEntries(abs, this.fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null - } -} - -GlobSync.prototype._readdirEntries = function (abs, entries) { - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } - } - - this.cache[abs] = entries - - // mark and cache dir-ness - return entries -} - -GlobSync.prototype._readdirError = function (f, er) { - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - throw error - } - break - - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break - - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) - throw er - if (!this.silent) - console.error('glob error', er) - break - } -} - -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { - - var entries = this._readdir(abs, inGlobStar) - - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return - - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) - - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) - - var len = entries.length - var isSym = this.symlinks[abs] - - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return - - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue - - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) - - var below = gspref.concat(entries[i], remain) - this._process(below, index, true) - } -} - -GlobSync.prototype._processSimple = function (prefix, index) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var exists = this._stat(prefix) - - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return - - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } - - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') - - // Mark this as a match - this._emitMatch(index, prefix) -} - -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - - if (f.length > this.maxLength) - return false - - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - - if (Array.isArray(c)) - c = 'DIR' - - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c - - if (needDir && c === 'FILE') - return false - - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } - - var exists - var stat = this.statCache[abs] - if (!stat) { - var lstat - try { - lstat = this.fs.lstatSync(abs) - } catch (er) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return false - } - } - - if (lstat && lstat.isSymbolicLink()) { - try { - stat = this.fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } - - this.statCache[abs] = stat - - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - - this.cache[abs] = this.cache[abs] || c - - if (needDir && c === 'FILE') - return false - - return c -} - -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} - -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - - -/***/ }), - -/***/ 3461: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var wrappy = __nccwpck_require__(3466) -var reqs = Object.create(null) -var once = __nccwpck_require__(2367) - -module.exports = wrappy(inflight) - -function inflight (key, cb) { - if (reqs[key]) { - reqs[key].push(cb) - return null - } else { - reqs[key] = [cb] - return makeres(key) - } -} - -function makeres (key) { - return once(function RES () { - var cbs = reqs[key] - var len = cbs.length - var args = slice(arguments) - - // XXX It's somewhat ambiguous whether a new callback added in this - // pass should be queued for later execution if something in the - // list of callbacks throws, or if it should just be discarded. - // However, it's such an edge case that it hardly matters, and either - // choice is likely as surprising as the other. - // As it happens, we do go ahead and schedule it for later execution. - try { - for (var i = 0; i < len; i++) { - cbs[i].apply(null, args) - } - } finally { - if (cbs.length > len) { - // added more in the interim. - // de-zalgo, just in case, but don't call again. - cbs.splice(0, len) - process.nextTick(function () { - RES.apply(null, args) - }) - } else { - delete reqs[key] - } - } - }) -} - -function slice (args) { - var length = args.length - var array = [] - - for (var i = 0; i < length; i++) array[i] = args[i] - return array -} - - -/***/ }), - -/***/ 614: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -try { - var util = __nccwpck_require__(3837); - /* istanbul ignore next */ - if (typeof util.inherits !== 'function') throw ''; - module.exports = util.inherits; -} catch (e) { - /* istanbul ignore next */ - module.exports = __nccwpck_require__(921); -} - - -/***/ }), - -/***/ 921: -/***/ ((module) => { - -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }) - } - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } -} - - -/***/ }), - -/***/ 9595: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -module.exports = minimatch -minimatch.Minimatch = Minimatch - -var path = (function () { try { return __nccwpck_require__(1017) } catch (e) {}}()) || { - sep: '/' -} -minimatch.sep = path.sep - -var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} -var expand = __nccwpck_require__(4642) - -var plTypes = { - '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, - '?': { open: '(?:', close: ')?' }, - '+': { open: '(?:', close: ')+' }, - '*': { open: '(?:', close: ')*' }, - '@': { open: '(?:', close: ')' } -} - -// any single thing other than / -// don't need to escape / when using new RegExp() -var qmark = '[^/]' - -// * => any number of characters -var star = qmark + '*?' - -// ** when dots are allowed. Anything goes, except .. and . -// not (^ or / followed by one or two dots followed by $ or /), -// followed by anything, any number of times. -var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' - -// not a ^ or / followed by a dot, -// followed by anything, any number of times. -var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' - -// characters that need to be escaped in RegExp. -var reSpecials = charSet('().*{}+?[]^$\\!') - -// "abc" -> { a:true, b:true, c:true } -function charSet (s) { - return s.split('').reduce(function (set, c) { - set[c] = true - return set - }, {}) -} - -// normalizes slashes. -var slashSplit = /\/+/ - -minimatch.filter = filter -function filter (pattern, options) { - options = options || {} - return function (p, i, list) { - return minimatch(p, pattern, options) - } -} - -function ext (a, b) { - b = b || {} - var t = {} - Object.keys(a).forEach(function (k) { - t[k] = a[k] - }) - Object.keys(b).forEach(function (k) { - t[k] = b[k] - }) - return t -} - -minimatch.defaults = function (def) { - if (!def || typeof def !== 'object' || !Object.keys(def).length) { - return minimatch - } - - var orig = minimatch - - var m = function minimatch (p, pattern, options) { - return orig(p, pattern, ext(def, options)) - } - - m.Minimatch = function Minimatch (pattern, options) { - return new orig.Minimatch(pattern, ext(def, options)) - } - m.Minimatch.defaults = function defaults (options) { - return orig.defaults(ext(def, options)).Minimatch - } - - m.filter = function filter (pattern, options) { - return orig.filter(pattern, ext(def, options)) - } - - m.defaults = function defaults (options) { - return orig.defaults(ext(def, options)) - } - - m.makeRe = function makeRe (pattern, options) { - return orig.makeRe(pattern, ext(def, options)) - } - - m.braceExpand = function braceExpand (pattern, options) { - return orig.braceExpand(pattern, ext(def, options)) - } - - m.match = function (list, pattern, options) { - return orig.match(list, pattern, ext(def, options)) - } - - return m -} - -Minimatch.defaults = function (def) { - return minimatch.defaults(def).Minimatch -} - -function minimatch (p, pattern, options) { - assertValidPattern(pattern) - - if (!options) options = {} - - // shortcut: comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - return false - } - - return new Minimatch(pattern, options).match(p) -} - -function Minimatch (pattern, options) { - if (!(this instanceof Minimatch)) { - return new Minimatch(pattern, options) - } - - assertValidPattern(pattern) - - if (!options) options = {} - - pattern = pattern.trim() - - // windows support: need to use /, not \ - if (!options.allowWindowsEscape && path.sep !== '/') { - pattern = pattern.split(path.sep).join('/') - } - - this.options = options - this.set = [] - this.pattern = pattern - this.regexp = null - this.negate = false - this.comment = false - this.empty = false - this.partial = !!options.partial - - // make the set of regexps etc. - this.make() -} - -Minimatch.prototype.debug = function () {} - -Minimatch.prototype.make = make -function make () { - var pattern = this.pattern - var options = this.options - - // empty patterns and comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - this.comment = true - return - } - if (!pattern) { - this.empty = true - return - } - - // step 1: figure out negation, etc. - this.parseNegate() - - // step 2: expand braces - var set = this.globSet = this.braceExpand() - - if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) } - - this.debug(this.pattern, set) - - // step 3: now we have a set, so turn each one into a series of path-portion - // matching patterns. - // These will be regexps, except in the case of "**", which is - // set to the GLOBSTAR object for globstar behavior, - // and will not contain any / characters - set = this.globParts = set.map(function (s) { - return s.split(slashSplit) - }) - - this.debug(this.pattern, set) - - // glob --> regexps - set = set.map(function (s, si, set) { - return s.map(this.parse, this) - }, this) - - this.debug(this.pattern, set) - - // filter out everything that didn't compile properly. - set = set.filter(function (s) { - return s.indexOf(false) === -1 - }) - - this.debug(this.pattern, set) - - this.set = set -} - -Minimatch.prototype.parseNegate = parseNegate -function parseNegate () { - var pattern = this.pattern - var negate = false - var options = this.options - var negateOffset = 0 - - if (options.nonegate) return - - for (var i = 0, l = pattern.length - ; i < l && pattern.charAt(i) === '!' - ; i++) { - negate = !negate - negateOffset++ - } - - if (negateOffset) this.pattern = pattern.substr(negateOffset) - this.negate = negate -} - -// Brace expansion: -// a{b,c}d -> abd acd -// a{b,}c -> abc ac -// a{0..3}d -> a0d a1d a2d a3d -// a{b,c{d,e}f}g -> abg acdfg acefg -// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg -// -// Invalid sets are not expanded. -// a{2..}b -> a{2..}b -// a{b}c -> a{b}c -minimatch.braceExpand = function (pattern, options) { - return braceExpand(pattern, options) -} - -Minimatch.prototype.braceExpand = braceExpand - -function braceExpand (pattern, options) { - if (!options) { - if (this instanceof Minimatch) { - options = this.options - } else { - options = {} - } - } - - pattern = typeof pattern === 'undefined' - ? this.pattern : pattern - - assertValidPattern(pattern) - - // Thanks to Yeting Li for - // improving this regexp to avoid a ReDOS vulnerability. - if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { - // shortcut. no need to expand. - return [pattern] - } - - return expand(pattern) -} - -var MAX_PATTERN_LENGTH = 1024 * 64 -var assertValidPattern = function (pattern) { - if (typeof pattern !== 'string') { - throw new TypeError('invalid pattern') - } - - if (pattern.length > MAX_PATTERN_LENGTH) { - throw new TypeError('pattern is too long') - } -} - -// parse a component of the expanded set. -// At this point, no pattern may contain "/" in it -// so we're going to return a 2d array, where each entry is the full -// pattern, split on '/', and then turned into a regular expression. -// A regexp is made at the end which joins each array with an -// escaped /, and another full one which joins each regexp with |. -// -// Following the lead of Bash 4.1, note that "**" only has special meaning -// when it is the *only* thing in a path portion. Otherwise, any series -// of * is equivalent to a single *. Globstar behavior is enabled by -// default, and can be disabled by setting options.noglobstar. -Minimatch.prototype.parse = parse -var SUBPARSE = {} -function parse (pattern, isSub) { - assertValidPattern(pattern) - - var options = this.options - - // shortcuts - if (pattern === '**') { - if (!options.noglobstar) - return GLOBSTAR - else - pattern = '*' - } - if (pattern === '') return '' - - var re = '' - var hasMagic = !!options.nocase - var escaping = false - // ? => one single character - var patternListStack = [] - var negativeLists = [] - var stateChar - var inClass = false - var reClassStart = -1 - var classStart = -1 - // . and .. never match anything that doesn't start with ., - // even when options.dot is set. - var patternStart = pattern.charAt(0) === '.' ? '' // anything - // not (start or / followed by . or .. followed by / or end) - : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' - : '(?!\\.)' - var self = this - - function clearStateChar () { - if (stateChar) { - // we had some state-tracking character - // that wasn't consumed by this pass. - switch (stateChar) { - case '*': - re += star - hasMagic = true - break - case '?': - re += qmark - hasMagic = true - break - default: - re += '\\' + stateChar - break - } - self.debug('clearStateChar %j %j', stateChar, re) - stateChar = false - } - } - - for (var i = 0, len = pattern.length, c - ; (i < len) && (c = pattern.charAt(i)) - ; i++) { - this.debug('%s\t%s %s %j', pattern, i, re, c) - - // skip over any that are escaped. - if (escaping && reSpecials[c]) { - re += '\\' + c - escaping = false - continue - } - - switch (c) { - /* istanbul ignore next */ - case '/': { - // completely not allowed, even escaped. - // Should already be path-split by now. - return false - } - - case '\\': - clearStateChar() - escaping = true - continue - - // the various stateChar values - // for the "extglob" stuff. - case '?': - case '*': - case '+': - case '@': - case '!': - this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) - - // all of those are literals inside a class, except that - // the glob [!a] means [^a] in regexp - if (inClass) { - this.debug(' in class') - if (c === '!' && i === classStart + 1) c = '^' - re += c - continue - } - - // if we already have a stateChar, then it means - // that there was something like ** or +? in there. - // Handle the stateChar, then proceed with this one. - self.debug('call clearStateChar %j', stateChar) - clearStateChar() - stateChar = c - // if extglob is disabled, then +(asdf|foo) isn't a thing. - // just clear the statechar *now*, rather than even diving into - // the patternList stuff. - if (options.noext) clearStateChar() - continue - - case '(': - if (inClass) { - re += '(' - continue - } - - if (!stateChar) { - re += '\\(' - continue - } - - patternListStack.push({ - type: stateChar, - start: i - 1, - reStart: re.length, - open: plTypes[stateChar].open, - close: plTypes[stateChar].close - }) - // negation is (?:(?!js)[^/]*) - re += stateChar === '!' ? '(?:(?!(?:' : '(?:' - this.debug('plType %j %j', stateChar, re) - stateChar = false - continue - - case ')': - if (inClass || !patternListStack.length) { - re += '\\)' - continue - } - - clearStateChar() - hasMagic = true - var pl = patternListStack.pop() - // negation is (?:(?!js)[^/]*) - // The others are (?:) - re += pl.close - if (pl.type === '!') { - negativeLists.push(pl) - } - pl.reEnd = re.length - continue - - case '|': - if (inClass || !patternListStack.length || escaping) { - re += '\\|' - escaping = false - continue - } - - clearStateChar() - re += '|' - continue - - // these are mostly the same in regexp and glob - case '[': - // swallow any state-tracking char before the [ - clearStateChar() - - if (inClass) { - re += '\\' + c - continue - } - - inClass = true - classStart = i - reClassStart = re.length - re += c - continue - - case ']': - // a right bracket shall lose its special - // meaning and represent itself in - // a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - if (i === classStart + 1 || !inClass) { - re += '\\' + c - escaping = false - continue - } - - // handle the case where we left a class open. - // "[z-a]" is valid, equivalent to "\[z-a\]" - // split where the last [ was, make sure we don't have - // an invalid re. if so, re-walk the contents of the - // would-be class to re-translate any characters that - // were passed through as-is - // TODO: It would probably be faster to determine this - // without a try/catch and a new RegExp, but it's tricky - // to do safely. For now, this is safe and works. - var cs = pattern.substring(classStart + 1, i) - try { - RegExp('[' + cs + ']') - } catch (er) { - // not a valid class! - var sp = this.parse(cs, SUBPARSE) - re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' - hasMagic = hasMagic || sp[1] - inClass = false - continue - } - - // finish up the class. - hasMagic = true - inClass = false - re += c - continue - - default: - // swallow any state char that wasn't consumed - clearStateChar() - - if (escaping) { - // no need - escaping = false - } else if (reSpecials[c] - && !(c === '^' && inClass)) { - re += '\\' - } - - re += c - - } // switch - } // for - - // handle the case where we left a class open. - // "[abc" is valid, equivalent to "\[abc" - if (inClass) { - // split where the last [ was, and escape it - // this is a huge pita. We now have to re-walk - // the contents of the would-be class to re-translate - // any characters that were passed through as-is - cs = pattern.substr(classStart + 1) - sp = this.parse(cs, SUBPARSE) - re = re.substr(0, reClassStart) + '\\[' + sp[0] - hasMagic = hasMagic || sp[1] - } - - // handle the case where we had a +( thing at the *end* - // of the pattern. - // each pattern list stack adds 3 chars, and we need to go through - // and escape any | chars that were passed through as-is for the regexp. - // Go through and escape them, taking care not to double-escape any - // | chars that were already escaped. - for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { - var tail = re.slice(pl.reStart + pl.open.length) - this.debug('setting tail', re, pl) - // maybe some even number of \, then maybe 1 \, followed by a | - tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { - if (!$2) { - // the | isn't already escaped, so escape it. - $2 = '\\' - } - - // need to escape all those slashes *again*, without escaping the - // one that we need for escaping the | character. As it works out, - // escaping an even number of slashes can be done by simply repeating - // it exactly after itself. That's why this trick works. - // - // I am sorry that you have to see this. - return $1 + $1 + $2 + '|' - }) - - this.debug('tail=%j\n %s', tail, tail, pl, re) - var t = pl.type === '*' ? star - : pl.type === '?' ? qmark - : '\\' + pl.type - - hasMagic = true - re = re.slice(0, pl.reStart) + t + '\\(' + tail - } - - // handle trailing things that only matter at the very end. - clearStateChar() - if (escaping) { - // trailing \\ - re += '\\\\' - } - - // only need to apply the nodot start if the re starts with - // something that could conceivably capture a dot - var addPatternStart = false - switch (re.charAt(0)) { - case '[': case '.': case '(': addPatternStart = true - } - - // Hack to work around lack of negative lookbehind in JS - // A pattern like: *.!(x).!(y|z) needs to ensure that a name - // like 'a.xyz.yz' doesn't match. So, the first negative - // lookahead, has to look ALL the way ahead, to the end of - // the pattern. - for (var n = negativeLists.length - 1; n > -1; n--) { - var nl = negativeLists[n] - - var nlBefore = re.slice(0, nl.reStart) - var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) - var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) - var nlAfter = re.slice(nl.reEnd) - - nlLast += nlAfter - - // Handle nested stuff like *(*.js|!(*.json)), where open parens - // mean that we should *not* include the ) in the bit that is considered - // "after" the negated section. - var openParensBefore = nlBefore.split('(').length - 1 - var cleanAfter = nlAfter - for (i = 0; i < openParensBefore; i++) { - cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') - } - nlAfter = cleanAfter - - var dollar = '' - if (nlAfter === '' && isSub !== SUBPARSE) { - dollar = '$' - } - var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast - re = newRe - } - - // if the re is not "" at this point, then we need to make sure - // it doesn't match against an empty path part. - // Otherwise a/* will match a/, which it should not. - if (re !== '' && hasMagic) { - re = '(?=.)' + re - } - - if (addPatternStart) { - re = patternStart + re - } - - // parsing just a piece of a larger pattern. - if (isSub === SUBPARSE) { - return [re, hasMagic] - } - - // skip the regexp for non-magical patterns - // unescape anything in it, though, so that it'll be - // an exact match against a file etc. - if (!hasMagic) { - return globUnescape(pattern) - } - - var flags = options.nocase ? 'i' : '' - try { - var regExp = new RegExp('^' + re + '$', flags) - } catch (er) /* istanbul ignore next - should be impossible */ { - // If it was an invalid regular expression, then it can't match - // anything. This trick looks for a character after the end of - // the string, which is of course impossible, except in multi-line - // mode, but it's not a /m regex. - return new RegExp('$.') - } - - regExp._glob = pattern - regExp._src = re - - return regExp -} - -minimatch.makeRe = function (pattern, options) { - return new Minimatch(pattern, options || {}).makeRe() -} - -Minimatch.prototype.makeRe = makeRe -function makeRe () { - if (this.regexp || this.regexp === false) return this.regexp - - // at this point, this.set is a 2d array of partial - // pattern strings, or "**". - // - // It's better to use .match(). This function shouldn't - // be used, really, but it's pretty convenient sometimes, - // when you just want to work with a regex. - var set = this.set - - if (!set.length) { - this.regexp = false - return this.regexp - } - var options = this.options - - var twoStar = options.noglobstar ? star - : options.dot ? twoStarDot - : twoStarNoDot - var flags = options.nocase ? 'i' : '' - - var re = set.map(function (pattern) { - return pattern.map(function (p) { - return (p === GLOBSTAR) ? twoStar - : (typeof p === 'string') ? regExpEscape(p) - : p._src - }).join('\\\/') - }).join('|') - - // must match entire pattern - // ending in a * or ** will make it less strict. - re = '^(?:' + re + ')$' - - // can match anything, as long as it's not this. - if (this.negate) re = '^(?!' + re + ').*$' - - try { - this.regexp = new RegExp(re, flags) - } catch (ex) /* istanbul ignore next - should be impossible */ { - this.regexp = false - } - return this.regexp -} - -minimatch.match = function (list, pattern, options) { - options = options || {} - var mm = new Minimatch(pattern, options) - list = list.filter(function (f) { - return mm.match(f) - }) - if (mm.options.nonull && !list.length) { - list.push(pattern) - } - return list -} - -Minimatch.prototype.match = function match (f, partial) { - if (typeof partial === 'undefined') partial = this.partial - this.debug('match', f, this.pattern) - // short-circuit in the case of busted things. - // comments, etc. - if (this.comment) return false - if (this.empty) return f === '' - - if (f === '/' && partial) return true - - var options = this.options - - // windows: need to use /, not \ - if (path.sep !== '/') { - f = f.split(path.sep).join('/') - } - - // treat the test path as a set of pathparts. - f = f.split(slashSplit) - this.debug(this.pattern, 'split', f) - - // just ONE of the pattern sets in this.set needs to match - // in order for it to be valid. If negating, then just one - // match means that we have failed. - // Either way, return on the first hit. - - var set = this.set - this.debug(this.pattern, 'set', set) - - // Find the basename of the path by looking for the last non-empty segment - var filename - var i - for (i = f.length - 1; i >= 0; i--) { - filename = f[i] - if (filename) break - } - - for (i = 0; i < set.length; i++) { - var pattern = set[i] - var file = f - if (options.matchBase && pattern.length === 1) { - file = [filename] - } - var hit = this.matchOne(file, pattern, partial) - if (hit) { - if (options.flipNegate) return true - return !this.negate - } - } - - // didn't get any hits. this is success if it's a negative - // pattern, failure otherwise. - if (options.flipNegate) return false - return this.negate -} - -// set partial to true to test if, for example, -// "/a/b" matches the start of "/*/b/*/d" -// Partial means, if you run out of file before you run -// out of pattern, then that's fine, as long as all -// the parts match. -Minimatch.prototype.matchOne = function (file, pattern, partial) { - var options = this.options - - this.debug('matchOne', - { 'this': this, file: file, pattern: pattern }) - - this.debug('matchOne', file.length, pattern.length) - - for (var fi = 0, - pi = 0, - fl = file.length, - pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi++, pi++) { - this.debug('matchOne loop') - var p = pattern[pi] - var f = file[fi] - - this.debug(pattern, p, f) - - // should be impossible. - // some invalid regexp stuff in the set. - /* istanbul ignore if */ - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - var pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) return false - } - return true - } - - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr] - - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) - - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr) - break - } - - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr++ - } - } - - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - /* istanbul ignore if */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr) - if (fr === fl) return true - } - return false - } - - // something other than ** - // non-magic patterns just have to match exactly - // patterns with magic have been turned into regexps. - var hit - if (typeof p === 'string') { - hit = f === p - this.debug('string match', p, f, hit) - } else { - hit = f.match(p) - this.debug('pattern match', p, f, hit) - } - - if (!hit) return false - } - - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - - // now either we fell off the end of the pattern, or we're done. - if (fi === fl && pi === pl) { - // ran out of pattern and filename at the same time. - // an exact hit! - return true - } else if (fi === fl) { - // ran out of file, but still had pattern left. - // this is ok if we're doing the match as part of - // a glob fs traversal. - return partial - } else /* istanbul ignore else */ if (pi === pl) { - // ran out of pattern, still have file left. - // this is only acceptable if we're on the very last - // empty segment of a file with a trailing slash. - // a/* should match a/b/ - return (fi === fl - 1) && (file[fi] === '') - } - - // should be unreachable. - /* istanbul ignore next */ - throw new Error('wtf?') -} - -// replace stuff like \* with * -function globUnescape (s) { - return s.replace(/\\(.)/g, '$1') -} - -function regExpEscape (s) { - return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') -} - - -/***/ }), - -/***/ 2367: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var wrappy = __nccwpck_require__(3466) -module.exports = wrappy(once) -module.exports.strict = wrappy(onceStrict) - -once.proto = once(function () { - Object.defineProperty(Function.prototype, 'once', { - value: function () { - return once(this) - }, - configurable: true - }) - - Object.defineProperty(Function.prototype, 'onceStrict', { - value: function () { - return onceStrict(this) - }, - configurable: true - }) -}) - -function once (fn) { - var f = function () { - if (f.called) return f.value - f.called = true - return f.value = fn.apply(this, arguments) - } - f.called = false - return f -} - -function onceStrict (fn) { - var f = function () { - if (f.called) - throw new Error(f.onceError) - f.called = true - return f.value = fn.apply(this, arguments) - } - var name = fn.name || 'Function wrapped with `once`' - f.onceError = name + " shouldn't be called more than once" - f.called = false - return f -} - - -/***/ }), - -/***/ 6872: -/***/ ((module) => { - -"use strict"; - - -function posix(path) { - return path.charAt(0) === '/'; -} - -function win32(path) { - // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56 - var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; - var result = splitDeviceRe.exec(path); - var device = result[1] || ''; - var isUnc = Boolean(device && device.charAt(1) !== ':'); - - // UNC paths are always absolute - return Boolean(result[2] || isUnc); -} - -module.exports = process.platform === 'win32' ? win32 : posix; -module.exports.posix = posix; -module.exports.win32 = win32; - - -/***/ }), - -/***/ 9773: -/***/ ((module) => { - -module.exports = [ - 'cat', - 'cd', - 'chmod', - 'cp', - 'dirs', - 'echo', - 'exec', - 'find', - 'grep', - 'head', - 'ln', - 'ls', - 'mkdir', - 'mv', - 'pwd', - 'rm', - 'sed', - 'set', - 'sort', - 'tail', - 'tempdir', - 'test', - 'to', - 'toEnd', - 'touch', - 'uniq', - 'which', -]; - - -/***/ }), - -/***/ 2800: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -// -// ShellJS -// Unix shell commands on top of Node's API -// -// Copyright (c) 2012 Artur Adib -// http://github.com/shelljs/shelljs -// - -function __ncc_wildcard$0 (arg) { - if (arg === "cat.js" || arg === "cat") return __nccwpck_require__(4201); - else if (arg === "cd.js" || arg === "cd") return __nccwpck_require__(4724); - else if (arg === "chmod.js" || arg === "chmod") return __nccwpck_require__(4457); - else if (arg === "common.js" || arg === "common") return __nccwpck_require__(4396); - else if (arg === "cp.js" || arg === "cp") return __nccwpck_require__(9926); - else if (arg === "dirs.js" || arg === "dirs") return __nccwpck_require__(5417); - else if (arg === "echo.js" || arg === "echo") return __nccwpck_require__(8484); - else if (arg === "error.js" || arg === "error") return __nccwpck_require__(6147); - else if (arg === "exec-child.js" || arg === "exec-child") return __nccwpck_require__(2020); - else if (arg === "exec.js" || arg === "exec") return __nccwpck_require__(3378); - else if (arg === "find.js" || arg === "find") return __nccwpck_require__(4385); - else if (arg === "grep.js" || arg === "grep") return __nccwpck_require__(415); - else if (arg === "head.js" || arg === "head") return __nccwpck_require__(4049); - else if (arg === "ln.js" || arg === "ln") return __nccwpck_require__(6655); - else if (arg === "ls.js" || arg === "ls") return __nccwpck_require__(7513); - else if (arg === "mkdir.js" || arg === "mkdir") return __nccwpck_require__(6738); - else if (arg === "mv.js" || arg === "mv") return __nccwpck_require__(9503); - else if (arg === "popd.js" || arg === "popd") return __nccwpck_require__(2720); - else if (arg === "pushd.js" || arg === "pushd") return __nccwpck_require__(9835); - else if (arg === "pwd.js" || arg === "pwd") return __nccwpck_require__(6214); - else if (arg === "rm.js" || arg === "rm") return __nccwpck_require__(1177); - else if (arg === "sed.js" || arg === "sed") return __nccwpck_require__(7776); - else if (arg === "set.js" || arg === "set") return __nccwpck_require__(5091); - else if (arg === "sort.js" || arg === "sort") return __nccwpck_require__(9552); - else if (arg === "tail.js" || arg === "tail") return __nccwpck_require__(662); - else if (arg === "tempdir.js" || arg === "tempdir") return __nccwpck_require__(2979); - else if (arg === "test.js" || arg === "test") return __nccwpck_require__(8760); - else if (arg === "to.js" || arg === "to") return __nccwpck_require__(9934); - else if (arg === "toEnd.js" || arg === "toEnd") return __nccwpck_require__(3934); - else if (arg === "touch.js" || arg === "touch") return __nccwpck_require__(4536); - else if (arg === "uniq.js" || arg === "uniq") return __nccwpck_require__(2619); - else if (arg === "which.js" || arg === "which") return __nccwpck_require__(3698); -} -var common = __nccwpck_require__(4396); - -//@ -//@ All commands run synchronously, unless otherwise stated. -//@ All commands accept standard bash globbing characters (`*`, `?`, etc.), -//@ compatible with the [node `glob` module](https://github.com/isaacs/node-glob). -//@ -//@ For less-commonly used commands and features, please check out our [wiki -//@ page](https://github.com/shelljs/shelljs/wiki). -//@ - -// Include the docs for all the default commands -//@commands - -// Load all default commands -(__nccwpck_require__(9773).forEach)(function (command) { - __ncc_wildcard$0(command); -}); - -//@ -//@ ### exit(code) -//@ -//@ Exits the current process with the given exit `code`. -exports.exit = process.exit; - -//@include ./src/error -exports.error = __nccwpck_require__(6147); - -//@include ./src/common -exports.ShellString = common.ShellString; - -//@ -//@ ### env['VAR_NAME'] -//@ -//@ Object containing environment variables (both getter and setter). Shortcut -//@ to `process.env`. -exports.env = process.env; - -//@ -//@ ### Pipes -//@ -//@ Examples: -//@ -//@ ```javascript -//@ grep('foo', 'file1.txt', 'file2.txt').sed(/o/g, 'a').to('output.txt'); -//@ echo('files with o\'s in the name:\n' + ls().grep('o')); -//@ cat('test.js').exec('node'); // pipe to exec() call -//@ ``` -//@ -//@ Commands can send their output to another command in a pipe-like fashion. -//@ `sed`, `grep`, `cat`, `exec`, `to`, and `toEnd` can appear on the right-hand -//@ side of a pipe. Pipes can be chained. - -//@ -//@ ## Configuration -//@ - -exports.config = common.config; - -//@ -//@ ### config.silent -//@ -//@ Example: -//@ -//@ ```javascript -//@ var sh = require('shelljs'); -//@ var silentState = sh.config.silent; // save old silent state -//@ sh.config.silent = true; -//@ /* ... */ -//@ sh.config.silent = silentState; // restore old silent state -//@ ``` -//@ -//@ Suppresses all command output if `true`, except for `echo()` calls. -//@ Default is `false`. - -//@ -//@ ### config.fatal -//@ -//@ Example: -//@ -//@ ```javascript -//@ require('shelljs/global'); -//@ config.fatal = true; // or set('-e'); -//@ cp('this_file_does_not_exist', '/dev/null'); // throws Error here -//@ /* more commands... */ -//@ ``` -//@ -//@ If `true`, the script will throw a Javascript error when any shell.js -//@ command encounters an error. Default is `false`. This is analogous to -//@ Bash's `set -e`. - -//@ -//@ ### config.verbose -//@ -//@ Example: -//@ -//@ ```javascript -//@ config.verbose = true; // or set('-v'); -//@ cd('dir/'); -//@ rm('-rf', 'foo.txt', 'bar.txt'); -//@ exec('echo hello'); -//@ ``` -//@ -//@ Will print each command as follows: -//@ -//@ ``` -//@ cd dir/ -//@ rm -rf foo.txt bar.txt -//@ exec echo hello -//@ ``` - -//@ -//@ ### config.globOptions -//@ -//@ Example: -//@ -//@ ```javascript -//@ config.globOptions = {nodir: true}; -//@ ``` -//@ -//@ Use this value for calls to `glob.sync()` instead of the default options. - -//@ -//@ ### config.reset() -//@ -//@ Example: -//@ -//@ ```javascript -//@ var shell = require('shelljs'); -//@ // Make changes to shell.config, and do stuff... -//@ /* ... */ -//@ shell.config.reset(); // reset to original state -//@ // Do more stuff, but with original settings -//@ /* ... */ -//@ ``` -//@ -//@ Reset `shell.config` to the defaults: -//@ -//@ ```javascript -//@ { -//@ fatal: false, -//@ globOptions: {}, -//@ maxdepth: 255, -//@ noglob: false, -//@ silent: false, -//@ verbose: false, -//@ } -//@ ``` - - -/***/ }), - -/***/ 4201: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('cat', _cat, { - canReceivePipe: true, - cmdOptions: { - 'n': 'number', - }, -}); - -//@ -//@ ### cat([options,] file [, file ...]) -//@ ### cat([options,] file_array) -//@ -//@ Available options: -//@ -//@ + `-n`: number all output lines -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var str = cat('file*.txt'); -//@ var str = cat('file1', 'file2'); -//@ var str = cat(['file1', 'file2']); // same as above -//@ ``` -//@ -//@ Returns a string containing the given file, or a concatenated string -//@ containing the files if more than one file is given (a new line character is -//@ introduced between each file). -function _cat(options, files) { - var cat = common.readFromPipe(); - - if (!files && !cat) common.error('no paths given'); - - files = [].slice.call(arguments, 1); - - files.forEach(function (file) { - if (!fs.existsSync(file)) { - common.error('no such file or directory: ' + file); - } else if (common.statFollowLinks(file).isDirectory()) { - common.error(file + ': Is a directory'); - } - - cat += fs.readFileSync(file, 'utf8'); - }); - - if (options.number) { - cat = addNumbers(cat); - } - - return cat; -} -module.exports = _cat; - -function addNumbers(cat) { - var lines = cat.split('\n'); - var lastLine = lines.pop(); - - lines = lines.map(function (line, i) { - return numberedLine(i + 1, line); - }); - - if (lastLine.length) { - lastLine = numberedLine(lines.length + 1, lastLine); - } - lines.push(lastLine); - - return lines.join('\n'); -} - -function numberedLine(n, line) { - // GNU cat use six pad start number + tab. See http://lingrok.org/xref/coreutils/src/cat.c#57 - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart - var number = (' ' + n).slice(-6) + '\t'; - return number + line; -} - - -/***/ }), - -/***/ 4724: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var os = __nccwpck_require__(2037); -var common = __nccwpck_require__(4396); - -common.register('cd', _cd, {}); - -//@ -//@ ### cd([dir]) -//@ -//@ Changes to directory `dir` for the duration of the script. Changes to home -//@ directory if no argument is supplied. -function _cd(options, dir) { - if (!dir) dir = os.homedir(); - - if (dir === '-') { - if (!process.env.OLDPWD) { - common.error('could not find previous directory'); - } else { - dir = process.env.OLDPWD; - } - } - - try { - var curDir = process.cwd(); - process.chdir(dir); - process.env.OLDPWD = curDir; - } catch (e) { - // something went wrong, let's figure out the error - var err; - try { - common.statFollowLinks(dir); // if this succeeds, it must be some sort of file - err = 'not a directory: ' + dir; - } catch (e2) { - err = 'no such file or directory: ' + dir; - } - if (err) common.error(err); - } - return ''; -} -module.exports = _cd; - - -/***/ }), - -/***/ 4457: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); - -var PERMS = (function (base) { - return { - OTHER_EXEC: base.EXEC, - OTHER_WRITE: base.WRITE, - OTHER_READ: base.READ, - - GROUP_EXEC: base.EXEC << 3, - GROUP_WRITE: base.WRITE << 3, - GROUP_READ: base.READ << 3, - - OWNER_EXEC: base.EXEC << 6, - OWNER_WRITE: base.WRITE << 6, - OWNER_READ: base.READ << 6, - - // Literal octal numbers are apparently not allowed in "strict" javascript. - STICKY: parseInt('01000', 8), - SETGID: parseInt('02000', 8), - SETUID: parseInt('04000', 8), - - TYPE_MASK: parseInt('0770000', 8), - }; -}({ - EXEC: 1, - WRITE: 2, - READ: 4, -})); - -common.register('chmod', _chmod, { -}); - -//@ -//@ ### chmod([options,] octal_mode || octal_string, file) -//@ ### chmod([options,] symbolic_mode, file) -//@ -//@ Available options: -//@ -//@ + `-v`: output a diagnostic for every file processed//@ -//@ + `-c`: like verbose, but report only when a change is made//@ -//@ + `-R`: change files and directories recursively//@ -//@ -//@ Examples: -//@ -//@ ```javascript -//@ chmod(755, '/Users/brandon'); -//@ chmod('755', '/Users/brandon'); // same as above -//@ chmod('u+x', '/Users/brandon'); -//@ chmod('-R', 'a-w', '/Users/brandon'); -//@ ``` -//@ -//@ Alters the permissions of a file or directory by either specifying the -//@ absolute permissions in octal form or expressing the changes in symbols. -//@ This command tries to mimic the POSIX behavior as much as possible. -//@ Notable exceptions: -//@ -//@ + In symbolic modes, `a-r` and `-r` are identical. No consideration is -//@ given to the `umask`. -//@ + There is no "quiet" option, since default behavior is to run silent. -function _chmod(options, mode, filePattern) { - if (!filePattern) { - if (options.length > 0 && options.charAt(0) === '-') { - // Special case where the specified file permissions started with - to subtract perms, which - // get picked up by the option parser as command flags. - // If we are down by one argument and options starts with -, shift everything over. - [].unshift.call(arguments, ''); - } else { - common.error('You must specify a file.'); - } - } - - options = common.parseOptions(options, { - 'R': 'recursive', - 'c': 'changes', - 'v': 'verbose', - }); - - filePattern = [].slice.call(arguments, 2); - - var files; - - // TODO: replace this with a call to common.expand() - if (options.recursive) { - files = []; - filePattern.forEach(function addFile(expandedFile) { - var stat = common.statNoFollowLinks(expandedFile); - - if (!stat.isSymbolicLink()) { - files.push(expandedFile); - - if (stat.isDirectory()) { // intentionally does not follow symlinks. - fs.readdirSync(expandedFile).forEach(function (child) { - addFile(expandedFile + '/' + child); - }); - } - } - }); - } else { - files = filePattern; - } - - files.forEach(function innerChmod(file) { - file = path.resolve(file); - if (!fs.existsSync(file)) { - common.error('File not found: ' + file); - } - - // When recursing, don't follow symlinks. - if (options.recursive && common.statNoFollowLinks(file).isSymbolicLink()) { - return; - } - - var stat = common.statFollowLinks(file); - var isDir = stat.isDirectory(); - var perms = stat.mode; - var type = perms & PERMS.TYPE_MASK; - - var newPerms = perms; - - if (isNaN(parseInt(mode, 8))) { - // parse options - mode.split(',').forEach(function (symbolicMode) { - var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i; - var matches = pattern.exec(symbolicMode); - - if (matches) { - var applyTo = matches[1]; - var operator = matches[2]; - var change = matches[3]; - - var changeOwner = applyTo.indexOf('u') !== -1 || applyTo === 'a' || applyTo === ''; - var changeGroup = applyTo.indexOf('g') !== -1 || applyTo === 'a' || applyTo === ''; - var changeOther = applyTo.indexOf('o') !== -1 || applyTo === 'a' || applyTo === ''; - - var changeRead = change.indexOf('r') !== -1; - var changeWrite = change.indexOf('w') !== -1; - var changeExec = change.indexOf('x') !== -1; - var changeExecDir = change.indexOf('X') !== -1; - var changeSticky = change.indexOf('t') !== -1; - var changeSetuid = change.indexOf('s') !== -1; - - if (changeExecDir && isDir) { - changeExec = true; - } - - var mask = 0; - if (changeOwner) { - mask |= (changeRead ? PERMS.OWNER_READ : 0) + (changeWrite ? PERMS.OWNER_WRITE : 0) + (changeExec ? PERMS.OWNER_EXEC : 0) + (changeSetuid ? PERMS.SETUID : 0); - } - if (changeGroup) { - mask |= (changeRead ? PERMS.GROUP_READ : 0) + (changeWrite ? PERMS.GROUP_WRITE : 0) + (changeExec ? PERMS.GROUP_EXEC : 0) + (changeSetuid ? PERMS.SETGID : 0); - } - if (changeOther) { - mask |= (changeRead ? PERMS.OTHER_READ : 0) + (changeWrite ? PERMS.OTHER_WRITE : 0) + (changeExec ? PERMS.OTHER_EXEC : 0); - } - - // Sticky bit is special - it's not tied to user, group or other. - if (changeSticky) { - mask |= PERMS.STICKY; - } - - switch (operator) { - case '+': - newPerms |= mask; - break; - - case '-': - newPerms &= ~mask; - break; - - case '=': - newPerms = type + mask; - - // According to POSIX, when using = to explicitly set the - // permissions, setuid and setgid can never be cleared. - if (common.statFollowLinks(file).isDirectory()) { - newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; - } - break; - default: - common.error('Could not recognize operator: `' + operator + '`'); - } - - if (options.verbose) { - console.log(file + ' -> ' + newPerms.toString(8)); - } - - if (perms !== newPerms) { - if (!options.verbose && options.changes) { - console.log(file + ' -> ' + newPerms.toString(8)); - } - fs.chmodSync(file, newPerms); - perms = newPerms; // for the next round of changes! - } - } else { - common.error('Invalid symbolic mode change: ' + symbolicMode); - } - }); - } else { - // they gave us a full number - newPerms = type + parseInt(mode, 8); - - // POSIX rules are that setuid and setgid can only be added using numeric - // form, but not cleared. - if (common.statFollowLinks(file).isDirectory()) { - newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; - } - - fs.chmodSync(file, newPerms); - } - }); - return ''; -} -module.exports = _chmod; - - -/***/ }), - -/***/ 4396: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; -// Ignore warning about 'new String()' -/* eslint no-new-wrappers: 0 */ - - -var os = __nccwpck_require__(2037); -var fs = __nccwpck_require__(7147); -var glob = __nccwpck_require__(8928); -var shell = __nccwpck_require__(2800); - -var shellMethods = Object.create(shell); - -exports.extend = Object.assign; - -// Check if we're running under electron -var isElectron = Boolean(process.versions.electron); - -// Module globals (assume no execPath by default) -var DEFAULT_CONFIG = { - fatal: false, - globOptions: {}, - maxdepth: 255, - noglob: false, - silent: false, - verbose: false, - execPath: null, - bufLength: 64 * 1024, // 64KB -}; - -var config = { - reset: function () { - Object.assign(this, DEFAULT_CONFIG); - if (!isElectron) { - this.execPath = process.execPath; - } - }, - resetForTesting: function () { - this.reset(); - this.silent = true; - }, -}; - -config.reset(); -exports.config = config; - -// Note: commands should generally consider these as read-only values. -var state = { - error: null, - errorCode: 0, - currentCmd: 'shell.js', -}; -exports.state = state; - -delete process.env.OLDPWD; // initially, there's no previous directory - -// Reliably test if something is any sort of javascript object -function isObject(a) { - return typeof a === 'object' && a !== null; -} -exports.isObject = isObject; - -function log() { - /* istanbul ignore next */ - if (!config.silent) { - console.error.apply(console, arguments); - } -} -exports.log = log; - -// Converts strings to be equivalent across all platforms. Primarily responsible -// for making sure we use '/' instead of '\' as path separators, but this may be -// expanded in the future if necessary -function convertErrorOutput(msg) { - if (typeof msg !== 'string') { - throw new TypeError('input must be a string'); - } - return msg.replace(/\\/g, '/'); -} -exports.convertErrorOutput = convertErrorOutput; - -// Shows error message. Throws if config.fatal is true -function error(msg, _code, options) { - // Validate input - if (typeof msg !== 'string') throw new Error('msg must be a string'); - - var DEFAULT_OPTIONS = { - continue: false, - code: 1, - prefix: state.currentCmd + ': ', - silent: false, - }; - - if (typeof _code === 'number' && isObject(options)) { - options.code = _code; - } else if (isObject(_code)) { // no 'code' - options = _code; - } else if (typeof _code === 'number') { // no 'options' - options = { code: _code }; - } else if (typeof _code !== 'number') { // only 'msg' - options = {}; - } - options = Object.assign({}, DEFAULT_OPTIONS, options); - - if (!state.errorCode) state.errorCode = options.code; - - var logEntry = convertErrorOutput(options.prefix + msg); - state.error = state.error ? state.error + '\n' : ''; - state.error += logEntry; - - // Throw an error, or log the entry - if (config.fatal) throw new Error(logEntry); - if (msg.length > 0 && !options.silent) log(logEntry); - - if (!options.continue) { - throw { - msg: 'earlyExit', - retValue: (new ShellString('', state.error, state.errorCode)), - }; - } -} -exports.error = error; - -//@ -//@ ### ShellString(str) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var foo = ShellString('hello world'); -//@ ``` -//@ -//@ Turns a regular string into a string-like object similar to what each -//@ command returns. This has special methods, like `.to()` and `.toEnd()`. -function ShellString(stdout, stderr, code) { - var that; - if (stdout instanceof Array) { - that = stdout; - that.stdout = stdout.join('\n'); - if (stdout.length > 0) that.stdout += '\n'; - } else { - that = new String(stdout); - that.stdout = stdout; - } - that.stderr = stderr; - that.code = code; - // A list of all commands that can appear on the right-hand side of a pipe - // (populated by calls to common.wrap()) - pipeMethods.forEach(function (cmd) { - that[cmd] = shellMethods[cmd].bind(that); - }); - return that; -} - -exports.ShellString = ShellString; - -// Returns {'alice': true, 'bob': false} when passed a string and dictionary as follows: -// parseOptions('-a', {'a':'alice', 'b':'bob'}); -// Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form: -// parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'}); -// Throws an error when passed a string that does not start with '-': -// parseOptions('a', {'a':'alice'}); // throws -function parseOptions(opt, map, errorOptions) { - // Validate input - if (typeof opt !== 'string' && !isObject(opt)) { - throw new Error('options must be strings or key-value pairs'); - } else if (!isObject(map)) { - throw new Error('parseOptions() internal error: map must be an object'); - } else if (errorOptions && !isObject(errorOptions)) { - throw new Error('parseOptions() internal error: errorOptions must be object'); - } - - if (opt === '--') { - // This means there are no options. - return {}; - } - - // All options are false by default - var options = {}; - Object.keys(map).forEach(function (letter) { - var optName = map[letter]; - if (optName[0] !== '!') { - options[optName] = false; - } - }); - - if (opt === '') return options; // defaults - - if (typeof opt === 'string') { - if (opt[0] !== '-') { - throw new Error("Options string must start with a '-'"); - } - - // e.g. chars = ['R', 'f'] - var chars = opt.slice(1).split(''); - - chars.forEach(function (c) { - if (c in map) { - var optionName = map[c]; - if (optionName[0] === '!') { - options[optionName.slice(1)] = false; - } else { - options[optionName] = true; - } - } else { - error('option not recognized: ' + c, errorOptions || {}); - } - }); - } else { // opt is an Object - Object.keys(opt).forEach(function (key) { - // key is a string of the form '-r', '-d', etc. - var c = key[1]; - if (c in map) { - var optionName = map[c]; - options[optionName] = opt[key]; // assign the given value - } else { - error('option not recognized: ' + c, errorOptions || {}); - } - }); - } - return options; -} -exports.parseOptions = parseOptions; - -// Expands wildcards with matching (ie. existing) file names. -// For example: -// expand(['file*.js']) = ['file1.js', 'file2.js', ...] -// (if the files 'file1.js', 'file2.js', etc, exist in the current dir) -function expand(list) { - if (!Array.isArray(list)) { - throw new TypeError('must be an array'); - } - var expanded = []; - list.forEach(function (listEl) { - // Don't expand non-strings - if (typeof listEl !== 'string') { - expanded.push(listEl); - } else { - var ret; - try { - ret = glob.sync(listEl, config.globOptions); - // if nothing matched, interpret the string literally - ret = ret.length > 0 ? ret : [listEl]; - } catch (e) { - // if glob fails, interpret the string literally - ret = [listEl]; - } - expanded = expanded.concat(ret); - } - }); - return expanded; -} -exports.expand = expand; - -// Normalizes Buffer creation, using Buffer.alloc if possible. -// Also provides a good default buffer length for most use cases. -var buffer = typeof Buffer.alloc === 'function' ? - function (len) { - return Buffer.alloc(len || config.bufLength); - } : - function (len) { - return new Buffer(len || config.bufLength); - }; -exports.buffer = buffer; - -// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e. -// file can be unlinked even if it's read-only, see https://github.com/joyent/node/issues/3006 -function unlinkSync(file) { - try { - fs.unlinkSync(file); - } catch (e) { - // Try to override file permission - /* istanbul ignore next */ - if (e.code === 'EPERM') { - fs.chmodSync(file, '0666'); - fs.unlinkSync(file); - } else { - throw e; - } - } -} -exports.unlinkSync = unlinkSync; - -// wrappers around common.statFollowLinks and common.statNoFollowLinks that clarify intent -// and improve readability -function statFollowLinks() { - return fs.statSync.apply(fs, arguments); -} -exports.statFollowLinks = statFollowLinks; - -function statNoFollowLinks() { - return fs.lstatSync.apply(fs, arguments); -} -exports.statNoFollowLinks = statNoFollowLinks; - -// e.g. 'shelljs_a5f185d0443ca...' -function randomFileName() { - function randomHash(count) { - if (count === 1) { - return parseInt(16 * Math.random(), 10).toString(16); - } - var hash = ''; - for (var i = 0; i < count; i++) { - hash += randomHash(1); - } - return hash; - } - - return 'shelljs_' + randomHash(20); -} -exports.randomFileName = randomFileName; - -// Common wrapper for all Unix-like commands that performs glob expansion, -// command-logging, and other nice things -function wrap(cmd, fn, options) { - options = options || {}; - return function () { - var retValue = null; - - state.currentCmd = cmd; - state.error = null; - state.errorCode = 0; - - try { - var args = [].slice.call(arguments, 0); - - // Log the command to stderr, if appropriate - if (config.verbose) { - console.error.apply(console, [cmd].concat(args)); - } - - // If this is coming from a pipe, let's set the pipedValue (otherwise, set - // it to the empty string) - state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : ''; - - if (options.unix === false) { // this branch is for exec() - retValue = fn.apply(this, args); - } else { // and this branch is for everything else - if (isObject(args[0]) && args[0].constructor.name === 'Object') { - // a no-op, allowing the syntax `touch({'-r': file}, ...)` - } else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') { - args.unshift(''); // only add dummy option if '-option' not already present - } - - // flatten out arrays that are arguments, to make the syntax: - // `cp([file1, file2, file3], dest);` - // equivalent to: - // `cp(file1, file2, file3, dest);` - args = args.reduce(function (accum, cur) { - if (Array.isArray(cur)) { - return accum.concat(cur); - } - accum.push(cur); - return accum; - }, []); - - // Convert ShellStrings (basically just String objects) to regular strings - args = args.map(function (arg) { - if (isObject(arg) && arg.constructor.name === 'String') { - return arg.toString(); - } - return arg; - }); - - // Expand the '~' if appropriate - var homeDir = os.homedir(); - args = args.map(function (arg) { - if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') { - return arg.replace(/^~/, homeDir); - } - return arg; - }); - - // Perform glob-expansion on all arguments after globStart, but preserve - // the arguments before it (like regexes for sed and grep) - if (!config.noglob && options.allowGlobbing === true) { - args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart))); - } - - try { - // parse options if options are provided - if (isObject(options.cmdOptions)) { - args[0] = parseOptions(args[0], options.cmdOptions); - } - - retValue = fn.apply(this, args); - } catch (e) { - /* istanbul ignore else */ - if (e.msg === 'earlyExit') { - retValue = e.retValue; - } else { - throw e; // this is probably a bug that should be thrown up the call stack - } - } - } - } catch (e) { - /* istanbul ignore next */ - if (!state.error) { - // If state.error hasn't been set it's an error thrown by Node, not us - probably a bug... - e.name = 'ShellJSInternalError'; - throw e; - } - if (config.fatal) throw e; - } - - if (options.wrapOutput && - (typeof retValue === 'string' || Array.isArray(retValue))) { - retValue = new ShellString(retValue, state.error, state.errorCode); - } - - state.currentCmd = 'shell.js'; - return retValue; - }; -} // wrap -exports.wrap = wrap; - -// This returns all the input that is piped into the current command (or the -// empty string, if this isn't on the right-hand side of a pipe -function _readFromPipe() { - return state.pipedValue; -} -exports.readFromPipe = _readFromPipe; - -var DEFAULT_WRAP_OPTIONS = { - allowGlobbing: true, - canReceivePipe: false, - cmdOptions: null, - globStart: 1, - pipeOnly: false, - wrapOutput: true, - unix: true, -}; - -// This is populated during plugin registration -var pipeMethods = []; - -// Register a new ShellJS command -function _register(name, implementation, wrapOptions) { - wrapOptions = wrapOptions || {}; - - // Validate options - Object.keys(wrapOptions).forEach(function (option) { - if (!DEFAULT_WRAP_OPTIONS.hasOwnProperty(option)) { - throw new Error("Unknown option '" + option + "'"); - } - if (typeof wrapOptions[option] !== typeof DEFAULT_WRAP_OPTIONS[option]) { - throw new TypeError("Unsupported type '" + typeof wrapOptions[option] + - "' for option '" + option + "'"); - } - }); - - // If an option isn't specified, use the default - wrapOptions = Object.assign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); - - if (shell.hasOwnProperty(name)) { - throw new Error('Command `' + name + '` already exists'); - } - - if (wrapOptions.pipeOnly) { - wrapOptions.canReceivePipe = true; - shellMethods[name] = wrap(name, implementation, wrapOptions); - } else { - shell[name] = wrap(name, implementation, wrapOptions); - } - - if (wrapOptions.canReceivePipe) { - pipeMethods.push(name); - } -} -exports.register = _register; - - -/***/ }), - -/***/ 9926: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); -var common = __nccwpck_require__(4396); - -common.register('cp', _cp, { - cmdOptions: { - 'f': '!no_force', - 'n': 'no_force', - 'u': 'update', - 'R': 'recursive', - 'r': 'recursive', - 'L': 'followsymlink', - 'P': 'noFollowsymlink', - }, - wrapOutput: false, -}); - -// Buffered file copy, synchronous -// (Using readFileSync() + writeFileSync() could easily cause a memory overflow -// with large files) -function copyFileSync(srcFile, destFile, options) { - if (!fs.existsSync(srcFile)) { - common.error('copyFileSync: no such file or directory: ' + srcFile); - } - - var isWindows = process.platform === 'win32'; - - // Check the mtimes of the files if the '-u' flag is provided - try { - if (options.update && common.statFollowLinks(srcFile).mtime < fs.statSync(destFile).mtime) { - return; - } - } catch (e) { - // If we're here, destFile probably doesn't exist, so just do a normal copy - } - - if (common.statNoFollowLinks(srcFile).isSymbolicLink() && !options.followsymlink) { - try { - common.statNoFollowLinks(destFile); - common.unlinkSync(destFile); // re-link it - } catch (e) { - // it doesn't exist, so no work needs to be done - } - - var symlinkFull = fs.readlinkSync(srcFile); - fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); - } else { - var buf = common.buffer(); - var bufLength = buf.length; - var bytesRead = bufLength; - var pos = 0; - var fdr = null; - var fdw = null; - - try { - fdr = fs.openSync(srcFile, 'r'); - } catch (e) { - /* istanbul ignore next */ - common.error('copyFileSync: could not read src file (' + srcFile + ')'); - } - - try { - fdw = fs.openSync(destFile, 'w'); - } catch (e) { - /* istanbul ignore next */ - common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile); - } - - while (bytesRead === bufLength) { - bytesRead = fs.readSync(fdr, buf, 0, bufLength, pos); - fs.writeSync(fdw, buf, 0, bytesRead); - pos += bytesRead; - } - - fs.closeSync(fdr); - fs.closeSync(fdw); - - fs.chmodSync(destFile, common.statFollowLinks(srcFile).mode); - } -} - -// Recursively copies 'sourceDir' into 'destDir' -// Adapted from https://github.com/ryanmcgrath/wrench-js -// -// Copyright (c) 2010 Ryan McGrath -// Copyright (c) 2012 Artur Adib -// -// Licensed under the MIT License -// http://www.opensource.org/licenses/mit-license.php -function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { - if (!opts) opts = {}; - - // Ensure there is not a run away recursive copy - if (currentDepth >= common.config.maxdepth) return; - currentDepth++; - - var isWindows = process.platform === 'win32'; - - // Create the directory where all our junk is moving to; read the mode of the - // source directory and mirror it - try { - fs.mkdirSync(destDir); - } catch (e) { - // if the directory already exists, that's okay - if (e.code !== 'EEXIST') throw e; - } - - var files = fs.readdirSync(sourceDir); - - for (var i = 0; i < files.length; i++) { - var srcFile = sourceDir + '/' + files[i]; - var destFile = destDir + '/' + files[i]; - var srcFileStat = common.statNoFollowLinks(srcFile); - - var symlinkFull; - if (opts.followsymlink) { - if (cpcheckcycle(sourceDir, srcFile)) { - // Cycle link found. - console.error('Cycle link found.'); - symlinkFull = fs.readlinkSync(srcFile); - fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); - continue; - } - } - if (srcFileStat.isDirectory()) { - /* recursion this thing right on back. */ - cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); - } else if (srcFileStat.isSymbolicLink() && !opts.followsymlink) { - symlinkFull = fs.readlinkSync(srcFile); - try { - common.statNoFollowLinks(destFile); - common.unlinkSync(destFile); // re-link it - } catch (e) { - // it doesn't exist, so no work needs to be done - } - fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); - } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) { - srcFileStat = common.statFollowLinks(srcFile); - if (srcFileStat.isDirectory()) { - cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); - } else { - copyFileSync(srcFile, destFile, opts); - } - } else { - /* At this point, we've hit a file actually worth copying... so copy it on over. */ - if (fs.existsSync(destFile) && opts.no_force) { - common.log('skipping existing file: ' + files[i]); - } else { - copyFileSync(srcFile, destFile, opts); - } - } - } // for files - - // finally change the mode for the newly created directory (otherwise, we - // couldn't add files to a read-only directory). - var checkDir = common.statFollowLinks(sourceDir); - fs.chmodSync(destDir, checkDir.mode); -} // cpdirSyncRecursive - -// Checks if cureent file was created recently -function checkRecentCreated(sources, index) { - var lookedSource = sources[index]; - return sources.slice(0, index).some(function (src) { - return path.basename(src) === path.basename(lookedSource); - }); -} - -function cpcheckcycle(sourceDir, srcFile) { - var srcFileStat = common.statNoFollowLinks(srcFile); - if (srcFileStat.isSymbolicLink()) { - // Do cycle check. For example: - // $ mkdir -p 1/2/3/4 - // $ cd 1/2/3/4 - // $ ln -s ../../3 link - // $ cd ../../../.. - // $ cp -RL 1 copy - var cyclecheck = common.statFollowLinks(srcFile); - if (cyclecheck.isDirectory()) { - var sourcerealpath = fs.realpathSync(sourceDir); - var symlinkrealpath = fs.realpathSync(srcFile); - var re = new RegExp(symlinkrealpath); - if (re.test(sourcerealpath)) { - return true; - } - } - } - return false; -} - -//@ -//@ ### cp([options,] source [, source ...], dest) -//@ ### cp([options,] source_array, dest) -//@ -//@ Available options: -//@ -//@ + `-f`: force (default behavior) -//@ + `-n`: no-clobber -//@ + `-u`: only copy if `source` is newer than `dest` -//@ + `-r`, `-R`: recursive -//@ + `-L`: follow symlinks -//@ + `-P`: don't follow symlinks -//@ -//@ Examples: -//@ -//@ ```javascript -//@ cp('file1', 'dir1'); -//@ cp('-R', 'path/to/dir/', '~/newCopy/'); -//@ cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp'); -//@ cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above -//@ ``` -//@ -//@ Copies files. -function _cp(options, sources, dest) { - // If we're missing -R, it actually implies -L (unless -P is explicit) - if (options.followsymlink) { - options.noFollowsymlink = false; - } - if (!options.recursive && !options.noFollowsymlink) { - options.followsymlink = true; - } - - // Get sources, dest - if (arguments.length < 3) { - common.error('missing and/or '); - } else { - sources = [].slice.call(arguments, 1, arguments.length - 1); - dest = arguments[arguments.length - 1]; - } - - var destExists = fs.existsSync(dest); - var destStat = destExists && common.statFollowLinks(dest); - - // Dest is not existing dir, but multiple sources given - if ((!destExists || !destStat.isDirectory()) && sources.length > 1) { - common.error('dest is not a directory (too many sources)'); - } - - // Dest is an existing file, but -n is given - if (destExists && destStat.isFile() && options.no_force) { - return new common.ShellString('', '', 0); - } - - sources.forEach(function (src, srcIndex) { - if (!fs.existsSync(src)) { - if (src === '') src = "''"; // if src was empty string, display empty string - common.error('no such file or directory: ' + src, { continue: true }); - return; // skip file - } - var srcStat = common.statFollowLinks(src); - if (!options.noFollowsymlink && srcStat.isDirectory()) { - if (!options.recursive) { - // Non-Recursive - common.error("omitting directory '" + src + "'", { continue: true }); - } else { - // Recursive - // 'cp /a/source dest' should create 'source' in 'dest' - var newDest = (destStat && destStat.isDirectory()) ? - path.join(dest, path.basename(src)) : - dest; - - try { - common.statFollowLinks(path.dirname(dest)); - cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink }); - } catch (e) { - /* istanbul ignore next */ - common.error("cannot create directory '" + dest + "': No such file or directory"); - } - } - } else { - // If here, src is a file - - // When copying to '/path/dir': - // thisDest = '/path/dir/file1' - var thisDest = dest; - if (destStat && destStat.isDirectory()) { - thisDest = path.normalize(dest + '/' + path.basename(src)); - } - - var thisDestExists = fs.existsSync(thisDest); - if (thisDestExists && checkRecentCreated(sources, srcIndex)) { - // cannot overwrite file created recently in current execution, but we want to continue copying other files - if (!options.no_force) { - common.error("will not overwrite just-created '" + thisDest + "' with '" + src + "'", { continue: true }); - } - return; - } - - if (thisDestExists && options.no_force) { - return; // skip file - } - - if (path.relative(src, thisDest) === '') { - // a file cannot be copied to itself, but we want to continue copying other files - common.error("'" + thisDest + "' and '" + src + "' are the same file", { continue: true }); - return; - } - - copyFileSync(src, thisDest, options); - } - }); // forEach(src) - - return new common.ShellString('', common.state.error, common.state.errorCode); -} -module.exports = _cp; - - -/***/ }), - -/***/ 5417: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var _cd = __nccwpck_require__(4724); -var path = __nccwpck_require__(1017); - -common.register('dirs', _dirs, { - wrapOutput: false, -}); -common.register('pushd', _pushd, { - wrapOutput: false, -}); -common.register('popd', _popd, { - wrapOutput: false, -}); - -// Pushd/popd/dirs internals -var _dirStack = []; - -function _isStackIndex(index) { - return (/^[\-+]\d+$/).test(index); -} - -function _parseStackIndex(index) { - if (_isStackIndex(index)) { - if (Math.abs(index) < _dirStack.length + 1) { // +1 for pwd - return (/^-/).test(index) ? Number(index) - 1 : Number(index); - } - common.error(index + ': directory stack index out of range'); - } else { - common.error(index + ': invalid number'); - } -} - -function _actualDirStack() { - return [process.cwd()].concat(_dirStack); -} - -//@ -//@ ### pushd([options,] [dir | '-N' | '+N']) -//@ -//@ Available options: -//@ -//@ + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. -//@ + `-q`: Supresses output to the console. -//@ -//@ Arguments: -//@ -//@ + `dir`: Sets the current working directory to the top of the stack, then executes the equivalent of `cd dir`. -//@ + `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. -//@ + `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. -//@ -//@ Examples: -//@ -//@ ```javascript -//@ // process.cwd() === '/usr' -//@ pushd('/etc'); // Returns /etc /usr -//@ pushd('+1'); // Returns /usr /etc -//@ ``` -//@ -//@ Save the current directory on the top of the directory stack and then `cd` to `dir`. With no arguments, `pushd` exchanges the top two directories. Returns an array of paths in the stack. -function _pushd(options, dir) { - if (_isStackIndex(options)) { - dir = options; - options = ''; - } - - options = common.parseOptions(options, { - 'n': 'no-cd', - 'q': 'quiet', - }); - - var dirs = _actualDirStack(); - - if (dir === '+0') { - return dirs; // +0 is a noop - } else if (!dir) { - if (dirs.length > 1) { - dirs = dirs.splice(1, 1).concat(dirs); - } else { - return common.error('no other directory'); - } - } else if (_isStackIndex(dir)) { - var n = _parseStackIndex(dir); - dirs = dirs.slice(n).concat(dirs.slice(0, n)); - } else { - if (options['no-cd']) { - dirs.splice(1, 0, dir); - } else { - dirs.unshift(dir); - } - } - - if (options['no-cd']) { - dirs = dirs.slice(1); - } else { - dir = path.resolve(dirs.shift()); - _cd('', dir); - } - - _dirStack = dirs; - return _dirs(options.quiet ? '-q' : ''); -} -exports.pushd = _pushd; - -//@ -//@ -//@ ### popd([options,] ['-N' | '+N']) -//@ -//@ Available options: -//@ -//@ + `-n`: Suppress the normal directory change when removing directories from the stack, so that only the stack is manipulated. -//@ + `-q`: Supresses output to the console. -//@ -//@ Arguments: -//@ -//@ + `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero. -//@ + `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero. -//@ -//@ Examples: -//@ -//@ ```javascript -//@ echo(process.cwd()); // '/usr' -//@ pushd('/etc'); // '/etc /usr' -//@ echo(process.cwd()); // '/etc' -//@ popd(); // '/usr' -//@ echo(process.cwd()); // '/usr' -//@ ``` -//@ -//@ When no arguments are given, `popd` removes the top directory from the stack and performs a `cd` to the new top directory. The elements are numbered from 0, starting at the first directory listed with dirs (i.e., `popd` is equivalent to `popd +0`). Returns an array of paths in the stack. -function _popd(options, index) { - if (_isStackIndex(options)) { - index = options; - options = ''; - } - - options = common.parseOptions(options, { - 'n': 'no-cd', - 'q': 'quiet', - }); - - if (!_dirStack.length) { - return common.error('directory stack empty'); - } - - index = _parseStackIndex(index || '+0'); - - if (options['no-cd'] || index > 0 || _dirStack.length + index === 0) { - index = index > 0 ? index - 1 : index; - _dirStack.splice(index, 1); - } else { - var dir = path.resolve(_dirStack.shift()); - _cd('', dir); - } - - return _dirs(options.quiet ? '-q' : ''); -} -exports.popd = _popd; - -//@ -//@ -//@ ### dirs([options | '+N' | '-N']) -//@ -//@ Available options: -//@ -//@ + `-c`: Clears the directory stack by deleting all of the elements. -//@ + `-q`: Supresses output to the console. -//@ -//@ Arguments: -//@ -//@ + `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. -//@ + `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. -//@ -//@ Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if `+N` or `-N` was specified. -//@ -//@ See also: `pushd`, `popd` -function _dirs(options, index) { - if (_isStackIndex(options)) { - index = options; - options = ''; - } - - options = common.parseOptions(options, { - 'c': 'clear', - 'q': 'quiet', - }); - - if (options.clear) { - _dirStack = []; - return _dirStack; - } - - var stack = _actualDirStack(); - - if (index) { - index = _parseStackIndex(index); - - if (index < 0) { - index = stack.length + index; - } - - if (!options.quiet) { - common.log(stack[index]); - } - return stack[index]; - } - - if (!options.quiet) { - common.log(stack.join(' ')); - } - - return stack; -} -exports.dirs = _dirs; - - -/***/ }), - -/***/ 8484: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var format = (__nccwpck_require__(3837).format); - -var common = __nccwpck_require__(4396); - -common.register('echo', _echo, { - allowGlobbing: false, -}); - -//@ -//@ ### echo([options,] string [, string ...]) -//@ -//@ Available options: -//@ -//@ + `-e`: interpret backslash escapes (default) -//@ + `-n`: remove trailing newline from output -//@ -//@ Examples: -//@ -//@ ```javascript -//@ echo('hello world'); -//@ var str = echo('hello world'); -//@ echo('-n', 'no newline at end'); -//@ ``` -//@ -//@ Prints `string` to stdout, and returns string with additional utility methods -//@ like `.to()`. -function _echo(opts) { - // allow strings starting with '-', see issue #20 - var messages = [].slice.call(arguments, opts ? 0 : 1); - var options = {}; - - // If the first argument starts with '-', parse it as options string. - // If parseOptions throws, it wasn't an options string. - try { - options = common.parseOptions(messages[0], { - 'e': 'escapes', - 'n': 'no_newline', - }, { - silent: true, - }); - - // Allow null to be echoed - if (messages[0]) { - messages.shift(); - } - } catch (_) { - // Clear out error if an error occurred - common.state.error = null; - } - - var output = format.apply(null, messages); - - // Add newline if -n is not passed. - if (!options.no_newline) { - output += '\n'; - } - - process.stdout.write(output); - - return output; -} - -module.exports = _echo; - - -/***/ }), - -/***/ 6147: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); - -//@ -//@ ### error() -//@ -//@ Tests if error occurred in the last command. Returns a truthy value if an -//@ error returned, or a falsy value otherwise. -//@ -//@ **Note**: do not rely on the -//@ return value to be an error message. If you need the last error message, use -//@ the `.stderr` attribute from the last command's return value instead. -function error() { - return common.state.error; -} -module.exports = error; - - -/***/ }), - -/***/ 2020: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -/* module decorator */ module = __nccwpck_require__.nmd(module); -if (require.main !== module) { - throw new Error('This file should not be required'); -} - -var childProcess = __nccwpck_require__(2081); -var fs = __nccwpck_require__(7147); - -var paramFilePath = process.argv[2]; - -var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); -var params = JSON.parse(serializedParams); - -var cmd = params.command; -var execOptions = params.execOptions; -var pipe = params.pipe; -var stdoutFile = params.stdoutFile; -var stderrFile = params.stderrFile; - -var c = childProcess.exec(cmd, execOptions, function (err) { - if (!err) { - process.exitCode = 0; - } else if (err.code === undefined) { - process.exitCode = 1; - } else { - process.exitCode = err.code; - } -}); - -var stdoutStream = fs.createWriteStream(stdoutFile); -var stderrStream = fs.createWriteStream(stderrFile); - -c.stdout.pipe(stdoutStream); -c.stderr.pipe(stderrStream); -c.stdout.pipe(process.stdout); -c.stderr.pipe(process.stderr); - -if (pipe) { - c.stdin.end(pipe); -} - - -/***/ }), - -/***/ 3378: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var _tempDir = (__nccwpck_require__(2979).tempDir); -var _pwd = __nccwpck_require__(6214); -var path = __nccwpck_require__(1017); -var fs = __nccwpck_require__(7147); -var child = __nccwpck_require__(2081); - -var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024; -var DEFAULT_ERROR_CODE = 1; - -common.register('exec', _exec, { - unix: false, - canReceivePipe: true, - wrapOutput: false, -}); - -// We use this function to run `exec` synchronously while also providing realtime -// output. -function execSync(cmd, opts, pipe) { - if (!common.config.execPath) { - common.error('Unable to find a path to the node binary. Please manually set config.execPath'); - } - - var tempDir = _tempDir(); - var paramsFile = path.resolve(tempDir + '/' + common.randomFileName()); - var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); - var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); - - opts = common.extend({ - silent: common.config.silent, - cwd: _pwd().toString(), - env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE, - encoding: 'utf8', - }, opts); - - if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile); - if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); - if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); - - opts.cwd = path.resolve(opts.cwd); - - var paramsToSerialize = { - command: cmd, - execOptions: opts, - pipe: pipe, - stdoutFile: stdoutFile, - stderrFile: stderrFile, - }; - - // Create the files and ensure these are locked down (for read and write) to - // the current user. The main concerns here are: - // - // * If we execute a command which prints sensitive output, then - // stdoutFile/stderrFile must not be readable by other users. - // * paramsFile must not be readable by other users, or else they can read it - // to figure out the path for stdoutFile/stderrFile and create these first - // (locked down to their own access), which will crash exec() when it tries - // to write to the files. - function writeFileLockedDown(filePath, data) { - fs.writeFileSync(filePath, data, { - encoding: 'utf8', - mode: parseInt('600', 8), - }); - } - writeFileLockedDown(stdoutFile, ''); - writeFileLockedDown(stderrFile, ''); - writeFileLockedDown(paramsFile, JSON.stringify(paramsToSerialize)); - - var execArgs = [ - __nccwpck_require__.ab + "exec-child.js", - paramsFile, - ]; - - /* istanbul ignore else */ - if (opts.silent) { - opts.stdio = 'ignore'; - } else { - opts.stdio = [0, 1, 2]; - } - - var code = 0; - - // Welcome to the future - try { - // Bad things if we pass in a `shell` option to child_process.execFileSync, - // so we need to explicitly remove it here. - delete opts.shell; - - child.execFileSync(common.config.execPath, execArgs, opts); - } catch (e) { - // Commands with non-zero exit code raise an exception. - code = e.status || DEFAULT_ERROR_CODE; - } - - // fs.readFileSync uses buffer encoding by default, so call - // it without the encoding option if the encoding is 'buffer'. - // Also, if the exec timeout is too short for node to start up, - // the files will not be created, so these calls will throw. - var stdout = ''; - var stderr = ''; - if (opts.encoding === 'buffer') { - stdout = fs.readFileSync(stdoutFile); - stderr = fs.readFileSync(stderrFile); - } else { - stdout = fs.readFileSync(stdoutFile, opts.encoding); - stderr = fs.readFileSync(stderrFile, opts.encoding); - } - - // No biggie if we can't erase the files now -- they're in a temp dir anyway - // and we locked down permissions (see the note above). - try { common.unlinkSync(paramsFile); } catch (e) {} - try { common.unlinkSync(stderrFile); } catch (e) {} - try { common.unlinkSync(stdoutFile); } catch (e) {} - - if (code !== 0) { - // Note: `silent` should be unconditionally true to avoid double-printing - // the command's stderr, and to avoid printing any stderr when the user has - // set `shell.config.silent`. - common.error(stderr, code, { continue: true, silent: true }); - } - var obj = common.ShellString(stdout, stderr, code); - return obj; -} // execSync() - -// Wrapper around exec() to enable echoing output to console in real time -function execAsync(cmd, opts, pipe, callback) { - opts = common.extend({ - silent: common.config.silent, - cwd: _pwd().toString(), - env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE, - encoding: 'utf8', - }, opts); - - var c = child.exec(cmd, opts, function (err, stdout, stderr) { - if (callback) { - if (!err) { - callback(0, stdout, stderr); - } else if (err.code === undefined) { - // See issue #536 - /* istanbul ignore next */ - callback(1, stdout, stderr); - } else { - callback(err.code, stdout, stderr); - } - } - }); - - if (pipe) c.stdin.end(pipe); - - if (!opts.silent) { - c.stdout.pipe(process.stdout); - c.stderr.pipe(process.stderr); - } - - return c; -} - -//@ -//@ ### exec(command [, options] [, callback]) -//@ -//@ Available options: -//@ -//@ + `async`: Asynchronous execution. If a callback is provided, it will be set to -//@ `true`, regardless of the passed value (default: `false`). -//@ + `silent`: Do not echo program output to console (default: `false`). -//@ + `encoding`: Character encoding to use. Affects the values returned to stdout and stderr, and -//@ what is written to stdout and stderr when not in silent mode (default: `'utf8'`). -//@ + and any option available to Node.js's -//@ [`child_process.exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var version = exec('node --version', {silent:true}).stdout; -//@ -//@ var child = exec('some_long_running_process', {async:true}); -//@ child.stdout.on('data', function(data) { -//@ /* ... do something with data ... */ -//@ }); -//@ -//@ exec('some_long_running_process', function(code, stdout, stderr) { -//@ console.log('Exit code:', code); -//@ console.log('Program output:', stdout); -//@ console.log('Program stderr:', stderr); -//@ }); -//@ ``` -//@ -//@ Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous -//@ mode, this returns a `ShellString` (compatible with ShellJS v0.6.x, which returns an object -//@ of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process -//@ object, and the `callback` receives the arguments `(code, stdout, stderr)`. -//@ -//@ Not seeing the behavior you want? `exec()` runs everything through `sh` -//@ by default (or `cmd.exe` on Windows), which differs from `bash`. If you -//@ need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. -function _exec(command, options, callback) { - options = options || {}; - if (!command) common.error('must specify command'); - - var pipe = common.readFromPipe(); - - // Callback is defined instead of options. - if (typeof options === 'function') { - callback = options; - options = { async: true }; - } - - // Callback is defined with options. - if (typeof options === 'object' && typeof callback === 'function') { - options.async = true; - } - - options = common.extend({ - silent: common.config.silent, - async: false, - }, options); - - if (options.async) { - return execAsync(command, options, pipe, callback); - } else { - return execSync(command, options, pipe); - } -} -module.exports = _exec; - - -/***/ }), - -/***/ 4385: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var path = __nccwpck_require__(1017); -var common = __nccwpck_require__(4396); -var _ls = __nccwpck_require__(7513); - -common.register('find', _find, {}); - -//@ -//@ ### find(path [, path ...]) -//@ ### find(path_array) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ find('src', 'lib'); -//@ find(['src', 'lib']); // same as above -//@ find('.').filter(function(file) { return file.match(/\.js$/); }); -//@ ``` -//@ -//@ Returns array of all files (however deep) in the given paths. -//@ -//@ The main difference from `ls('-R', path)` is that the resulting file names -//@ include the base directories (e.g., `lib/resources/file1` instead of just `file1`). -function _find(options, paths) { - if (!paths) { - common.error('no path specified'); - } else if (typeof paths === 'string') { - paths = [].slice.call(arguments, 1); - } - - var list = []; - - function pushFile(file) { - if (process.platform === 'win32') { - file = file.replace(/\\/g, '/'); - } - list.push(file); - } - - // why not simply do `ls('-R', paths)`? because the output wouldn't give the base dirs - // to get the base dir in the output, we need instead `ls('-R', 'dir/*')` for every directory - - paths.forEach(function (file) { - var stat; - try { - stat = common.statFollowLinks(file); - } catch (e) { - common.error('no such file or directory: ' + file); - } - - pushFile(file); - - if (stat.isDirectory()) { - _ls({ recursive: true, all: true }, file).forEach(function (subfile) { - pushFile(path.join(file, subfile)); - }); - } - }); - - return list; -} -module.exports = _find; - - -/***/ }), - -/***/ 415: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('grep', _grep, { - globStart: 2, // don't glob-expand the regex - canReceivePipe: true, - cmdOptions: { - 'v': 'inverse', - 'l': 'nameOnly', - 'i': 'ignoreCase', - }, -}); - -//@ -//@ ### grep([options,] regex_filter, file [, file ...]) -//@ ### grep([options,] regex_filter, file_array) -//@ -//@ Available options: -//@ -//@ + `-v`: Invert `regex_filter` (only print non-matching lines). -//@ + `-l`: Print only filenames of matching files. -//@ + `-i`: Ignore case. -//@ -//@ Examples: -//@ -//@ ```javascript -//@ grep('-v', 'GLOBAL_VARIABLE', '*.js'); -//@ grep('GLOBAL_VARIABLE', '*.js'); -//@ ``` -//@ -//@ Reads input string from given files and returns a string containing all lines of the -//@ file that match the given `regex_filter`. -function _grep(options, regex, files) { - // Check if this is coming from a pipe - var pipe = common.readFromPipe(); - - if (!files && !pipe) common.error('no paths given', 2); - - files = [].slice.call(arguments, 2); - - if (pipe) { - files.unshift('-'); - } - - var grep = []; - if (options.ignoreCase) { - regex = new RegExp(regex, 'i'); - } - files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, 2, { continue: true }); - return; - } - - var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - if (options.nameOnly) { - if (contents.match(regex)) { - grep.push(file); - } - } else { - var lines = contents.split('\n'); - lines.forEach(function (line) { - var matched = line.match(regex); - if ((options.inverse && !matched) || (!options.inverse && matched)) { - grep.push(line); - } - }); - } - }); - - return grep.join('\n') + '\n'; -} -module.exports = _grep; - - -/***/ }), - -/***/ 4049: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('head', _head, { - canReceivePipe: true, - cmdOptions: { - 'n': 'numLines', - }, -}); - -// Reads |numLines| lines or the entire file, whichever is less. -function readSomeLines(file, numLines) { - var buf = common.buffer(); - var bufLength = buf.length; - var bytesRead = bufLength; - var pos = 0; - - var fdr = fs.openSync(file, 'r'); - var numLinesRead = 0; - var ret = ''; - while (bytesRead === bufLength && numLinesRead < numLines) { - bytesRead = fs.readSync(fdr, buf, 0, bufLength, pos); - var bufStr = buf.toString('utf8', 0, bytesRead); - numLinesRead += bufStr.split('\n').length - 1; - ret += bufStr; - pos += bytesRead; - } - - fs.closeSync(fdr); - return ret; -} - -//@ -//@ ### head([{'-n': \},] file [, file ...]) -//@ ### head([{'-n': \},] file_array) -//@ -//@ Available options: -//@ -//@ + `-n `: Show the first `` lines of the files -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var str = head({'-n': 1}, 'file*.txt'); -//@ var str = head('file1', 'file2'); -//@ var str = head(['file1', 'file2']); // same as above -//@ ``` -//@ -//@ Read the start of a file. -function _head(options, files) { - var head = []; - var pipe = common.readFromPipe(); - - if (!files && !pipe) common.error('no paths given'); - - var idx = 1; - if (options.numLines === true) { - idx = 2; - options.numLines = Number(arguments[1]); - } else if (options.numLines === false) { - options.numLines = 10; - } - files = [].slice.call(arguments, idx); - - if (pipe) { - files.unshift('-'); - } - - var shouldAppendNewline = false; - files.forEach(function (file) { - if (file !== '-') { - if (!fs.existsSync(file)) { - common.error('no such file or directory: ' + file, { continue: true }); - return; - } else if (common.statFollowLinks(file).isDirectory()) { - common.error("error reading '" + file + "': Is a directory", { - continue: true, - }); - return; - } - } - - var contents; - if (file === '-') { - contents = pipe; - } else if (options.numLines < 0) { - contents = fs.readFileSync(file, 'utf8'); - } else { - contents = readSomeLines(file, options.numLines); - } - - var lines = contents.split('\n'); - var hasTrailingNewline = (lines[lines.length - 1] === ''); - if (hasTrailingNewline) { - lines.pop(); - } - shouldAppendNewline = (hasTrailingNewline || options.numLines < lines.length); - - head = head.concat(lines.slice(0, options.numLines)); - }); - - if (shouldAppendNewline) { - head.push(''); // to add a trailing newline once we join - } - return head.join('\n'); -} -module.exports = _head; - - -/***/ }), - -/***/ 6655: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); -var common = __nccwpck_require__(4396); - -common.register('ln', _ln, { - cmdOptions: { - 's': 'symlink', - 'f': 'force', - }, -}); - -//@ -//@ ### ln([options,] source, dest) -//@ -//@ Available options: -//@ -//@ + `-s`: symlink -//@ + `-f`: force -//@ -//@ Examples: -//@ -//@ ```javascript -//@ ln('file', 'newlink'); -//@ ln('-sf', 'file', 'existing'); -//@ ``` -//@ -//@ Links `source` to `dest`. Use `-f` to force the link, should `dest` already exist. -function _ln(options, source, dest) { - if (!source || !dest) { - common.error('Missing and/or '); - } - - source = String(source); - var sourcePath = path.normalize(source).replace(RegExp(path.sep + '$'), ''); - var isAbsolute = (path.resolve(source) === sourcePath); - dest = path.resolve(process.cwd(), String(dest)); - - if (fs.existsSync(dest)) { - if (!options.force) { - common.error('Destination file exists', { continue: true }); - } - - fs.unlinkSync(dest); - } - - if (options.symlink) { - var isWindows = process.platform === 'win32'; - var linkType = isWindows ? 'file' : null; - var resolvedSourcePath = isAbsolute ? sourcePath : path.resolve(process.cwd(), path.dirname(dest), source); - if (!fs.existsSync(resolvedSourcePath)) { - common.error('Source file does not exist', { continue: true }); - } else if (isWindows && common.statFollowLinks(resolvedSourcePath).isDirectory()) { - linkType = 'junction'; - } - - try { - fs.symlinkSync(linkType === 'junction' ? resolvedSourcePath : source, dest, linkType); - } catch (err) { - common.error(err.message); - } - } else { - if (!fs.existsSync(source)) { - common.error('Source file does not exist', { continue: true }); - } - try { - fs.linkSync(source, dest); - } catch (err) { - common.error(err.message); - } - } - return ''; -} -module.exports = _ln; - - -/***/ }), - -/***/ 7513: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var path = __nccwpck_require__(1017); -var fs = __nccwpck_require__(7147); -var common = __nccwpck_require__(4396); -var glob = __nccwpck_require__(8928); - -var globPatternRecursive = path.sep + '**'; - -common.register('ls', _ls, { - cmdOptions: { - 'R': 'recursive', - 'A': 'all', - 'L': 'link', - 'a': 'all_deprecated', - 'd': 'directory', - 'l': 'long', - }, -}); - -//@ -//@ ### ls([options,] [path, ...]) -//@ ### ls([options,] path_array) -//@ -//@ Available options: -//@ -//@ + `-R`: recursive -//@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`) -//@ + `-L`: follow symlinks -//@ + `-d`: list directories themselves, not their contents -//@ + `-l`: list objects representing each file, each with fields containing `ls -//@ -l` output fields. See -//@ [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) -//@ for more info -//@ -//@ Examples: -//@ -//@ ```javascript -//@ ls('projs/*.js'); -//@ ls('-R', '/users/me', '/tmp'); -//@ ls('-R', ['/users/me', '/tmp']); // same as above -//@ ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} -//@ ``` -//@ -//@ Returns array of files in the given `path`, or files in -//@ the current directory if no `path` is provided. -function _ls(options, paths) { - if (options.all_deprecated) { - // We won't support the -a option as it's hard to image why it's useful - // (it includes '.' and '..' in addition to '.*' files) - // For backwards compatibility we'll dump a deprecated message and proceed as before - common.log('ls: Option -a is deprecated. Use -A instead'); - options.all = true; - } - - if (!paths) { - paths = ['.']; - } else { - paths = [].slice.call(arguments, 1); - } - - var list = []; - - function pushFile(abs, relName, stat) { - if (process.platform === 'win32') { - relName = relName.replace(/\\/g, '/'); - } - if (options.long) { - stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs)); - list.push(addLsAttributes(relName, stat)); - } else { - // list.push(path.relative(rel || '.', file)); - list.push(relName); - } - } - - paths.forEach(function (p) { - var stat; - - try { - stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p); - // follow links to directories by default - if (stat.isSymbolicLink()) { - /* istanbul ignore next */ - // workaround for https://github.com/shelljs/shelljs/issues/795 - // codecov seems to have a bug that miscalculate this block as uncovered. - // but according to nyc report this block does get covered. - try { - var _stat = common.statFollowLinks(p); - if (_stat.isDirectory()) { - stat = _stat; - } - } catch (_) {} // bad symlink, treat it like a file - } - } catch (e) { - common.error('no such file or directory: ' + p, 2, { continue: true }); - return; - } - - // If the stat succeeded - if (stat.isDirectory() && !options.directory) { - if (options.recursive) { - // use glob, because it's simple - glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link }) - .forEach(function (item) { - // Glob pattern returns the directory itself and needs to be filtered out. - if (path.relative(p, item)) { - pushFile(item, path.relative(p, item)); - } - }); - } else if (options.all) { - // use fs.readdirSync, because it's fast - fs.readdirSync(p).forEach(function (item) { - pushFile(path.join(p, item), item); - }); - } else { - // use fs.readdirSync and then filter out secret files - fs.readdirSync(p).forEach(function (item) { - if (item[0] !== '.') { - pushFile(path.join(p, item), item); - } - }); - } - } else { - pushFile(p, p, stat); - } - }); - - // Add methods, to make this more compatible with ShellStrings - return list; -} - -function addLsAttributes(pathName, stats) { - // Note: this object will contain more information than .toString() returns - stats.name = pathName; - stats.toString = function () { - // Return a string resembling unix's `ls -l` format - return [this.mode, this.nlink, this.uid, this.gid, this.size, this.mtime, this.name].join(' '); - }; - return stats; -} - -module.exports = _ls; - - -/***/ }), - -/***/ 6738: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); - -common.register('mkdir', _mkdir, { - cmdOptions: { - 'p': 'fullpath', - }, -}); - -// Recursively creates `dir` -function mkdirSyncRecursive(dir) { - var baseDir = path.dirname(dir); - - // Prevents some potential problems arising from malformed UNCs or - // insufficient permissions. - /* istanbul ignore next */ - if (baseDir === dir) { - common.error('dirname() failed: [' + dir + ']'); - } - - // Base dir exists, no recursion necessary - if (fs.existsSync(baseDir)) { - fs.mkdirSync(dir, parseInt('0777', 8)); - return; - } - - // Base dir does not exist, go recursive - mkdirSyncRecursive(baseDir); - - // Base dir created, can create dir - fs.mkdirSync(dir, parseInt('0777', 8)); -} - -//@ -//@ ### mkdir([options,] dir [, dir ...]) -//@ ### mkdir([options,] dir_array) -//@ -//@ Available options: -//@ -//@ + `-p`: full path (and create intermediate directories, if necessary) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ mkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g'); -//@ mkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above -//@ ``` -//@ -//@ Creates directories. -function _mkdir(options, dirs) { - if (!dirs) common.error('no paths given'); - - if (typeof dirs === 'string') { - dirs = [].slice.call(arguments, 1); - } - // if it's array leave it as it is - - dirs.forEach(function (dir) { - try { - var stat = common.statNoFollowLinks(dir); - if (!options.fullpath) { - common.error('path already exists: ' + dir, { continue: true }); - } else if (stat.isFile()) { - common.error('cannot create directory ' + dir + ': File exists', { continue: true }); - } - return; // skip dir - } catch (e) { - // do nothing - } - - // Base dir does not exist, and no -p option given - var baseDir = path.dirname(dir); - if (!fs.existsSync(baseDir) && !options.fullpath) { - common.error('no such file or directory: ' + baseDir, { continue: true }); - return; // skip dir - } - - try { - if (options.fullpath) { - mkdirSyncRecursive(path.resolve(dir)); - } else { - fs.mkdirSync(dir, parseInt('0777', 8)); - } - } catch (e) { - var reason; - if (e.code === 'EACCES') { - reason = 'Permission denied'; - } else if (e.code === 'ENOTDIR' || e.code === 'ENOENT') { - reason = 'Not a directory'; - } else { - /* istanbul ignore next */ - throw e; - } - common.error('cannot create directory ' + dir + ': ' + reason, { continue: true }); - } - }); - return ''; -} // mkdir -module.exports = _mkdir; - - -/***/ }), - -/***/ 9503: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); -var common = __nccwpck_require__(4396); -var cp = __nccwpck_require__(9926); -var rm = __nccwpck_require__(1177); - -common.register('mv', _mv, { - cmdOptions: { - 'f': '!no_force', - 'n': 'no_force', - }, -}); - -// Checks if cureent file was created recently -function checkRecentCreated(sources, index) { - var lookedSource = sources[index]; - return sources.slice(0, index).some(function (src) { - return path.basename(src) === path.basename(lookedSource); - }); -} - -//@ -//@ ### mv([options ,] source [, source ...], dest') -//@ ### mv([options ,] source_array, dest') -//@ -//@ Available options: -//@ -//@ + `-f`: force (default behavior) -//@ + `-n`: no-clobber -//@ -//@ Examples: -//@ -//@ ```javascript -//@ mv('-n', 'file', 'dir/'); -//@ mv('file1', 'file2', 'dir/'); -//@ mv(['file1', 'file2'], 'dir/'); // same as above -//@ ``` -//@ -//@ Moves `source` file(s) to `dest`. -function _mv(options, sources, dest) { - // Get sources, dest - if (arguments.length < 3) { - common.error('missing and/or '); - } else if (arguments.length > 3) { - sources = [].slice.call(arguments, 1, arguments.length - 1); - dest = arguments[arguments.length - 1]; - } else if (typeof sources === 'string') { - sources = [sources]; - } else { - // TODO(nate): figure out if we actually need this line - common.error('invalid arguments'); - } - - var exists = fs.existsSync(dest); - var stats = exists && common.statFollowLinks(dest); - - // Dest is not existing dir, but multiple sources given - if ((!exists || !stats.isDirectory()) && sources.length > 1) { - common.error('dest is not a directory (too many sources)'); - } - - // Dest is an existing file, but no -f given - if (exists && stats.isFile() && options.no_force) { - common.error('dest file already exists: ' + dest); - } - - sources.forEach(function (src, srcIndex) { - if (!fs.existsSync(src)) { - common.error('no such file or directory: ' + src, { continue: true }); - return; // skip file - } - - // If here, src exists - - // When copying to '/path/dir': - // thisDest = '/path/dir/file1' - var thisDest = dest; - if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory()) { - thisDest = path.normalize(dest + '/' + path.basename(src)); - } - - var thisDestExists = fs.existsSync(thisDest); - - if (thisDestExists && checkRecentCreated(sources, srcIndex)) { - // cannot overwrite file created recently in current execution, but we want to continue copying other files - if (!options.no_force) { - common.error("will not overwrite just-created '" + thisDest + "' with '" + src + "'", { continue: true }); - } - return; - } - - if (fs.existsSync(thisDest) && options.no_force) { - common.error('dest file already exists: ' + thisDest, { continue: true }); - return; // skip file - } - - if (path.resolve(src) === path.dirname(path.resolve(thisDest))) { - common.error('cannot move to self: ' + src, { continue: true }); - return; // skip file - } - - try { - fs.renameSync(src, thisDest); - } catch (e) { - /* istanbul ignore next */ - if (e.code === 'EXDEV') { - // If we're trying to `mv` to an external partition, we'll actually need - // to perform a copy and then clean up the original file. If either the - // copy or the rm fails with an exception, we should allow this - // exception to pass up to the top level. - cp('-r', src, thisDest); - rm('-rf', src); - } - } - }); // forEach(src) - return ''; -} // mv -module.exports = _mv; - - -/***/ }), - -/***/ 2720: -/***/ (() => { - -// see dirs.js - - -/***/ }), - -/***/ 9835: -/***/ (() => { - -// see dirs.js - - -/***/ }), - -/***/ 6214: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var path = __nccwpck_require__(1017); -var common = __nccwpck_require__(4396); - -common.register('pwd', _pwd, { - allowGlobbing: false, -}); - -//@ -//@ ### pwd() -//@ -//@ Returns the current directory. -function _pwd() { - var pwd = path.resolve(process.cwd()); - return pwd; -} -module.exports = _pwd; - - -/***/ }), - -/***/ 1177: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('rm', _rm, { - cmdOptions: { - 'f': 'force', - 'r': 'recursive', - 'R': 'recursive', - }, -}); - -// Recursively removes 'dir' -// Adapted from https://github.com/ryanmcgrath/wrench-js -// -// Copyright (c) 2010 Ryan McGrath -// Copyright (c) 2012 Artur Adib -// -// Licensed under the MIT License -// http://www.opensource.org/licenses/mit-license.php -function rmdirSyncRecursive(dir, force, fromSymlink) { - var files; - - files = fs.readdirSync(dir); - - // Loop through and delete everything in the sub-tree after checking it - for (var i = 0; i < files.length; i++) { - var file = dir + '/' + files[i]; - var currFile = common.statNoFollowLinks(file); - - if (currFile.isDirectory()) { // Recursive function back to the beginning - rmdirSyncRecursive(file, force); - } else { // Assume it's a file - perhaps a try/catch belongs here? - if (force || isWriteable(file)) { - try { - common.unlinkSync(file); - } catch (e) { - /* istanbul ignore next */ - common.error('could not remove file (code ' + e.code + '): ' + file, { - continue: true, - }); - } - } - } - } - - // if was directory was referenced through a symbolic link, - // the contents should be removed, but not the directory itself - if (fromSymlink) return; - - // Now that we know everything in the sub-tree has been deleted, we can delete the main directory. - // Huzzah for the shopkeep. - - var result; - try { - // Retry on windows, sometimes it takes a little time before all the files in the directory are gone - var start = Date.now(); - - // TODO: replace this with a finite loop - for (;;) { - try { - result = fs.rmdirSync(dir); - if (fs.existsSync(dir)) throw { code: 'EAGAIN' }; - break; - } catch (er) { - /* istanbul ignore next */ - // In addition to error codes, also check if the directory still exists and loop again if true - if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM' || er.code === 'EAGAIN')) { - if (Date.now() - start > 1000) throw er; - } else if (er.code === 'ENOENT') { - // Directory did not exist, deletion was successful - break; - } else { - throw er; - } - } - } - } catch (e) { - common.error('could not remove directory (code ' + e.code + '): ' + dir, { continue: true }); - } - - return result; -} // rmdirSyncRecursive - -// Hack to determine if file has write permissions for current user -// Avoids having to check user, group, etc, but it's probably slow -function isWriteable(file) { - var writePermission = true; - try { - var __fd = fs.openSync(file, 'a'); - fs.closeSync(__fd); - } catch (e) { - writePermission = false; - } - - return writePermission; -} - -function handleFile(file, options) { - if (options.force || isWriteable(file)) { - // -f was passed, or file is writable, so it can be removed - common.unlinkSync(file); - } else { - common.error('permission denied: ' + file, { continue: true }); - } -} - -function handleDirectory(file, options) { - if (options.recursive) { - // -r was passed, so directory can be removed - rmdirSyncRecursive(file, options.force); - } else { - common.error('path is a directory', { continue: true }); - } -} - -function handleSymbolicLink(file, options) { - var stats; - try { - stats = common.statFollowLinks(file); - } catch (e) { - // symlink is broken, so remove the symlink itself - common.unlinkSync(file); - return; - } - - if (stats.isFile()) { - common.unlinkSync(file); - } else if (stats.isDirectory()) { - if (file[file.length - 1] === '/') { - // trailing separator, so remove the contents, not the link - if (options.recursive) { - // -r was passed, so directory can be removed - var fromSymlink = true; - rmdirSyncRecursive(file, options.force, fromSymlink); - } else { - common.error('path is a directory', { continue: true }); - } - } else { - // no trailing separator, so remove the link - common.unlinkSync(file); - } - } -} - -function handleFIFO(file) { - common.unlinkSync(file); -} - -//@ -//@ ### rm([options,] file [, file ...]) -//@ ### rm([options,] file_array) -//@ -//@ Available options: -//@ -//@ + `-f`: force -//@ + `-r, -R`: recursive -//@ -//@ Examples: -//@ -//@ ```javascript -//@ rm('-rf', '/tmp/*'); -//@ rm('some_file.txt', 'another_file.txt'); -//@ rm(['some_file.txt', 'another_file.txt']); // same as above -//@ ``` -//@ -//@ Removes files. -function _rm(options, files) { - if (!files) common.error('no paths given'); - - // Convert to array - files = [].slice.call(arguments, 1); - - files.forEach(function (file) { - var lstats; - try { - var filepath = (file[file.length - 1] === '/') - ? file.slice(0, -1) // remove the '/' so lstatSync can detect symlinks - : file; - lstats = common.statNoFollowLinks(filepath); // test for existence - } catch (e) { - // Path does not exist, no force flag given - if (!options.force) { - common.error('no such file or directory: ' + file, { continue: true }); - } - return; // skip file - } - - // If here, path exists - if (lstats.isFile()) { - handleFile(file, options); - } else if (lstats.isDirectory()) { - handleDirectory(file, options); - } else if (lstats.isSymbolicLink()) { - handleSymbolicLink(file, options); - } else if (lstats.isFIFO()) { - handleFIFO(file); - } - }); // forEach(file) - return ''; -} // rm -module.exports = _rm; - - -/***/ }), - -/***/ 7776: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('sed', _sed, { - globStart: 3, // don't glob-expand regexes - canReceivePipe: true, - cmdOptions: { - 'i': 'inplace', - }, -}); - -//@ -//@ ### sed([options,] search_regex, replacement, file [, file ...]) -//@ ### sed([options,] search_regex, replacement, file_array) -//@ -//@ Available options: -//@ -//@ + `-i`: Replace contents of `file` in-place. _Note that no backups will be created!_ -//@ -//@ Examples: -//@ -//@ ```javascript -//@ sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js'); -//@ sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); -//@ ``` -//@ -//@ Reads an input string from `file`s, and performs a JavaScript `replace()` on the input -//@ using the given `search_regex` and `replacement` string or function. Returns the new string after replacement. -//@ -//@ Note: -//@ -//@ Like unix `sed`, ShellJS `sed` supports capture groups. Capture groups are specified -//@ using the `$n` syntax: -//@ -//@ ```javascript -//@ sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt'); -//@ ``` -function _sed(options, regex, replacement, files) { - // Check if this is coming from a pipe - var pipe = common.readFromPipe(); - - if (typeof replacement !== 'string' && typeof replacement !== 'function') { - if (typeof replacement === 'number') { - replacement = replacement.toString(); // fallback - } else { - common.error('invalid replacement string'); - } - } - - // Convert all search strings to RegExp - if (typeof regex === 'string') { - regex = RegExp(regex); - } - - if (!files && !pipe) { - common.error('no files given'); - } - - files = [].slice.call(arguments, 3); - - if (pipe) { - files.unshift('-'); - } - - var sed = []; - files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, 2, { continue: true }); - return; - } - - var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - var lines = contents.split('\n'); - var result = lines.map(function (line) { - return line.replace(regex, replacement); - }).join('\n'); - - sed.push(result); - - if (options.inplace) { - fs.writeFileSync(file, result, 'utf8'); - } - }); - - return sed.join('\n'); -} -module.exports = _sed; - - -/***/ }), - -/***/ 5091: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); - -common.register('set', _set, { - allowGlobbing: false, - wrapOutput: false, -}); - -//@ -//@ ### set(options) -//@ -//@ Available options: -//@ -//@ + `+/-e`: exit upon error (`config.fatal`) -//@ + `+/-v`: verbose: show all commands (`config.verbose`) -//@ + `+/-f`: disable filename expansion (globbing) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ set('-e'); // exit upon first error -//@ set('+e'); // this undoes a "set('-e')" -//@ ``` -//@ -//@ Sets global configuration variables. -function _set(options) { - if (!options) { - var args = [].slice.call(arguments, 0); - if (args.length < 2) common.error('must provide an argument'); - options = args[1]; - } - var negate = (options[0] === '+'); - if (negate) { - options = '-' + options.slice(1); // parseOptions needs a '-' prefix - } - options = common.parseOptions(options, { - 'e': 'fatal', - 'v': 'verbose', - 'f': 'noglob', - }); - - if (negate) { - Object.keys(options).forEach(function (key) { - options[key] = !options[key]; - }); - } - - Object.keys(options).forEach(function (key) { - // Only change the global config if `negate` is false and the option is true - // or if `negate` is true and the option is false (aka negate !== option) - if (negate !== options[key]) { - common.config[key] = options[key]; - } - }); - return; -} -module.exports = _set; - - -/***/ }), - -/***/ 9552: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('sort', _sort, { - canReceivePipe: true, - cmdOptions: { - 'r': 'reverse', - 'n': 'numerical', - }, -}); - -// parse out the number prefix of a line -function parseNumber(str) { - var match = str.match(/^\s*(\d*)\s*(.*)$/); - return { num: Number(match[1]), value: match[2] }; -} - -// compare two strings case-insensitively, but examine case for strings that are -// case-insensitive equivalent -function unixCmp(a, b) { - var aLower = a.toLowerCase(); - var bLower = b.toLowerCase(); - return (aLower === bLower ? - -1 * a.localeCompare(b) : // unix sort treats case opposite how javascript does - aLower.localeCompare(bLower)); -} - -// compare two strings in the fashion that unix sort's -n option works -function numericalCmp(a, b) { - var objA = parseNumber(a); - var objB = parseNumber(b); - if (objA.hasOwnProperty('num') && objB.hasOwnProperty('num')) { - return ((objA.num !== objB.num) ? - (objA.num - objB.num) : - unixCmp(objA.value, objB.value)); - } else { - return unixCmp(objA.value, objB.value); - } -} - -//@ -//@ ### sort([options,] file [, file ...]) -//@ ### sort([options,] file_array) -//@ -//@ Available options: -//@ -//@ + `-r`: Reverse the results -//@ + `-n`: Compare according to numerical value -//@ -//@ Examples: -//@ -//@ ```javascript -//@ sort('foo.txt', 'bar.txt'); -//@ sort('-r', 'foo.txt'); -//@ ``` -//@ -//@ Return the contents of the `file`s, sorted line-by-line. Sorting multiple -//@ files mixes their content (just as unix `sort` does). -function _sort(options, files) { - // Check if this is coming from a pipe - var pipe = common.readFromPipe(); - - if (!files && !pipe) common.error('no files given'); - - files = [].slice.call(arguments, 1); - - if (pipe) { - files.unshift('-'); - } - - var lines = files.reduce(function (accum, file) { - if (file !== '-') { - if (!fs.existsSync(file)) { - common.error('no such file or directory: ' + file, { continue: true }); - return accum; - } else if (common.statFollowLinks(file).isDirectory()) { - common.error('read failed: ' + file + ': Is a directory', { - continue: true, - }); - return accum; - } - } - - var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - return accum.concat(contents.trimRight().split('\n')); - }, []); - - var sorted = lines.sort(options.numerical ? numericalCmp : unixCmp); - - if (options.reverse) { - sorted = sorted.reverse(); - } - - return sorted.join('\n') + '\n'; -} - -module.exports = _sort; - - -/***/ }), - -/***/ 662: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('tail', _tail, { - canReceivePipe: true, - cmdOptions: { - 'n': 'numLines', - }, -}); - -//@ -//@ ### tail([{'-n': \},] file [, file ...]) -//@ ### tail([{'-n': \},] file_array) -//@ -//@ Available options: -//@ -//@ + `-n `: Show the last `` lines of `file`s -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var str = tail({'-n': 1}, 'file*.txt'); -//@ var str = tail('file1', 'file2'); -//@ var str = tail(['file1', 'file2']); // same as above -//@ ``` -//@ -//@ Read the end of a `file`. -function _tail(options, files) { - var tail = []; - var pipe = common.readFromPipe(); - - if (!files && !pipe) common.error('no paths given'); - - var idx = 1; - if (options.numLines === true) { - idx = 2; - options.numLines = Number(arguments[1]); - } else if (options.numLines === false) { - options.numLines = 10; - } - options.numLines = -1 * Math.abs(options.numLines); - files = [].slice.call(arguments, idx); - - if (pipe) { - files.unshift('-'); - } - - var shouldAppendNewline = false; - files.forEach(function (file) { - if (file !== '-') { - if (!fs.existsSync(file)) { - common.error('no such file or directory: ' + file, { continue: true }); - return; - } else if (common.statFollowLinks(file).isDirectory()) { - common.error("error reading '" + file + "': Is a directory", { - continue: true, - }); - return; - } - } - - var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - - var lines = contents.split('\n'); - if (lines[lines.length - 1] === '') { - lines.pop(); - shouldAppendNewline = true; - } else { - shouldAppendNewline = false; - } - - tail = tail.concat(lines.slice(options.numLines)); - }); - - if (shouldAppendNewline) { - tail.push(''); // to add a trailing newline once we join - } - return tail.join('\n'); -} -module.exports = _tail; - - -/***/ }), - -/***/ 2979: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var os = __nccwpck_require__(2037); -var fs = __nccwpck_require__(7147); - -common.register('tempdir', _tempDir, { - allowGlobbing: false, - wrapOutput: false, -}); - -// Returns false if 'dir' is not a writeable directory, 'dir' otherwise -function writeableDir(dir) { - if (!dir || !fs.existsSync(dir)) return false; - - if (!common.statFollowLinks(dir).isDirectory()) return false; - - var testFile = dir + '/' + common.randomFileName(); - try { - fs.writeFileSync(testFile, ' '); - common.unlinkSync(testFile); - return dir; - } catch (e) { - /* istanbul ignore next */ - return false; - } -} - -// Variable to cache the tempdir value for successive lookups. -var cachedTempDir; - -//@ -//@ ### tempdir() -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var tmp = tempdir(); // "/tmp" for most *nix platforms -//@ ``` -//@ -//@ Searches and returns string containing a writeable, platform-dependent temporary directory. -//@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir). -function _tempDir() { - if (cachedTempDir) return cachedTempDir; - - cachedTempDir = writeableDir(os.tmpdir()) || - writeableDir(process.env.TMPDIR) || - writeableDir(process.env.TEMP) || - writeableDir(process.env.TMP) || - writeableDir(process.env.Wimp$ScrapDir) || // RiscOS - writeableDir('C:\\TEMP') || // Windows - writeableDir('C:\\TMP') || // Windows - writeableDir('\\TEMP') || // Windows - writeableDir('\\TMP') || // Windows - writeableDir('/tmp') || - writeableDir('/var/tmp') || - writeableDir('/usr/tmp') || - writeableDir('.'); // last resort - - return cachedTempDir; -} - -// Indicates if the tempdir value is currently cached. This is exposed for tests -// only. The return value should only be tested for truthiness. -function isCached() { - return cachedTempDir; -} - -// Clears the cached tempDir value, if one is cached. This is exposed for tests -// only. -function clearCache() { - cachedTempDir = undefined; -} - -module.exports.tempDir = _tempDir; -module.exports.isCached = isCached; -module.exports.clearCache = clearCache; - - -/***/ }), - -/***/ 8760: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('test', _test, { - cmdOptions: { - 'b': 'block', - 'c': 'character', - 'd': 'directory', - 'e': 'exists', - 'f': 'file', - 'L': 'link', - 'p': 'pipe', - 'S': 'socket', - }, - wrapOutput: false, - allowGlobbing: false, -}); - - -//@ -//@ ### test(expression) -//@ -//@ Available expression primaries: -//@ -//@ + `'-b', 'path'`: true if path is a block device -//@ + `'-c', 'path'`: true if path is a character device -//@ + `'-d', 'path'`: true if path is a directory -//@ + `'-e', 'path'`: true if path exists -//@ + `'-f', 'path'`: true if path is a regular file -//@ + `'-L', 'path'`: true if path is a symbolic link -//@ + `'-p', 'path'`: true if path is a pipe (FIFO) -//@ + `'-S', 'path'`: true if path is a socket -//@ -//@ Examples: -//@ -//@ ```javascript -//@ if (test('-d', path)) { /* do something with dir */ }; -//@ if (!test('-f', path)) continue; // skip if it's a regular file -//@ ``` -//@ -//@ Evaluates `expression` using the available primaries and returns corresponding value. -function _test(options, path) { - if (!path) common.error('no path given'); - - var canInterpret = false; - Object.keys(options).forEach(function (key) { - if (options[key] === true) { - canInterpret = true; - } - }); - - if (!canInterpret) common.error('could not interpret expression'); - - if (options.link) { - try { - return common.statNoFollowLinks(path).isSymbolicLink(); - } catch (e) { - return false; - } - } - - if (!fs.existsSync(path)) return false; - - if (options.exists) return true; - - var stats = common.statFollowLinks(path); - - if (options.block) return stats.isBlockDevice(); - - if (options.character) return stats.isCharacterDevice(); - - if (options.directory) return stats.isDirectory(); - - if (options.file) return stats.isFile(); - - /* istanbul ignore next */ - if (options.pipe) return stats.isFIFO(); - - /* istanbul ignore next */ - if (options.socket) return stats.isSocket(); - - /* istanbul ignore next */ - return false; // fallback -} // test -module.exports = _test; - - -/***/ }), - -/***/ 9934: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); - -common.register('to', _to, { - pipeOnly: true, - wrapOutput: false, -}); - -//@ -//@ ### ShellString.prototype.to(file) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ cat('input.txt').to('output.txt'); -//@ ``` -//@ -//@ Analogous to the redirection operator `>` in Unix, but works with -//@ `ShellStrings` (such as those returned by `cat`, `grep`, etc.). _Like Unix -//@ redirections, `to()` will overwrite any existing file!_ -function _to(options, file) { - if (!file) common.error('wrong arguments'); - - if (!fs.existsSync(path.dirname(file))) { - common.error('no such file or directory: ' + path.dirname(file)); - } - - try { - fs.writeFileSync(file, this.stdout || this.toString(), 'utf8'); - return this; - } catch (e) { - /* istanbul ignore next */ - common.error('could not write to file (code ' + e.code + '): ' + file, { continue: true }); - } -} -module.exports = _to; - - -/***/ }), - -/***/ 3934: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); - -common.register('toEnd', _toEnd, { - pipeOnly: true, - wrapOutput: false, -}); - -//@ -//@ ### ShellString.prototype.toEnd(file) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ cat('input.txt').toEnd('output.txt'); -//@ ``` -//@ -//@ Analogous to the redirect-and-append operator `>>` in Unix, but works with -//@ `ShellStrings` (such as those returned by `cat`, `grep`, etc.). -function _toEnd(options, file) { - if (!file) common.error('wrong arguments'); - - if (!fs.existsSync(path.dirname(file))) { - common.error('no such file or directory: ' + path.dirname(file)); - } - - try { - fs.appendFileSync(file, this.stdout || this.toString(), 'utf8'); - return this; - } catch (e) { - /* istanbul ignore next */ - common.error('could not append to file (code ' + e.code + '): ' + file, { continue: true }); - } -} -module.exports = _toEnd; - - -/***/ }), - -/***/ 4536: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -common.register('touch', _touch, { - cmdOptions: { - 'a': 'atime_only', - 'c': 'no_create', - 'd': 'date', - 'm': 'mtime_only', - 'r': 'reference', - }, -}); - -//@ -//@ ### touch([options,] file [, file ...]) -//@ ### touch([options,] file_array) -//@ -//@ Available options: -//@ -//@ + `-a`: Change only the access time -//@ + `-c`: Do not create any files -//@ + `-m`: Change only the modification time -//@ + `-d DATE`: Parse `DATE` and use it instead of current time -//@ + `-r FILE`: Use `FILE`'s times instead of current time -//@ -//@ Examples: -//@ -//@ ```javascript -//@ touch('source.js'); -//@ touch('-c', '/path/to/some/dir/source.js'); -//@ touch({ '-r': FILE }, '/path/to/some/dir/source.js'); -//@ ``` -//@ -//@ Update the access and modification times of each `FILE` to the current time. -//@ A `FILE` argument that does not exist is created empty, unless `-c` is supplied. -//@ This is a partial implementation of [`touch(1)`](http://linux.die.net/man/1/touch). -function _touch(opts, files) { - if (!files) { - common.error('no files given'); - } else if (typeof files === 'string') { - files = [].slice.call(arguments, 1); - } else { - common.error('file arg should be a string file path or an Array of string file paths'); - } - - files.forEach(function (f) { - touchFile(opts, f); - }); - return ''; -} - -function touchFile(opts, file) { - var stat = tryStatFile(file); - - if (stat && stat.isDirectory()) { - // don't error just exit - return; - } - - // if the file doesn't already exist and the user has specified --no-create then - // this script is finished - if (!stat && opts.no_create) { - return; - } - - // open the file and then close it. this will create it if it doesn't exist but will - // not truncate the file - fs.closeSync(fs.openSync(file, 'a')); - - // - // Set timestamps - // - - // setup some defaults - var now = new Date(); - var mtime = opts.date || now; - var atime = opts.date || now; - - // use reference file - if (opts.reference) { - var refStat = tryStatFile(opts.reference); - if (!refStat) { - common.error('failed to get attributess of ' + opts.reference); - } - mtime = refStat.mtime; - atime = refStat.atime; - } else if (opts.date) { - mtime = opts.date; - atime = opts.date; - } - - if (opts.atime_only && opts.mtime_only) { - // keep the new values of mtime and atime like GNU - } else if (opts.atime_only) { - mtime = stat.mtime; - } else if (opts.mtime_only) { - atime = stat.atime; - } - - fs.utimesSync(file, atime, mtime); -} - -module.exports = _touch; - -function tryStatFile(filePath) { - try { - return common.statFollowLinks(filePath); - } catch (e) { - return null; - } -} - - -/***/ }), - -/***/ 2619: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); - -// add c spaces to the left of str -function lpad(c, str) { - var res = '' + str; - if (res.length < c) { - res = Array((c - res.length) + 1).join(' ') + res; - } - return res; -} - -common.register('uniq', _uniq, { - canReceivePipe: true, - cmdOptions: { - 'i': 'ignoreCase', - 'c': 'count', - 'd': 'duplicates', - }, -}); - -//@ -//@ ### uniq([options,] [input, [output]]) -//@ -//@ Available options: -//@ -//@ + `-i`: Ignore case while comparing -//@ + `-c`: Prefix lines by the number of occurrences -//@ + `-d`: Only print duplicate lines, one for each group of identical lines -//@ -//@ Examples: -//@ -//@ ```javascript -//@ uniq('foo.txt'); -//@ uniq('-i', 'foo.txt'); -//@ uniq('-cd', 'foo.txt', 'bar.txt'); -//@ ``` -//@ -//@ Filter adjacent matching lines from `input`. -function _uniq(options, input, output) { - // Check if this is coming from a pipe - var pipe = common.readFromPipe(); - - if (!pipe) { - if (!input) common.error('no input given'); - - if (!fs.existsSync(input)) { - common.error(input + ': No such file or directory'); - } else if (common.statFollowLinks(input).isDirectory()) { - common.error("error reading '" + input + "'"); - } - } - if (output && fs.existsSync(output) && common.statFollowLinks(output).isDirectory()) { - common.error(output + ': Is a directory'); - } - - var lines = (input ? fs.readFileSync(input, 'utf8') : pipe). - trimRight(). - split('\n'); - - var compare = function (a, b) { - return options.ignoreCase ? - a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()) : - a.localeCompare(b); - }; - var uniqed = lines.reduceRight(function (res, e) { - // Perform uniq -c on the input - if (res.length === 0) { - return [{ count: 1, ln: e }]; - } else if (compare(res[0].ln, e) === 0) { - return [{ count: res[0].count + 1, ln: e }].concat(res.slice(1)); - } else { - return [{ count: 1, ln: e }].concat(res); - } - }, []).filter(function (obj) { - // Do we want only duplicated objects? - return options.duplicates ? obj.count > 1 : true; - }).map(function (obj) { - // Are we tracking the counts of each line? - return (options.count ? (lpad(7, obj.count) + ' ') : '') + obj.ln; - }).join('\n') + '\n'; - - if (output) { - (new common.ShellString(uniqed)).to(output); - // if uniq writes to output, nothing is passed to the next command in the pipeline (if any) - return ''; - } else { - return uniqed; - } -} - -module.exports = _uniq; - - -/***/ }), - -/***/ 3698: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var common = __nccwpck_require__(4396); -var fs = __nccwpck_require__(7147); -var path = __nccwpck_require__(1017); - -common.register('which', _which, { - allowGlobbing: false, - cmdOptions: { - 'a': 'all', - }, -}); - -// XP's system default value for `PATHEXT` system variable, just in case it's not -// set on Windows. -var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh'; - -// For earlier versions of NodeJS that doesn't have a list of constants (< v6) -var FILE_EXECUTABLE_MODE = 1; - -function isWindowsPlatform() { - return process.platform === 'win32'; -} - -// Cross-platform method for splitting environment `PATH` variables -function splitPath(p) { - return p ? p.split(path.delimiter) : []; -} - -// Tests are running all cases for this func but it stays uncovered by codecov due to unknown reason -/* istanbul ignore next */ -function isExecutable(pathName) { - try { - // TODO(node-support): replace with fs.constants.X_OK once remove support for node < v6 - fs.accessSync(pathName, FILE_EXECUTABLE_MODE); - } catch (err) { - return false; - } - return true; -} - -function checkPath(pathName) { - return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory() - && (isWindowsPlatform() || isExecutable(pathName)); -} - -//@ -//@ ### which(command) -//@ -//@ Examples: -//@ -//@ ```javascript -//@ var nodeExec = which('node'); -//@ ``` -//@ -//@ Searches for `command` in the system's `PATH`. On Windows, this uses the -//@ `PATHEXT` variable to append the extension if it's not already executable. -//@ Returns string containing the absolute path to `command`. -function _which(options, cmd) { - if (!cmd) common.error('must specify command'); - - var isWindows = isWindowsPlatform(); - var pathArray = splitPath(process.env.PATH); - - var queryMatches = []; - - // No relative/absolute paths provided? - if (cmd.indexOf('/') === -1) { - // Assume that there are no extensions to append to queries (this is the - // case for unix) - var pathExtArray = ['']; - if (isWindows) { - // In case the PATHEXT variable is somehow not set (e.g. - // child_process.spawn with an empty environment), use the XP default. - var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; - pathExtArray = splitPath(pathExtEnv.toUpperCase()); - } - - // Search for command in PATH - for (var k = 0; k < pathArray.length; k++) { - // already found it - if (queryMatches.length > 0 && !options.all) break; - - var attempt = path.resolve(pathArray[k], cmd); - - if (isWindows) { - attempt = attempt.toUpperCase(); - } - - var match = attempt.match(/\.[^<>:"/\|?*.]+$/); - if (match && pathExtArray.indexOf(match[0]) >= 0) { // this is Windows-only - // The user typed a query with the file extension, like - // `which('node.exe')` - if (checkPath(attempt)) { - queryMatches.push(attempt); - break; - } - } else { // All-platforms - // Cycle through the PATHEXT array, and check each extension - // Note: the array is always [''] on Unix - for (var i = 0; i < pathExtArray.length; i++) { - var ext = pathExtArray[i]; - var newAttempt = attempt + ext; - if (checkPath(newAttempt)) { - queryMatches.push(newAttempt); - break; - } - } - } - } - } else if (checkPath(cmd)) { // a valid absolute or relative path - queryMatches.push(path.resolve(cmd)); - } - - if (queryMatches.length > 0) { - return options.all ? queryMatches : queryMatches[0]; - } - return options.all ? [] : null; -} -module.exports = _which; - - -/***/ }), - -/***/ 2986: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -module.exports = __nccwpck_require__(1647); - - -/***/ }), - -/***/ 1647: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -var net = __nccwpck_require__(1808); -var tls = __nccwpck_require__(4404); -var http = __nccwpck_require__(3685); -var https = __nccwpck_require__(5687); -var events = __nccwpck_require__(2361); -var assert = __nccwpck_require__(9491); -var util = __nccwpck_require__(3837); - - -exports.httpOverHttp = httpOverHttp; -exports.httpsOverHttp = httpsOverHttp; -exports.httpOverHttps = httpOverHttps; -exports.httpsOverHttps = httpsOverHttps; - - -function httpOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - return agent; -} - -function httpsOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - agent.createSocket = createSecureSocket; - agent.defaultPort = 443; - return agent; -} - -function httpOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - return agent; -} - -function httpsOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - agent.createSocket = createSecureSocket; - agent.defaultPort = 443; - return agent; -} - - -function TunnelingAgent(options) { - var self = this; - self.options = options || {}; - self.proxyOptions = self.options.proxy || {}; - self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; - self.requests = []; - self.sockets = []; - - self.on('free', function onFree(socket, host, port, localAddress) { - var options = toOptions(host, port, localAddress); - for (var i = 0, len = self.requests.length; i < len; ++i) { - var pending = self.requests[i]; - if (pending.host === options.host && pending.port === options.port) { - // Detect the request to connect same origin server, - // reuse the connection. - self.requests.splice(i, 1); - pending.request.onSocket(socket); - return; - } - } - socket.destroy(); - self.removeSocket(socket); - }); -} -util.inherits(TunnelingAgent, events.EventEmitter); - -TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) { - var self = this; - var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress)); - - if (self.sockets.length >= this.maxSockets) { - // We are over limit so we'll add it to the queue. - self.requests.push(options); - return; - } - - // If we are under maxSockets create a new one. - self.createSocket(options, function(socket) { - socket.on('free', onFree); - socket.on('close', onCloseOrRemove); - socket.on('agentRemove', onCloseOrRemove); - req.onSocket(socket); - - function onFree() { - self.emit('free', socket, options); - } - - function onCloseOrRemove(err) { - self.removeSocket(socket); - socket.removeListener('free', onFree); - socket.removeListener('close', onCloseOrRemove); - socket.removeListener('agentRemove', onCloseOrRemove); - } - }); -}; - -TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { - var self = this; - var placeholder = {}; - self.sockets.push(placeholder); - - var connectOptions = mergeOptions({}, self.proxyOptions, { - method: 'CONNECT', - path: options.host + ':' + options.port, - agent: false, - headers: { - host: options.host + ':' + options.port - } - }); - if (options.localAddress) { - connectOptions.localAddress = options.localAddress; - } - if (connectOptions.proxyAuth) { - connectOptions.headers = connectOptions.headers || {}; - connectOptions.headers['Proxy-Authorization'] = 'Basic ' + - new Buffer(connectOptions.proxyAuth).toString('base64'); - } - - debug('making CONNECT request'); - var connectReq = self.request(connectOptions); - connectReq.useChunkedEncodingByDefault = false; // for v0.6 - connectReq.once('response', onResponse); // for v0.6 - connectReq.once('upgrade', onUpgrade); // for v0.6 - connectReq.once('connect', onConnect); // for v0.7 or later - connectReq.once('error', onError); - connectReq.end(); - - function onResponse(res) { - // Very hacky. This is necessary to avoid http-parser leaks. - res.upgrade = true; - } - - function onUpgrade(res, socket, head) { - // Hacky. - process.nextTick(function() { - onConnect(res, socket, head); - }); - } - - function onConnect(res, socket, head) { - connectReq.removeAllListeners(); - socket.removeAllListeners(); - - if (res.statusCode !== 200) { - debug('tunneling socket could not be established, statusCode=%d', - res.statusCode); - socket.destroy(); - var error = new Error('tunneling socket could not be established, ' + - 'statusCode=' + res.statusCode); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - return; - } - if (head.length > 0) { - debug('got illegal response body from proxy'); - socket.destroy(); - var error = new Error('got illegal response body from proxy'); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - return; - } - debug('tunneling connection has established'); - self.sockets[self.sockets.indexOf(placeholder)] = socket; - return cb(socket); - } - - function onError(cause) { - connectReq.removeAllListeners(); - - debug('tunneling socket could not be established, cause=%s\n', - cause.message, cause.stack); - var error = new Error('tunneling socket could not be established, ' + - 'cause=' + cause.message); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - } -}; - -TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { - var pos = this.sockets.indexOf(socket) - if (pos === -1) { - return; - } - this.sockets.splice(pos, 1); - - var pending = this.requests.shift(); - if (pending) { - // If we have pending requests and a socket gets closed a new one - // needs to be created to take over in the pool for the one that closed. - this.createSocket(pending, function(socket) { - pending.request.onSocket(socket); - }); - } -}; - -function createSecureSocket(options, cb) { - var self = this; - TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { - var hostHeader = options.request.getHeader('host'); - var tlsOptions = mergeOptions({}, self.options, { - socket: socket, - servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host - }); - - // 0 is dummy port for v0.6 - var secureSocket = tls.connect(0, tlsOptions); - self.sockets[self.sockets.indexOf(socket)] = secureSocket; - cb(secureSocket); - }); -} - - -function toOptions(host, port, localAddress) { - if (typeof host === 'string') { // since v0.10 - return { - host: host, - port: port, - localAddress: localAddress - }; - } - return host; // for v0.11 or later -} - -function mergeOptions(target) { - for (var i = 1, len = arguments.length; i < len; ++i) { - var overrides = arguments[i]; - if (typeof overrides === 'object') { - var keys = Object.keys(overrides); - for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { - var k = keys[j]; - if (overrides[k] !== undefined) { - target[k] = overrides[k]; - } - } - } - } - return target; -} - - -var debug; -if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { - debug = function() { - var args = Array.prototype.slice.call(arguments); - if (typeof args[0] === 'string') { - args[0] = 'TUNNEL: ' + args[0]; - } else { - args.unshift('TUNNEL:'); - } - console.error.apply(console, args); - } -} else { - debug = function() {}; -} -exports.debug = debug; // for test - - -/***/ }), - -/***/ 8077: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -Object.defineProperty(exports, "v1", ({ - enumerable: true, - get: function () { - return _v.default; - } -})); -Object.defineProperty(exports, "v3", ({ - enumerable: true, - get: function () { - return _v2.default; - } -})); -Object.defineProperty(exports, "v4", ({ - enumerable: true, - get: function () { - return _v3.default; - } -})); -Object.defineProperty(exports, "v5", ({ - enumerable: true, - get: function () { - return _v4.default; - } -})); -Object.defineProperty(exports, "NIL", ({ - enumerable: true, - get: function () { - return _nil.default; - } -})); -Object.defineProperty(exports, "version", ({ - enumerable: true, - get: function () { - return _version.default; - } -})); -Object.defineProperty(exports, "validate", ({ - enumerable: true, - get: function () { - return _validate.default; - } -})); -Object.defineProperty(exports, "stringify", ({ - enumerable: true, - get: function () { - return _stringify.default; - } -})); -Object.defineProperty(exports, "parse", ({ - enumerable: true, - get: function () { - return _parse.default; - } -})); - -var _v = _interopRequireDefault(__nccwpck_require__(6154)); - -var _v2 = _interopRequireDefault(__nccwpck_require__(1998)); - -var _v3 = _interopRequireDefault(__nccwpck_require__(2971)); - -var _v4 = _interopRequireDefault(__nccwpck_require__(4603)); - -var _nil = _interopRequireDefault(__nccwpck_require__(5296)); - -var _version = _interopRequireDefault(__nccwpck_require__(5021)); - -var _validate = _interopRequireDefault(__nccwpck_require__(1040)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(8172)); - -var _parse = _interopRequireDefault(__nccwpck_require__(495)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/***/ }), - -/***/ 4154: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function md5(bytes) { - if (Array.isArray(bytes)) { - bytes = Buffer.from(bytes); - } else if (typeof bytes === 'string') { - bytes = Buffer.from(bytes, 'utf8'); - } - - return _crypto.default.createHash('md5').update(bytes).digest(); -} - -var _default = md5; -exports["default"] = _default; - -/***/ }), - -/***/ 5296: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; -var _default = '00000000-0000-0000-0000-000000000000'; -exports["default"] = _default; - -/***/ }), - -/***/ 495: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(1040)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function parse(uuid) { - if (!(0, _validate.default)(uuid)) { - throw TypeError('Invalid UUID'); - } - - let v; - const arr = new Uint8Array(16); // Parse ########-....-....-....-............ - - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ - - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ - - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ - - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) - - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; -} - -var _default = parse; -exports["default"] = _default; - -/***/ }), - -/***/ 5553: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; -var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; -exports["default"] = _default; - -/***/ }), - -/***/ 4002: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = rng; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate - -let poolPtr = rnds8Pool.length; - -function rng() { - if (poolPtr > rnds8Pool.length - 16) { - _crypto.default.randomFillSync(rnds8Pool); - - poolPtr = 0; - } - - return rnds8Pool.slice(poolPtr, poolPtr += 16); -} - -/***/ }), - -/***/ 2249: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function sha1(bytes) { - if (Array.isArray(bytes)) { - bytes = Buffer.from(bytes); - } else if (typeof bytes === 'string') { - bytes = Buffer.from(bytes, 'utf8'); - } - - return _crypto.default.createHash('sha1').update(bytes).digest(); -} - -var _default = sha1; -exports["default"] = _default; - -/***/ }), - -/***/ 8172: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(1040)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - */ -const byteToHex = []; - -for (let i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); -} - -function stringify(arr, offset = 0) { - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one - // of the following: - // - One or more input array values don't map to a hex octet (leading to - // "undefined" in the uuid) - // - Invalid input values for the RFC `version` or `variant` fields - - if (!(0, _validate.default)(uuid)) { - throw TypeError('Stringified UUID is invalid'); - } - - return uuid; -} - -var _default = stringify; -exports["default"] = _default; - -/***/ }), - -/***/ 6154: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _rng = _interopRequireDefault(__nccwpck_require__(4002)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(8172)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -// **`v1()` - Generate time-based UUID** -// -// Inspired by https://github.com/LiosK/UUID.js -// and http://docs.python.org/library/uuid.html -let _nodeId; - -let _clockseq; // Previous uuid creation time - - -let _lastMSecs = 0; -let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details - -function v1(options, buf, offset) { - let i = buf && offset || 0; - const b = buf || new Array(16); - options = options || {}; - let node = options.node || _nodeId; - let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not - // specified. We do this lazily to minimize issues related to insufficient - // system entropy. See #189 - - if (node == null || clockseq == null) { - const seedBytes = options.random || (options.rng || _rng.default)(); - - if (node == null) { - // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) - node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; - } - - if (clockseq == null) { - // Per 4.2.2, randomize (14 bit) clockseq - clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; - } - } // UUID timestamps are 100 nano-second units since the Gregorian epoch, - // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so - // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' - // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. - - - let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock - // cycle to simulate higher resolution clock - - let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) - - const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression - - if (dt < 0 && options.clockseq === undefined) { - clockseq = clockseq + 1 & 0x3fff; - } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new - // time interval - - - if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { - nsecs = 0; - } // Per 4.2.1.2 Throw error if too many uuids are requested - - - if (nsecs >= 10000) { - throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); - } - - _lastMSecs = msecs; - _lastNSecs = nsecs; - _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch - - msecs += 12219292800000; // `time_low` - - const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; - b[i++] = tl >>> 24 & 0xff; - b[i++] = tl >>> 16 & 0xff; - b[i++] = tl >>> 8 & 0xff; - b[i++] = tl & 0xff; // `time_mid` - - const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; - b[i++] = tmh >>> 8 & 0xff; - b[i++] = tmh & 0xff; // `time_high_and_version` - - b[i++] = tmh >>> 24 & 0xf | 0x10; // include version - - b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) - - b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` - - b[i++] = clockseq & 0xff; // `node` - - for (let n = 0; n < 6; ++n) { - b[i + n] = node[n]; - } - - return buf || (0, _stringify.default)(b); -} - -var _default = v1; -exports["default"] = _default; - -/***/ }), - -/***/ 1998: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _v = _interopRequireDefault(__nccwpck_require__(8159)); - -var _md = _interopRequireDefault(__nccwpck_require__(4154)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const v3 = (0, _v.default)('v3', 0x30, _md.default); -var _default = v3; -exports["default"] = _default; - -/***/ }), - -/***/ 8159: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = _default; -exports.URL = exports.DNS = void 0; - -var _stringify = _interopRequireDefault(__nccwpck_require__(8172)); - -var _parse = _interopRequireDefault(__nccwpck_require__(495)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape - - const bytes = []; - - for (let i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); - } - - return bytes; -} - -const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; -exports.DNS = DNS; -const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; -exports.URL = URL; - -function _default(name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') { - value = stringToBytes(value); - } - - if (typeof namespace === 'string') { - namespace = (0, _parse.default)(namespace); - } - - if (namespace.length !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` - - - let bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; - - if (buf) { - offset = offset || 0; - - for (let i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } - - return buf; - } - - return (0, _stringify.default)(bytes); - } // Function#name is not settable on some platforms (#270) - - - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL; - return generateUUID; -} - -/***/ }), - -/***/ 2971: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _rng = _interopRequireDefault(__nccwpck_require__(4002)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(8172)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function v4(options, buf, offset) { - options = options || {}; - - const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - - - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided - - if (buf) { - offset = offset || 0; - - for (let i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; - } - - return buf; - } - - return (0, _stringify.default)(rnds); -} - -var _default = v4; -exports["default"] = _default; - -/***/ }), - -/***/ 4603: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _v = _interopRequireDefault(__nccwpck_require__(8159)); - -var _sha = _interopRequireDefault(__nccwpck_require__(2249)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const v5 = (0, _v.default)('v5', 0x50, _sha.default); -var _default = v5; -exports["default"] = _default; - -/***/ }), - -/***/ 1040: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _regex = _interopRequireDefault(__nccwpck_require__(5553)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function validate(uuid) { - return typeof uuid === 'string' && _regex.default.test(uuid); -} - -var _default = validate; -exports["default"] = _default; - -/***/ }), - -/***/ 5021: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(1040)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function version(uuid) { - if (!(0, _validate.default)(uuid)) { - throw TypeError('Invalid UUID'); - } - - return parseInt(uuid.substr(14, 1), 16); -} - -var _default = version; -exports["default"] = _default; - -/***/ }), - -/***/ 3466: -/***/ ((module) => { - -// Returns a wrapper function that returns a wrapped callback -// The wrapper function should do some stuff, and return a -// presumably different callback function. -// This makes sure that own properties are retained, so that -// decorations and such are not lost along the way. -module.exports = wrappy -function wrappy (fn, cb) { - if (fn && cb) return wrappy(fn)(cb) - - if (typeof fn !== 'function') - throw new TypeError('need wrapper function') - - Object.keys(fn).forEach(function (k) { - wrapper[k] = fn[k] - }) - - return wrapper - - function wrapper() { - var args = new Array(arguments.length) - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i] - } - var ret = fn.apply(this, args) - var cb = args[args.length-1] - if (typeof ret === 'function' && ret !== cb) { - Object.keys(cb).forEach(function (k) { - ret[k] = cb[k] - }) - } - return ret - } -} - - -/***/ }), - -/***/ 9491: -/***/ ((module) => { - -"use strict"; -module.exports = require("assert"); - -/***/ }), - -/***/ 2081: -/***/ ((module) => { - -"use strict"; -module.exports = require("child_process"); - -/***/ }), - -/***/ 6113: -/***/ ((module) => { - -"use strict"; -module.exports = require("crypto"); +module.exports = require("crypto"); /***/ }), @@ -23620,9 +13637,9 @@ __nccwpck_require__.d(__webpack_exports__, { "postScan": () => (/* binding */ postScan) }); -// EXTERNAL MODULE: ../shared/node_modules/@actions/core/lib/core.js -var core = __nccwpck_require__(3471); -;// CONCATENATED MODULE: ../shared/src/action-helper.ts +// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js +var core = __nccwpck_require__(2186); +;// CONCATENATED MODULE: ./src/action-helper.ts // SPDX-License-Identifier: MIT /** @@ -23641,16 +13658,16 @@ function handleError(error) { failAction(1); } -// EXTERNAL MODULE: ../shared/node_modules/shelljs/shell.js -var shelljs_shell = __nccwpck_require__(2800); -;// CONCATENATED MODULE: ../shared/src/settings.json -const settings_namespaceObject = {"Pz":"sechub.json"}; -;// CONCATENATED MODULE: ../shared/src/sechub.json +// EXTERNAL MODULE: ./node_modules/shelljs/shell.js +var shelljs_shell = __nccwpck_require__(3516); +;// CONCATENATED MODULE: ./src/settings.json +const settings_namespaceObject = JSON.parse('{"vz":"sechub scan-report","nl":"sechub_report_*.*","Pz":"sechub.json"}'); +;// CONCATENATED MODULE: ./src/sechub.json const sechub_namespaceObject = JSON.parse('{"apiVersion":"1.0","codeScan":{"fileSystem":{"folders":["."]},"excludes":[]}}'); var src_sechub_namespaceObject = /*#__PURE__*/__nccwpck_require__.t(sechub_namespaceObject, 2); // EXTERNAL MODULE: external "path" var external_path_ = __nccwpck_require__(1017); -;// CONCATENATED MODULE: ../shared/src/fs-helper.ts +;// CONCATENATED MODULE: ./src/fs-helper.ts // SPDX-License-Identifier: MIT @@ -23680,7 +13697,7 @@ function getFiles(pattern) { return reportFiles; } -;// CONCATENATED MODULE: ../shared/src/sechub-cli.ts +;// CONCATENATED MODULE: ./src/sechub-cli.ts // SPDX-License-Identifier: MIT @@ -23710,7 +13727,7 @@ function markFalsePositives(falsePositivePath) { return shell.exec(`${secHubCli} -file ${falsePositivePath} markFalsePositives`); } -;// CONCATENATED MODULE: ../shared/src/cli-helper.ts +;// CONCATENATED MODULE: ./src/cli-helper.ts // SPDX-License-Identifier: MIT @@ -23758,7 +13775,7 @@ function createSecHubJson(includeFolders, excludeFolders) { return sechubJson; } -;// CONCATENATED MODULE: ../shared/src/log-helper.ts +;// CONCATENATED MODULE: ./src/log-helper.ts // SPDX-License-Identifier: MIT /** @@ -23775,26 +13792,22 @@ function logExitCode(code) { } } -// EXTERNAL MODULE: ./node_modules/shelljs/shell.js -var node_modules_shelljs_shell = __nccwpck_require__(3516); -// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js -var lib_core = __nccwpck_require__(2186); ;// CONCATENATED MODULE: ./src/input.ts // SPDX-License-Identifier: MIT -const configPath = lib_core.getInput('config-path'); -const url = lib_core.getInput('url'); -const apiToken = lib_core.getInput('api-token'); -const user = lib_core.getInput('user'); -const projectName = lib_core.getInput('project-name'); -const sechubCLIVersion = lib_core.getInput('version'); -const debug = lib_core.getInput('debug'); -const input_includeFolders = lib_core.getInput('include-folders'); -const input_excludeFolders = lib_core.getInput('exclude-folders'); -const input_reportFormats = lib_core.getInput('report-formats'); -const failJobOnFindings = lib_core.getInput('fail-job-with-findings'); - -;// CONCATENATED MODULE: ../shared/src/report-formats.ts +const configPath = core.getInput('config-path'); +const url = core.getInput('url'); +const apiToken = core.getInput('api-token'); +const user = core.getInput('user'); +const projectName = core.getInput('project-name'); +const sechubCLIVersion = core.getInput('version'); +const debug = core.getInput('debug'); +const input_includeFolders = core.getInput('include-folders'); +const input_excludeFolders = core.getInput('exclude-folders'); +const input_reportFormats = core.getInput('report-formats'); +const failJobOnFindings = core.getInput('fail-job-with-findings'); + +;// CONCATENATED MODULE: ./src/report-formats.ts // SPDX-License-Identifier: MIT const availableFormats = ['json', 'html']; /** @@ -23820,11 +13833,11 @@ function getValidFormatsFromInput(inputFormats) { * Sets the necessary environment variables with the user input values. */ function initEnvironmentVariables() { - node_modules_shelljs_shell.env.SECHUB_USERID = user; - node_modules_shelljs_shell.env.SECHUB_APITOKEN = apiToken; - node_modules_shelljs_shell.env.SECHUB_SERVER = url; - node_modules_shelljs_shell.env.SECHUB_PROJECT = projectName; - node_modules_shelljs_shell.env.SECHUB_DEBUG = debug; + shelljs_shell.env.SECHUB_USERID = user; + shelljs_shell.env.SECHUB_APITOKEN = apiToken; + shelljs_shell.env.SECHUB_SERVER = url; + shelljs_shell.env.SECHUB_PROJECT = projectName; + shelljs_shell.env.SECHUB_DEBUG = debug; } /** * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. @@ -23833,14 +13846,14 @@ function initEnvironmentVariables() { * @param excludeFolders list of folders to exclude from the scan */ function initSecHubJson(configPath, includeFolders, excludeFolders) { - lib_core.startGroup('Set config'); + core.startGroup('Set config'); if (!configPath) { createSecHubJsonFile(includeFolders, excludeFolders); return null; } - lib_core.info(`Config-Path was found: ${configPath}`); + core.info(`Config-Path was found: ${configPath}`); const configParameter = `-configfile '${configPath}'`; - lib_core.endGroup(); + core.endGroup(); return configParameter; } /** @@ -23890,22 +13903,22 @@ var external_fs_ = __nccwpck_require__(7147); * @param formats formats in which the report should be downloaded */ function downloadReports(formats) { - lib_core.startGroup('Download Reports'); + core.startGroup('Download Reports'); if (formats.length === 0) { - lib_core.info('No more formats'); + core.info('No more formats'); return; } const json = loadJsonReport(); if (json) { const jobUUID = getFieldFromJsonReport('jobUUID', json); - lib_core.debug('JobUUID: ' + jobUUID); + core.debug('JobUUID: ' + jobUUID); formats.forEach((format) => { - lib_core.info(`Get Report as ${format}`); + core.info(`Get Report as ${format}`); const exitCode = getReport(jobUUID, projectName, format); logExitCode(exitCode ? exitCode.code : 0); }); } - lib_core.endGroup(); + core.endGroup(); return json; } /** @@ -23920,7 +13933,7 @@ function loadJsonReport() { return jsonData; } catch (error) { - lib_core.warning(`Error reading or parsing JSON file: ${error}`); + core.warning(`Error reading or parsing JSON file: ${error}`); return undefined; } } @@ -23930,22 +13943,22 @@ function loadJsonReport() { * @param paths All file paths to include into the artifact. */ async function uploadArtifact(name, paths) { - lib_core.startGroup('Upload artifacts'); + core.startGroup('Upload artifacts'); try { const artifactClient = artifact_client/* create */.U(); const artifactName = name; const options = { continueOnError: true }; const workspace = getWorkspaceDir(); - node_modules_shelljs_shell.exec(`ls ${workspace}`); - lib_core.debug('rootDirectory: ' + workspace); - lib_core.debug('files: ' + paths); + shelljs_shell.exec(`ls ${workspace}`); + core.debug('rootDirectory: ' + workspace); + core.debug('files: ' + paths); await artifactClient.uploadArtifact(artifactName, paths, workspace, options); } catch (e) { const message = e instanceof Error ? e.message : 'Unknown error'; - lib_core.error(`ERROR while uploading artifacts: ${message}`); + core.error(`ERROR while uploading artifacts: ${message}`); } - lib_core.endGroup(); + core.endGroup(); } /** * Reads the given field from the SecHub JSON report. @@ -23963,7 +13976,7 @@ function getFieldFromJsonReport(field, jsonData) { currentKey = currentKey[key]; } else { - lib_core.warning(`Field "${key}" not found in the JSON report.`); + core.warning(`Field "${key}" not found in the JSON report.`); return undefined; } } @@ -23975,20 +13988,20 @@ function getFieldFromJsonReport(field, jsonData) { */ function getJsonReportFileName() { const workspaceDir = getWorkspaceDir(); - const filesInWorkspace = node_modules_shelljs_shell.ls(workspaceDir); + const filesInWorkspace = shelljs_shell.ls(workspaceDir); for (const fileName of filesInWorkspace) { if (/sechub_report.*\.json$/.test(fileName)) { return fileName; } } - lib_core.warning('JSON report file not found in the workspace directory.'); + core.warning('JSON report file not found in the workspace directory.'); return ''; } /** * Reports specific outputs to GitHub Actions based on the SecHub result. */ function reportOutputs(jsonData) { - lib_core.startGroup('Reporting outputs to GitHub'); + core.startGroup('Reporting outputs to GitHub'); const findings = analyzeFindings(jsonData); const trafficLight = getFieldFromJsonReport('trafficLight', jsonData); const totalFindings = getFieldFromJsonReport('result.count', jsonData); @@ -23999,7 +14012,7 @@ function reportOutputs(jsonData) { setOutput('scan-findings-medium', findings.mediumCount, 'number'); setOutput('scan-findings-low', findings.lowCount, 'number'); setOutput('scan-readable-summary', humanReadableSummary, 'string'); - lib_core.endGroup(); + core.endGroup(); } /** * Analyzes the SecHub JSON report and returns the number of findings for each severity, if any found. @@ -24010,7 +14023,7 @@ function analyzeFindings(jsonData) { const findings = getFieldFromJsonReport('result.findings', jsonData); // if no findings were reported. if (findings === undefined) { - lib_core.debug('No findings reported to be categorized.'); + core.debug('No findings reported to be categorized.'); return { mediumCount: 0, highCount: 0, @@ -24038,7 +14051,7 @@ function analyzeFindings(jsonData) { } }); if (unmapped > 0) { - lib_core.debug('Unmapped findings: ${unmapped}'); + core.debug('Unmapped findings: ${unmapped}'); } return { mediumCount, @@ -24089,12 +14102,10 @@ function buildSummary(trafficLight, totalFindings, findings) { */ function setOutput(field, value, dataFormat) { value = value !== null && value !== void 0 ? value : (dataFormat === 'number' ? 0 : 'FAILURE'); - lib_core.debug(`Output ${field} set to ${value}`); - lib_core.setOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings. + core.debug(`Output ${field} set to ${value}`); + core.setOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings. } -;// CONCATENATED MODULE: ./src/settings.json -const src_settings_namespaceObject_0 = JSON.parse('{"vz":"sechub scan-report","nl":"sechub_report_*.*"}'); ;// CONCATENATED MODULE: ./src/main.ts // SPDX-License-Identifier: MIT @@ -24146,7 +14157,7 @@ function executeScan(configParameter, format) { async function postScan(reportFormats, exitCode) { const jsonReport = downloadReports(reportFormats.slice(1)); reportOutputs(jsonReport); - await uploadArtifact(src_settings_namespaceObject_0.vz, getFiles(src_settings_namespaceObject_0.nl)); + await uploadArtifact(settings_namespaceObject.vz, getFiles(settings_namespaceObject.nl)); if (exitCode !== 0 && failJobOnFindings === 'true') { failAction(exitCode); } @@ -24156,4 +14167,4 @@ async function postScan(reportFormats, exitCode) { module.exports = __webpack_exports__; /******/ })() -; +; \ No newline at end of file diff --git a/github-actions/shared/src/action-helper.ts b/github-actions/scan/src/action-helper.ts similarity index 100% rename from github-actions/shared/src/action-helper.ts rename to github-actions/scan/src/action-helper.ts diff --git a/github-actions/shared/src/cli-helper.ts b/github-actions/scan/src/cli-helper.ts similarity index 100% rename from github-actions/shared/src/cli-helper.ts rename to github-actions/scan/src/cli-helper.ts diff --git a/github-actions/shared/src/fs-helper.ts b/github-actions/scan/src/fs-helper.ts similarity index 100% rename from github-actions/shared/src/fs-helper.ts rename to github-actions/scan/src/fs-helper.ts diff --git a/github-actions/scan/src/init-scan.ts b/github-actions/scan/src/init-scan.ts index f5db6b8fbd..558d75b581 100644 --- a/github-actions/scan/src/init-scan.ts +++ b/github-actions/scan/src/init-scan.ts @@ -3,8 +3,8 @@ import * as shell from 'shelljs'; import * as input from './input'; import * as core from '@actions/core'; -import {createSecHubJsonFile} from '../../shared/src/cli-helper'; -import { getValidFormatsFromInput } from '../../shared/src/report-formats'; +import {createSecHubJsonFile} from './cli-helper'; +import { getValidFormatsFromInput } from './report-formats'; export interface ScanSettings { configParameter: string | null; diff --git a/github-actions/shared/src/log-helper.ts b/github-actions/scan/src/log-helper.ts similarity index 100% rename from github-actions/shared/src/log-helper.ts rename to github-actions/scan/src/log-helper.ts diff --git a/github-actions/scan/src/main.ts b/github-actions/scan/src/main.ts index 6928e8c996..d118084432 100644 --- a/github-actions/scan/src/main.ts +++ b/github-actions/scan/src/main.ts @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -import {failAction, handleError} from '../../shared/src/action-helper'; -import {downloadRelease} from '../../shared/src/cli-helper'; -import { scan } from '../../shared/src/sechub-cli'; -import { logExitCode } from '../../shared/src/log-helper'; -import { getFiles } from '../../shared/src/fs-helper'; +import {failAction, handleError} from './action-helper'; +import {downloadRelease} from './cli-helper'; +import { scan } from './sechub-cli'; +import { logExitCode } from './log-helper'; +import { getFiles } from './fs-helper'; import {initEnvironmentVariables, initReportFormats, initSecHubJson, ScanSettings} from './init-scan'; import { downloadReports, reportOutputs, uploadArtifact } from './post-scan'; import * as input from './input'; diff --git a/github-actions/scan/src/post-scan.ts b/github-actions/scan/src/post-scan.ts index 5bd3c6bf34..be8fa06578 100644 --- a/github-actions/scan/src/post-scan.ts +++ b/github-actions/scan/src/post-scan.ts @@ -3,9 +3,9 @@ import * as core from '@actions/core'; import * as artifact from '@actions/artifact'; import * as shell from 'shelljs'; -import { getReport } from '../../shared/src/sechub-cli'; -import { getWorkspaceDir } from '../../shared/src/fs-helper'; -import { logExitCode } from '../../shared/src/log-helper'; +import { getReport } from './sechub-cli'; +import { getWorkspaceDir } from './fs-helper'; +import { logExitCode } from './log-helper'; import * as input from './input'; import * as fs from 'fs'; diff --git a/github-actions/shared/src/report-formats.ts b/github-actions/scan/src/report-formats.ts similarity index 100% rename from github-actions/shared/src/report-formats.ts rename to github-actions/scan/src/report-formats.ts diff --git a/github-actions/shared/src/sechub-cli.ts b/github-actions/scan/src/sechub-cli.ts similarity index 100% rename from github-actions/shared/src/sechub-cli.ts rename to github-actions/scan/src/sechub-cli.ts diff --git a/github-actions/shared/src/sechub.json b/github-actions/scan/src/sechub.json similarity index 100% rename from github-actions/shared/src/sechub.json rename to github-actions/scan/src/sechub.json diff --git a/github-actions/scan/src/types.ts b/github-actions/scan/src/types.ts index bc96f77705..70387a23b3 100644 --- a/github-actions/scan/src/types.ts +++ b/github-actions/scan/src/types.ts @@ -5,3 +5,17 @@ export type Settings = { filePattern: string; secHubJsonFileName: string; }; + +export type SecHubJson = { + apiVersion: string; + codeScan: CodeScan; +}; + +type CodeScan = { + fileSystem: FileSystem; + excludes: string[]; +}; + +type FileSystem = { + folders: string[]; +}; diff --git a/github-actions/shared/.eslintrc.json b/github-actions/shared/.eslintrc.json deleted file mode 100644 index 426afea2e9..0000000000 --- a/github-actions/shared/.eslintrc.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "overrides": [ - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - "indent": [ - "error", - 4 - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ] - } -} diff --git a/github-actions/shared/.prettierrc.json b/github-actions/shared/.prettierrc.json deleted file mode 100644 index 7ee7728f51..0000000000 --- a/github-actions/shared/.prettierrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "printWidth": 150, - "semi": true, - "singleQuote": true, - "tabWidth": 4 -} diff --git a/github-actions/shared/jest.config.js b/github-actions/shared/jest.config.js deleted file mode 100644 index 5996228157..0000000000 --- a/github-actions/shared/jest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', -}; \ No newline at end of file diff --git a/github-actions/shared/package-lock.json b/github-actions/shared/package-lock.json deleted file mode 100644 index 54feb35c56..0000000000 --- a/github-actions/shared/package-lock.json +++ /dev/null @@ -1,5078 +0,0 @@ -{ - "name": "shared-code-for-github-actions", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "shared-code-for-github-actions", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@actions/core": "^1.8.2", - "shelljs": "^0.8.5" - }, - "devDependencies": { - "@types/jest": "^29.4.0", - "@types/shelljs": "^0.8.11", - "@typescript-eslint/eslint-plugin": "^5.54.1", - "@typescript-eslint/parser": "^5.54.1", - "@vercel/ncc": "^0.36.1", - "eslint": "^8.35.0", - "prettier": "2.8.4", - "ts-jest": "^29.0.5", - "typescript": "^4.9.5" - } - }, - "node_modules/@actions/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "node_modules/@actions/http-client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", - "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", - "dependencies": { - "tunnel": "^0.0.6" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz", - "integrity": "sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==", - "dev": true, - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.0", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.0", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.0", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true, - "peer": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.21.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz", - "integrity": "sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.21.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.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.21.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", - "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", - "dev": true, - "peer": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.2.tgz", - "integrity": "sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.2", - "@babel/types": "^7.21.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", - "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "peer": true - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "peer": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "peer": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "peer": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "peer": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "peer": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "peer": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "peer": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true, - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "peer": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "peer": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "dev": true, - "dependencies": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.15.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz", - "integrity": "sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true, - "peer": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/shelljs": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", - "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", - "dev": true, - "dependencies": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz", - "integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.54.1", - "@typescript-eslint/type-utils": "5.54.1", - "@typescript-eslint/utils": "5.54.1", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz", - "integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.54.1", - "@typescript-eslint/types": "5.54.1", - "@typescript-eslint/typescript-estree": "5.54.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz", - "integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.54.1", - "@typescript-eslint/visitor-keys": "5.54.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz", - "integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.54.1", - "@typescript-eslint/utils": "5.54.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz", - "integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz", - "integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.54.1", - "@typescript-eslint/visitor-keys": "5.54.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz", - "integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.54.1", - "@typescript-eslint/types": "5.54.1", - "@typescript-eslint/typescript-estree": "5.54.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.54.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz", - "integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.54.1", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vercel/ncc": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz", - "integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==", - "dev": true, - "bin": { - "ncc": "dist/ncc/cli.js" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "peer": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "peer": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "peer": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "peer": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001465", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001465.tgz", - "integrity": "sha512-HvjgL3MYAJjceTDCcjRnQGjwUz/5qec9n7JPOzUursUoOTIsYCSDOb1l7RsnZE8mjbxG78zVRCKfrBXyvChBag==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "peer": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true, - "peer": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "peer": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true, - "peer": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "peer": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true, - "peer": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", - "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.328", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.328.tgz", - "integrity": "sha512-DE9tTy2PNmy1v55AZAO542ui+MLC2cvINMK4P2LXGsJdput/ThVG9t+QGecPuAZZSgC8XoI+Jh9M1OG9IoNSCw==", - "dev": true, - "peer": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "peer": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "peer": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "peer": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "peer": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "peer": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "peer": true - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "peer": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "peer": true - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "peer": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "peer": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "peer": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "peer": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "peer": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "peer": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "peer": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "peer": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "peer": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "peer": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "peer": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "peer": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "peer": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "peer": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "peer": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true, - "peer": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "peer": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "peer": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "peer": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "peer": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "peer": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "peer": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "peer": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "peer": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "peer": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "peer": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "peer": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "peer": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "peer": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "peer": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "peer": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "peer": 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, - "peer": 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", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-jest": { - "version": "29.0.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", - "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "peer": true, - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true, - "peer": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "peer": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "peer": true - }, - "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "peer": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/github-actions/shared/package.json b/github-actions/shared/package.json deleted file mode 100644 index 54b02a9e5e..0000000000 --- a/github-actions/shared/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "shared-code-for-github-actions", - "version": "0.1.0", - "description": "Shared code for GitHub Actions", - "main": "dist/main.js", - "scripts": { - "build": "ncc build src/main.ts", - "lint": "eslint src", - "prettier": "npx prettier --write src", - "test": "npx jest" - }, - "license": "MIT", - "dependencies": { - "@actions/core": "^1.8.2", - "shelljs": "^0.8.5" - }, - "devDependencies": { - "@types/jest": "^29.4.0", - "@types/shelljs": "^0.8.11", - "@typescript-eslint/eslint-plugin": "^5.54.1", - "@typescript-eslint/parser": "^5.54.1", - "eslint": "^8.35.0", - "prettier": "2.8.4", - "ts-jest": "^29.0.5", - "typescript": "^4.9.5" - } -} diff --git a/github-actions/shared/src/settings.json b/github-actions/shared/src/settings.json deleted file mode 100644 index 9fc6cc48c4..0000000000 --- a/github-actions/shared/src/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "artifactName": "sechub scan-report", - "filePattern": "sechub_report_*.*", - "secHubJsonFileName": "sechub.json" -} diff --git a/github-actions/shared/src/types.ts b/github-actions/shared/src/types.ts deleted file mode 100644 index bd7409b199..0000000000 --- a/github-actions/shared/src/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT - -export type SecHubJson = { - apiVersion: string; - codeScan: CodeScan; -}; - -type CodeScan = { - fileSystem: FileSystem; - excludes: string[]; -}; - -type FileSystem = { - folders: string[]; -}; diff --git a/github-actions/shared/tsconfig.json b/github-actions/shared/tsconfig.json deleted file mode 100644 index bfebf8534e..0000000000 --- a/github-actions/shared/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "moduleResolution": "node", - "strict": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "outDir": "dist" - } -} From 885dc4bf1d9aaf0ba757052aabb5b6550339d9d3 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Fri, 19 Jan 2024 17:54:00 +0100 Subject: [PATCH 05/30] Introduced integration test possibility #2839 - introduced "integration-test" script in package.json - many refactorings necessary to get it working - renamed parts - moved parts - etc. --- github-actions/scan/.gitignore | 1 + github-actions/scan/README.adoc | 24 +- .../scan/__test__/ci-helper.test.ts | 15 + .../scan/__test__/init-scan.test.ts | 13 +- .../scan/__test__/integrationtest.test.ts | 95 +++++ .../scan/__test__/log-helper.test.ts | 16 +- .../scan/__test__/post-scan.test.ts | 10 +- .../scan/__test__/setup-integrationtest.sh | 44 +++ github-actions/scan/dist/index.js | 361 +++++++++++------- github-actions/scan/package.json | 6 +- github-actions/scan/src/cli-helper.ts | 53 --- github-actions/scan/src/client-download.ts | 33 ++ .../scan/src/configuration-builder.ts | 53 +++ .../scan/src/configuration-model.ts | 18 + github-actions/scan/src/environment.ts | 16 + github-actions/scan/src/exitcode.ts | 34 ++ github-actions/scan/src/fs-helper.ts | 22 ++ github-actions/scan/src/init-scan.ts | 43 +-- github-actions/scan/src/input.ts | 74 +++- github-actions/scan/src/launcher.ts | 142 +++++++ github-actions/scan/src/log-helper.ts | 16 - github-actions/scan/src/main.ts | 61 +-- github-actions/scan/src/post-scan.ts | 36 +- github-actions/scan/src/sechub-cli.ts | 34 +- github-actions/scan/src/sechub.json | 9 - github-actions/scan/src/settings.json | 5 - github-actions/scan/src/types.ts | 21 - 27 files changed, 871 insertions(+), 384 deletions(-) create mode 100644 github-actions/scan/.gitignore create mode 100644 github-actions/scan/__test__/ci-helper.test.ts create mode 100644 github-actions/scan/__test__/integrationtest.test.ts create mode 100755 github-actions/scan/__test__/setup-integrationtest.sh delete mode 100644 github-actions/scan/src/cli-helper.ts create mode 100644 github-actions/scan/src/client-download.ts create mode 100644 github-actions/scan/src/configuration-builder.ts create mode 100644 github-actions/scan/src/configuration-model.ts create mode 100644 github-actions/scan/src/environment.ts create mode 100644 github-actions/scan/src/exitcode.ts create mode 100644 github-actions/scan/src/launcher.ts delete mode 100644 github-actions/scan/src/log-helper.ts delete mode 100644 github-actions/scan/src/sechub.json delete mode 100644 github-actions/scan/src/settings.json delete mode 100644 github-actions/scan/src/types.ts diff --git a/github-actions/scan/.gitignore b/github-actions/scan/.gitignore new file mode 100644 index 0000000000..712f264ddd --- /dev/null +++ b/github-actions/scan/.gitignore @@ -0,0 +1 @@ +runtime/ diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc index d51171c1c2..822eeca8eb 100644 --- a/github-actions/scan/README.adoc +++ b/github-actions/scan/README.adoc @@ -88,9 +88,31 @@ It's necessary to execute the build after every change of the sources and you ha === Test -To run the tests you have to run this command: +==== Unit tests +To run the unit tests you have to execute this command: [source,npm] ---- npm run test ---- + + +==== Integration-Test +As a precondition to run the integration tests locally you have to + +- start a new SecHub server in integration test mode +- execute `__test__/setup-integrationtest.sh` + +When this has been done, you can execute this command multiple times: + +[source,npm] +---- +npm run integration-test +---- + +To enable full debug output: +[source,npm] +---- +export SECHUB_DEBUG=true +---- + diff --git a/github-actions/scan/__test__/ci-helper.test.ts b/github-actions/scan/__test__/ci-helper.test.ts new file mode 100644 index 0000000000..983294280c --- /dev/null +++ b/github-actions/scan/__test__/ci-helper.test.ts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +import * as cli from '../src/configuration-builder'; +jest.mock('@actions/core'); + +describe('cli-helper', function() { + it('createSecHubConfigModel creates with null always a model with api version 1.0.0', function () { + /* execute */ + const model= cli.createSecHubConfigurationModel(null,null); + + /* test */ + expect(model.apiVersion).toEqual('1.0'); + }); + +}); \ No newline at end of file diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts index 065e9255d2..80d224e35b 100644 --- a/github-actions/scan/__test__/init-scan.test.ts +++ b/github-actions/scan/__test__/init-scan.test.ts @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT -import {initReportFormats, initSecHubJson} from "../src/init-scan"; +import {initReportFormats, initSecHubJson} from '../src/init-scan'; + +jest.mock('./../src/configuration-builder'); +import {createSecHubConfigJsonFile} from '../src/configuration-builder'; -jest.mock('./../src/cli-helper'); -import {createSecHubJsonFile} from '../src/cli-helper'; describe('initSecHubJson', function () { it('returns parameter if configPath is set', function () { @@ -11,7 +12,7 @@ describe('initSecHubJson', function () { const configPath = 'sechub.json'; /* execute */ - const parameter = initSecHubJson(configPath, [], []); + const parameter = initSecHubJson('runtime/sechub.json', configPath, [], []); /* test */ expect(parameter).toContain(configPath); @@ -19,11 +20,11 @@ describe('initSecHubJson', function () { it('creates sechub.json if configPath is not set', function () { /* execute */ - const parameter = initSecHubJson('', [], []); + const parameter = initSecHubJson('runtime/sechub.json','', [], []); /* test */ expect(parameter).toBeNull(); - expect(createSecHubJsonFile).toHaveBeenCalledTimes(1); + expect(createSecHubConfigJsonFile).toHaveBeenCalledTimes(1); }); }); diff --git a/github-actions/scan/__test__/integrationtest.test.ts b/github-actions/scan/__test__/integrationtest.test.ts new file mode 100644 index 0000000000..83bca8f889 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest.test.ts @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT + +import * as launcher from '../src/launcher'; +import * as shell from 'shelljs'; +import { isDebug, debug, getInput } from '@actions/core'; +import { info } from '@actions/core'; +import { error } from '@actions/core'; +import { warning } from '@actions/core'; +import * as input from '../src/input'; +import { LaunchContext } from '../src/launcher'; +import { create } from '@actions/artifact'; +jest.mock('@actions/core'); +jest.mock('@actions/artifact'); +/* + * This is an integration test suite for github-action "scan". + * As precondition you have to start a local sechub server in integration test mode and execute "setup-integrationtest.sh". + * After this is done, you can execute these tests. +*/ + +const sechub_debug = shell.env['SECHUB_DEBUG']; +const debug_enabled = sechub_debug=='true'; + +beforeEach(() => { + jest.resetAllMocks(); + + (getInput as jest.Mock).mockImplementation((name) => { + return mockedInputMap.get(name); + }); + if (debug_enabled){ + (debug as jest.Mock).mockImplementation((message) => { + console.debug('gh-debug: %s', message); + }); + (isDebug as jest.Mock).mockImplementation(() => { + return true; + }); + } + + + (info as jest.Mock).mockImplementation((message) => { + console.log('gh-info: %s', message); + }); + (warning as jest.Mock).mockImplementation((message) => { + console.log('gh-warning: %s', message); + }); + (error as jest.Mock).mockImplementation((message) => { + console.log('gh-error: %s', message); + }); + + (create as jest.Mock).mockName('artifactClient'); + (create as jest.Mock).mockImplementation(() => { + return { + 'uploadArtifact' : jest.fn(), + }; + }); +}); + + +const mockedInputMap = new Map(); + +function initInputMap() { + mockedInputMap.clear(); + + mockedInputMap.set(input.PARAM_SECHUB_SERVER_URL, 'https://localhost:8443'); + mockedInputMap.set(input.PARAM_SECHUB_USER, 'int-test_superadmin'); + mockedInputMap.set(input.PARAM_API_TOKEN, 'int-test_superadmin-pwd'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project'); + + mockedInputMap.set(input.PARAM_CLIENT_VERSION, '1.2.0'); + + mockedInputMap.set(input.PARAM_REPORT_FORMATS, 'json'); + mockedInputMap.set(input.PARAM_TRUST_ALL, 'true'); // self signed certificate in test... +} + + +describe('integrationtest', function () { + test('integrationtest 1', function () { + + /* prepare */ + initInputMap(); + + /* execute */ + const launchPromise = launcher.launch(); + + /* test */ + assertExitCode(launchPromise, 0); + + }); + +}); + +async function assertExitCode(launchPromise: Promise, exitCode: number) { + const context = await launchPromise; + + expect(context.lastClientExitCode).toEqual(exitCode); +} \ No newline at end of file diff --git a/github-actions/scan/__test__/log-helper.test.ts b/github-actions/scan/__test__/log-helper.test.ts index 6009a007b7..c3e4fe5547 100644 --- a/github-actions/scan/__test__/log-helper.test.ts +++ b/github-actions/scan/__test__/log-helper.test.ts @@ -1,17 +1,17 @@ // SPDX-License-Identifier: MIT -import {logExitCode} from "../src/log-helper"; +import { logExitCode } from '../src/exitcode'; jest.mock('@actions/core'); import * as core from '@actions/core'; -describe('logExitCode', function() { - it('uses core.info', function () { - /* execute */ - logExitCode(0); +describe('logExitCode', function () { + it('uses core.info', function () { + /* execute */ + logExitCode(0); - /* test */ - expect(core.info).toHaveBeenCalledTimes(1); - }); + /* test */ + expect(core.info).toHaveBeenCalledTimes(1); + }); it('uses core.error', function () { /* execute */ diff --git a/github-actions/scan/__test__/post-scan.test.ts b/github-actions/scan/__test__/post-scan.test.ts index fba381a087..03973f4c63 100644 --- a/github-actions/scan/__test__/post-scan.test.ts +++ b/github-actions/scan/__test__/post-scan.test.ts @@ -3,31 +3,35 @@ import * as core from '@actions/core'; import { downloadReports, reportOutputs } from '../src/post-scan'; import { getReport } from '../src/sechub-cli'; +import { LAUNCHER_CONTEXT_DEFAULTS } from '../src/launcher'; jest.mock('@actions/core'); const mockedCore = core as jest.Mocked; jest.mock('../src/sechub-cli'); const mockedGetReport = getReport as jest.MockedFunction; + describe('downloadReports', function () { afterEach(() => { jest.clearAllMocks(); }); it('writes to log if formats is empty', function () { - downloadReports([]); + downloadReports(LAUNCHER_CONTEXT_DEFAULTS, []); expect(mockedCore.info).toHaveBeenCalledTimes(1); expect(mockedGetReport).toHaveBeenCalledTimes(0); }); it('calls getReport with correct parameters for non-empty formats', function () { + // eslint-disable-next-line @typescript-eslint/no-var-requires const fsMock = require('fs'); + fsMock.readFileSync = jest.fn(() => '{"test": "test"}'); // Mock an empty JSON report const formats = ['json', 'html']; const sampleJson = {'test': 'test'}; - const actualJson = downloadReports(formats); + const actualJson = downloadReports(LAUNCHER_CONTEXT_DEFAULTS, formats); - expect(mockedCore.info).toHaveBeenCalledTimes(4); // Assumes 3 formats, adjust based on the number of formats in the array + expect(mockedCore.info).toHaveBeenCalledTimes(2); // Assumes 3 formats, adjust based on the number of formats in the array expect(mockedGetReport).toHaveBeenCalledTimes(2); expect(actualJson).toEqual(sampleJson); }); diff --git a/github-actions/scan/__test__/setup-integrationtest.sh b/github-actions/scan/__test__/setup-integrationtest.sh new file mode 100755 index 0000000000..25beda4896 --- /dev/null +++ b/github-actions/scan/__test__/setup-integrationtest.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +cd $(dirname "$0") + +echo "[START] setup integration test scenario for github action 'scan' " +echo " precondition: SecHub server mut be started locally" + +echo "----- Handle settings" +if [[ "$SECHUB_SERVER" == "" ]]; then + export SECHUB_SERVER="https://localhost:8443" + echo "SECHUB_SERVER was not defined - use fallback" +fi +if [[ "$SECHUB_USERID" == "" ]]; then + export SECHUB_USERID="int-test_superadmin" + echo "SECHUB_USERID was not defined - use fallback" +fi +if [[ "$SECHUB_APITOKEN" == "" ]]; then + export SECHUB_APITOKEN="int-test_superadmin-pwd" + echo "SECHUB_APITOKEN was not defined - use fallback" +fi +echo "----- Prepare sechub api script usage" +cd ../../.. +# at root level now + +cd sechub-developertools/scripts +pwd + +# we use the given sechub user (integration test admin) as user itself +# means we need no user creation,signup etc. +user=$SECHUB_USERID +project="test-project" + +echo "----- Check server alive" +./sechub-api.sh alive_check + +echo "----- Create test project:$project for user:$user" +./sechub-api.sh project_create $project $user "Testproject for integration tests" +./sechub-api.sh project_assign_user $project $user # assign user to project + + + + + diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index bc161a14c5..5cca6e5c93 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -13631,12 +13631,6 @@ var __webpack_exports__ = {}; // ESM COMPAT FLAG __nccwpck_require__.r(__webpack_exports__); -// EXPORTS -__nccwpck_require__.d(__webpack_exports__, { - "executeScan": () => (/* binding */ executeScan), - "postScan": () => (/* binding */ postScan) -}); - // EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js var core = __nccwpck_require__(2186); ;// CONCATENATED MODULE: ./src/action-helper.ts @@ -13659,12 +13653,54 @@ function handleError(error) { } // EXTERNAL MODULE: ./node_modules/shelljs/shell.js -var shelljs_shell = __nccwpck_require__(3516); -;// CONCATENATED MODULE: ./src/settings.json -const settings_namespaceObject = JSON.parse('{"vz":"sechub scan-report","nl":"sechub_report_*.*","Pz":"sechub.json"}'); -;// CONCATENATED MODULE: ./src/sechub.json -const sechub_namespaceObject = JSON.parse('{"apiVersion":"1.0","codeScan":{"fileSystem":{"folders":["."]},"excludes":[]}}'); -var src_sechub_namespaceObject = /*#__PURE__*/__nccwpck_require__.t(sechub_namespaceObject, 2); +var shell = __nccwpck_require__(3516); +;// CONCATENATED MODULE: ./src/sechub-cli.ts +// SPDX-License-Identifier: MIT + +/** + * Executes the scan method of the SecHub CLI. + * @param parameter Parameters to execute the scan with + * @param format Report format that should be fetched + * @param context: launch context + */ +function scan(format, context) { + return shell.exec(`${context.clientExecutablePath} ${context.configParameter} -reportformat ${format} scan`); +} +/** + * Executes the getReport method of the SecHub CLI. + * @param jobUUID job UUID for which the report should be downloaded + * @param projectName name of the project for which the report should be downloaded + * @param format format in which the report should be downloaded + * @param context: launch context + */ +function getReport(jobUUID, format, context) { + return shell.exec(`${context.clientExecutablePath} -jobUUID ${jobUUID} -project ${context.inputData.projectName} --reportformat ${format} getReport`); +} +// /** +// * Executes the markFalsePositives method of the SecHub CLI. +// * @param falsePositivePath path to the false positive file +// */ +// export function markFalsePositives(falsePositivePath: string, context: LaunchContext): ShellString { +// return shell.exec(`${context.clientExecutablePath} -file ${falsePositivePath} markFalsePositives`); +// } + +;// CONCATENATED MODULE: ./src/log-helper.ts +// SPDX-License-Identifier: MIT + +/** + * Logs the exit code and uses error method if not 0. + * @param code The given exit code + */ +function logExitCode(code) { + const prefix = 'Exit code: '; + if (code === 0) { + core.info(prefix + code); + } + else { + core.error(prefix + code); + } +} + // EXTERNAL MODULE: external "path" var external_path_ = __nccwpck_require__(1017); ;// CONCATENATED MODULE: ./src/fs-helper.ts @@ -13676,7 +13712,7 @@ var external_path_ = __nccwpck_require__(1017); * Get workspace directory. */ function getWorkspaceDir() { - return shelljs_shell.env.GITHUB_WORKSPACE || ''; + return shell.env.GITHUB_WORKSPACE || ''; } /** * Get parent folder of workspace directory. @@ -13690,81 +13726,64 @@ function getWorkspaceParentDir() { */ function getFiles(pattern) { const reportFiles = []; - shelljs_shell.ls(pattern).forEach(function (file) { + shell.ls(pattern).forEach(function (file) { core.debug('file: ' + file); reportFiles.push(`${getWorkspaceDir()}/${file}`); }); return reportFiles; } - -;// CONCATENATED MODULE: ./src/sechub-cli.ts -// SPDX-License-Identifier: MIT - - -const secHubCli = `${getWorkspaceParentDir()}/platform/linux-386/sechub`; -/** - * Executes the scan method of the SecHub CLI. - * @param parameter Parameters to execute the scan with - * @param format Report format that should be fetched - */ -function scan(parameter, format) { - return shelljs_shell.exec(`${secHubCli} ${parameter} -reportformat ${format} scan`); -} -/** - * Executes the getReport method of the SecHub CLI. - * @param jobUUID job UUID for which the report should be downloaded - * @param projectName name of the project for which the report should be downloaded - * @param format format in which the report should be downloaded - */ -function getReport(jobUUID, projectName, format) { - return shelljs_shell.exec(`${secHubCli} -jobUUID ${jobUUID} -project ${projectName} --reportformat ${format} getReport`); +class ShellFailedWithExitCodeNotZeroError extends Error { + constructor(command, shellExecResult) { + super(`Shell script call failed.\nExit code: ${shellExecResult.code}\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}`); + } } /** - * Executes the markFalsePositives method of the SecHub CLI. - * @param falsePositivePath path to the false positive file + * Executes given command by shell - errors are handled + * @param command + * @throws ShellFailedWithExitCodeNotZeroError + * @returns shellstring */ -function markFalsePositives(falsePositivePath) { - return shell.exec(`${secHubCli} -file ${falsePositivePath} markFalsePositives`); +function shellExecOrFail(command) { + const shellExecResult = shell.exec(command); + if (shellExecResult.code != 0) { + throw new ShellFailedWithExitCodeNotZeroError(command, shellExecResult); + } + return shellExecResult; } -;// CONCATENATED MODULE: ./src/cli-helper.ts +;// CONCATENATED MODULE: ./src/sechub.json +const sechub_namespaceObject = JSON.parse('{"apiVersion":"1.0","codeScan":{"fileSystem":{"folders":["."]},"excludes":[]}}'); +var src_sechub_namespaceObject = /*#__PURE__*/__nccwpck_require__.t(sechub_namespaceObject, 2); +;// CONCATENATED MODULE: ./src/settings.json +const settings_namespaceObject = JSON.parse('{"vz":"sechub scan-report","nl":"sechub_report_*.*","Pz":"sechub.json"}'); +;// CONCATENATED MODULE: ./src/configuration-builder.ts // SPDX-License-Identifier: MIT - - /** - * Downloads a release for the SecHub CLI. - * @param version The version that should be downloaded - */ -function downloadRelease(version) { - const zipUrl = `https://github.com/mercedes-benz/sechub/releases/download/v${version}-client/sechub-cli-${version}.zip`; - core.debug('SecHub-Url: ' + zipUrl); - const secHubZip = `${getWorkspaceParentDir()}/sechub.zip`; - shelljs_shell.exec(`curl -L ${zipUrl} -o ${secHubZip}`); - shelljs_shell.exec(`unzip -o ${secHubZip} -d ${getWorkspaceParentDir()}`); - shelljs_shell.exec(`chmod +x ${secHubCli}`); -} -/** - * Creates the sechub.json with the given user input values. + * Creates the sechub.json configuration file with the given user input values. + * * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -function createSecHubJsonFile(includeFolders, excludeFolders) { +function createSecHubConfigJsonFile(includeFolders, excludeFolders) { core.info('Config-Path was not found. Config will be manually created...'); - const secHubJson = createSecHubJson(includeFolders, excludeFolders); + const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); - shelljs_shell.ShellString(stringifiedSecHubJson).to(settings_namespaceObject.Pz); + shell.ShellString(stringifiedSecHubJson).to(settings_namespaceObject.Pz); } /** - * Creates the object for the sechub.json with the given user input values. + * Creates a sechub configuration model object for given user input values. + * * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded + * + * @returns model */ -function createSecHubJson(includeFolders, excludeFolders) { +function createSecHubConfigurationModel(includeFolders, excludeFolders) { const sechubJson = src_sechub_namespaceObject; if (includeFolders) { sechubJson.codeScan.fileSystem.folders = includeFolders; @@ -13775,38 +13794,6 @@ function createSecHubJson(includeFolders, excludeFolders) { return sechubJson; } -;// CONCATENATED MODULE: ./src/log-helper.ts -// SPDX-License-Identifier: MIT - -/** - * Logs the exit code and uses error method if not 0. - * @param code The given exit code - */ -function logExitCode(code) { - const prefix = 'Exit code: '; - if (code === 0) { - core.info(prefix + code); - } - else { - core.error(prefix + code); - } -} - -;// CONCATENATED MODULE: ./src/input.ts -// SPDX-License-Identifier: MIT - -const configPath = core.getInput('config-path'); -const url = core.getInput('url'); -const apiToken = core.getInput('api-token'); -const user = core.getInput('user'); -const projectName = core.getInput('project-name'); -const sechubCLIVersion = core.getInput('version'); -const debug = core.getInput('debug'); -const input_includeFolders = core.getInput('include-folders'); -const input_excludeFolders = core.getInput('exclude-folders'); -const input_reportFormats = core.getInput('report-formats'); -const failJobOnFindings = core.getInput('fail-job-with-findings'); - ;// CONCATENATED MODULE: ./src/report-formats.ts // SPDX-License-Identifier: MIT const availableFormats = ['json', 'html']; @@ -13827,28 +13814,18 @@ function getValidFormatsFromInput(inputFormats) { - - -/** - * Sets the necessary environment variables with the user input values. - */ -function initEnvironmentVariables() { - shelljs_shell.env.SECHUB_USERID = user; - shelljs_shell.env.SECHUB_APITOKEN = apiToken; - shelljs_shell.env.SECHUB_SERVER = url; - shelljs_shell.env.SECHUB_PROJECT = projectName; - shelljs_shell.env.SECHUB_DEBUG = debug; -} /** * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. * @param configPath Path to the sechub.json * @param includeFolders list of folders to include to the scan * @param excludeFolders list of folders to exclude from the scan + * + * @returns parameter or null if config path is null */ function initSecHubJson(configPath, includeFolders, excludeFolders) { core.startGroup('Set config'); if (!configPath) { - createSecHubJsonFile(includeFolders, excludeFolders); + createSecHubConfigJsonFile(includeFolders, excludeFolders); return null; } core.info(`Config-Path was found: ${configPath}`); @@ -13897,12 +13874,11 @@ var external_fs_ = __nccwpck_require__(7147); - /** * Downloads the reports for the given formats. * @param formats formats in which the report should be downloaded */ -function downloadReports(formats) { +function downloadReports(context, formats) { core.startGroup('Download Reports'); if (formats.length === 0) { core.info('No more formats'); @@ -13914,7 +13890,7 @@ function downloadReports(formats) { core.debug('JobUUID: ' + jobUUID); formats.forEach((format) => { core.info(`Get Report as ${format}`); - const exitCode = getReport(jobUUID, projectName, format); + const exitCode = getReport(jobUUID, format, context); logExitCode(exitCode ? exitCode.code : 0); }); } @@ -13949,7 +13925,7 @@ async function uploadArtifact(name, paths) { const artifactName = name; const options = { continueOnError: true }; const workspace = getWorkspaceDir(); - shelljs_shell.exec(`ls ${workspace}`); + shell.exec(`ls ${workspace}`); core.debug('rootDirectory: ' + workspace); core.debug('files: ' + paths); await artifactClient.uploadArtifact(artifactName, paths, workspace, options); @@ -13972,6 +13948,7 @@ function getFieldFromJsonReport(field, jsonData) { // Traverse the JSON object to find the requested field let currentKey = jsonData; for (const key of keys) { + // eslint-disable-next-line no-prototype-builtins if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { currentKey = currentKey[key]; } @@ -13988,7 +13965,7 @@ function getFieldFromJsonReport(field, jsonData) { */ function getJsonReportFileName() { const workspaceDir = getWorkspaceDir(); - const filesInWorkspace = shelljs_shell.ls(workspaceDir); + const filesInWorkspace = shell.ls(workspaceDir); for (const fileName of filesInWorkspace) { if (/sechub_report.*\.json$/.test(fileName)) { return fileName; @@ -14106,63 +14083,177 @@ function setOutput(field, value, dataFormat) { core.setOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings. } -;// CONCATENATED MODULE: ./src/main.ts +;// CONCATENATED MODULE: ./src/input.ts +// SPDX-License-Identifier: MIT + +const PARAM_CONFIG_PATH = 'config-path'; +const PARAM_SECHUB_SERVER_URL = 'url'; +const PARAM_API_TOKEN = 'api-token'; +const PARAM_SECHUB_USER = 'user'; +const PARAM_PROJECT_NAME = 'project-name'; +const PARAM_CLIENT_VERSION = 'version'; +const PARAM_DEBUG = 'debug'; +const PARAM_INCLUDED_FOLDERS = 'include-folders'; +const PARAM_EXCLUDED_FOLDERS = 'exclude-folders'; +const PARAM_REPORT_FORMATS = 'report-formats'; +const PARAM_FAIL_JOB_ON_FINDING = 'fail-job-with-findings'; +const emptyInputDataDefaults = { + configPath: '', + url: '', + apiToken: '', + user: '', + projectName: '', + sechubCLIVersion: '', + debug: '', + includeFolders: '', + excludeFolders: '', + reportFormats: '', + failJobOnFindings: '', +}; +function resolveGitHubInputData() { + return { + configPath: core.getInput(PARAM_CONFIG_PATH), + url: core.getInput(PARAM_SECHUB_SERVER_URL), + apiToken: core.getInput(PARAM_API_TOKEN), + user: core.getInput(PARAM_SECHUB_USER), + projectName: core.getInput(PARAM_PROJECT_NAME), + sechubCLIVersion: core.getInput(PARAM_CLIENT_VERSION), + debug: core.getInput(PARAM_DEBUG), + includeFolders: core.getInput(PARAM_INCLUDED_FOLDERS), + excludeFolders: core.getInput(PARAM_EXCLUDED_FOLDERS), + reportFormats: core.getInput(PARAM_REPORT_FORMATS), + failJobOnFindings: core.getInput(PARAM_FAIL_JOB_ON_FINDING), + }; +} + +;// CONCATENATED MODULE: ./src/environment.ts // SPDX-License-Identifier: MIT +/** + * Sets the necessary environment variables with the user input values. + */ +function initEnvironmentVariables(data) { + shell.env.SECHUB_USERID = data.user; + shell.env.SECHUB_APITOKEN = data.apiToken; + shell.env.SECHUB_SERVER = data.url; + shell.env.SECHUB_PROJECT = data.projectName; + shell.env.SECHUB_DEBUG = data.debug; +} +;// CONCATENATED MODULE: ./src/client-download.ts +// SPDX-License-Identifier: MIT +/** + * Downloads release for the SecHub CLI if not already loaded. + * + * @param version The version that should be downloaded + */ +function downloadClientRelease(context) { + const clientVersion = context.inputData.sechubCLIVersion; + if (clientVersion == null || clientVersion == '') { + throw new Error('No SecHub client version defined!'); + } + if (external_fs_.existsSync(context.clientExecutablePath)) { + core.debug(`Client already downloaded - skip download. Path:${context.clientExecutablePath}`); + return; + } + const secHubZipFilePath = `${context.clientDownloadFolder}/sechub.zip`; + const zipDownloadUrl = `https://github.com/mercedes-benz/sechub/releases/download/v${clientVersion}-client/sechub-cli-${clientVersion}.zip`; + core.debug(`SecHub-Client download URL: ${zipDownloadUrl}`); + core.debug(`SecHub-Client download folder: ${context.clientDownloadFolder}`); + shellExecOrFail(`mkdir ${context.clientDownloadFolder} -p`); + shellExecOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); + shellExecOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); + shellExecOrFail(`chmod +x ${secHubZipFilePath}`); +} +;// CONCATENATED MODULE: ./src/launcher.ts +// SPDX-License-Identifier: MIT -main().catch(handleError); -async function main() { - const scanSettings = initScan(); - const exitCode = executeScan(scanSettings.configParameter, scanSettings.reportFormats[0]); - await postScan(scanSettings.reportFormats, exitCode); + + + + + + + +async function launch() { + const context = createContext(); + init(context); + const exitCode = executeScan(context); + await postScan(context, exitCode); } +const LAUNCHER_CONTEXT_DEFAULTS = { + inputData: emptyInputDataDefaults, + reportFormats: ['json'], + clientDownloadFolder: '', + configParameter: null, + clientExecutablePath: '', +}; /** - * Initializes the scan and returns required scan settings. + * Create scan settings */ -function initScan() { +function createContext() { var _a, _b; - initEnvironmentVariables(); - downloadRelease(sechubCLIVersion); - const includeFolders = (_a = input_includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); - const excludeFolders = (_b = input_excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); - const configParameter = initSecHubJson(configPath, includeFolders, excludeFolders); - const reportFormats = initReportFormats(input_reportFormats); + const gitHubInputData = resolveGitHubInputData(); + const clientVersion = gitHubInputData.sechubCLIVersion; + // client + const expression = /\./gi; + const clientVersionSubFolder = clientVersion.replace(expression, '_'); // avoid . inside path from user input + const clientDownloadFolder = `${getWorkspaceParentDir()}/runtime/client/${clientVersionSubFolder}`; + const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; + const includeFolders = (_a = gitHubInputData.includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); + const excludeFolders = (_b = gitHubInputData.excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); + const configParameter = initSecHubJson(gitHubInputData.configPath, includeFolders, excludeFolders); + const reportFormats = initReportFormats(gitHubInputData.reportFormats); return { configParameter: configParameter, reportFormats: reportFormats, + inputData: gitHubInputData, + clientDownloadFolder: clientDownloadFolder, + clientExecutablePath: clientExecutablePath, }; } +function init(context) { + initEnvironmentVariables(context.inputData); + downloadClientRelease(context); +} /** * Executes the scan. * @param configParameter Parameter for the sechub.json path. Can be null if the file was created by the action. * @param format Report format that should be downloaded */ -function executeScan(configParameter, format) { - const exitCode = scan(configParameter, format).code; +function executeScan(context) { + // TODO 2024-01-19: de-jcup: here only the first report format is used... is this not a bug? + const exitCode = scan(context.reportFormats[0], context).code; logExitCode(exitCode); return exitCode; } -/** - * Executes several actions after the scan finished. - * @param reportFormats formats in which the report should be downloaded - * @param exitCode exit code from the scan - */ -async function postScan(reportFormats, exitCode) { - const jsonReport = downloadReports(reportFormats.slice(1)); +async function postScan(context, exitCode) { + const jsonReport = downloadReports(context, context.reportFormats.slice(1)); reportOutputs(jsonReport); await uploadArtifact(settings_namespaceObject.vz, getFiles(settings_namespaceObject.nl)); - if (exitCode !== 0 && failJobOnFindings === 'true') { + if (exitCode !== 0 && context.inputData.failJobOnFindings === 'true') { failAction(exitCode); } } +;// CONCATENATED MODULE: ./src/main.ts +// SPDX-License-Identifier: MIT + + +main().catch(handleError); +async function main() { + // Seperated launcher and main methd. + // Reason: launch mechanism would be loaded on imports + // before we can handle mocking in integration tests! + await launch(); +} + })(); module.exports = __webpack_exports__; diff --git a/github-actions/scan/package.json b/github-actions/scan/package.json index 8910487430..b1eca1b0f1 100644 --- a/github-actions/scan/package.json +++ b/github-actions/scan/package.json @@ -5,9 +5,13 @@ "main": "dist/main.js", "scripts": { "build": "ncc build src/main.ts", + "cleanBuild": "ncc cache clean;ncc build src/main.ts", "lint": "eslint src", "prettier": "npx prettier --write src", - "test": "npx jest" + "test": "npx jest", + "test-x": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", + "integration-test": "npx jest --runInBand --testPathPattern='integrationtest.test.ts'" + }, "license": "MIT", "dependencies": { diff --git a/github-actions/scan/src/cli-helper.ts b/github-actions/scan/src/cli-helper.ts deleted file mode 100644 index 8bcc1dd115..0000000000 --- a/github-actions/scan/src/cli-helper.ts +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT - -import * as core from '@actions/core'; -import * as shell from 'shelljs'; -import * as settingsFile from './settings.json'; -import { SecHubJson } from './types'; -import * as configFile from './sechub.json'; -import {secHubCli} from "./sechub-cli"; -import {getWorkspaceParentDir} from "./fs-helper"; - -/** - * Downloads a release for the SecHub CLI. - * @param version The version that should be downloaded - */ -export function downloadRelease(version: string): void { - const zipUrl = `https://github.com/mercedes-benz/sechub/releases/download/v${version}-client/sechub-cli-${version}.zip`; - core.debug('SecHub-Url: ' + zipUrl); - const secHubZip = `${getWorkspaceParentDir()}/sechub.zip`; - shell.exec(`curl -L ${zipUrl} -o ${secHubZip}`); - shell.exec(`unzip -o ${secHubZip} -d ${getWorkspaceParentDir()}`); - shell.exec(`chmod +x ${secHubCli}`); -} - -/** - * Creates the sechub.json with the given user input values. - * @param includeFolders Which folders should be included - * @param excludeFolders Which folders should be excluded - */ -export function createSecHubJsonFile(includeFolders: string[] | null, excludeFolders: string[] | null) { - core.info('Config-Path was not found. Config will be manually created...'); - const secHubJson = createSecHubJson(includeFolders, excludeFolders); - const stringifiedSecHubJson = JSON.stringify(secHubJson); - core.debug('SecHub-Config: ' + stringifiedSecHubJson); - - shell.ShellString(stringifiedSecHubJson).to(settingsFile.secHubJsonFileName); -} - -/** - * Creates the object for the sechub.json with the given user input values. - * @param includeFolders Which folders should be included - * @param excludeFolders Which folders should be excluded - */ -function createSecHubJson(includeFolders: string[] | null, excludeFolders: string[] | null): SecHubJson { - const sechubJson: SecHubJson = configFile; - if (includeFolders) { - sechubJson.codeScan.fileSystem.folders = includeFolders; - } - - if (excludeFolders) { - sechubJson.codeScan.excludes = excludeFolders; - } - return sechubJson; -} diff --git a/github-actions/scan/src/client-download.ts b/github-actions/scan/src/client-download.ts new file mode 100644 index 0000000000..8cb27da3f2 --- /dev/null +++ b/github-actions/scan/src/client-download.ts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +import * as fs from 'fs'; +import * as core from '@actions/core'; +import { shellExecOrFail } from './fs-helper'; +import { LaunchContext } from './launcher'; + +/** + * Downloads release for the SecHub CLI if not already loaded. + * + * @param version The version that should be downloaded + */ +export function downloadClientRelease(context: LaunchContext): void { + const clientVersion = context.inputData.sechubCLIVersion; + + if (fs.existsSync(context.clientExecutablePath)) { + core.debug(`Client already downloaded - skip download. Path:${context.clientExecutablePath}`); + return; + } + + const secHubZipFilePath = `${context.clientDownloadFolder}/sechub.zip`; + const zipDownloadUrl = `https://github.com/mercedes-benz/sechub/releases/download/v${clientVersion}-client/sechub-cli-${clientVersion}.zip`; + + core.debug(`SecHub-Client download URL: ${zipDownloadUrl}`); + core.debug(`SecHub-Client download folder: ${context.clientDownloadFolder}`); + + shellExecOrFail(`mkdir ${context.clientDownloadFolder} -p`); + + shellExecOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); + shellExecOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); + shellExecOrFail(`chmod +x ${secHubZipFilePath}`); +} + diff --git a/github-actions/scan/src/configuration-builder.ts b/github-actions/scan/src/configuration-builder.ts new file mode 100644 index 0000000000..495e1ddf12 --- /dev/null +++ b/github-actions/scan/src/configuration-builder.ts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +import * as core from '@actions/core'; +import * as shell from 'shelljs'; +import { SecHubConfigurationModel } from './configuration-model'; + +/** + * Creates the sechub.json configuration file with the given user input values. + * + * @param includeFolders Which folders should be included + * @param excludeFolders Which folders should be excluded + */ +export function createSecHubConfigJsonFile(secHubJsonFilePath:string, includeFolders: string[] | null, excludeFolders: string[] | null) { + core.info('Config-Path was not found. Config will be created.'); + const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); + const stringifiedSecHubJson = JSON.stringify(secHubJson); + core.debug('SecHub-Config: ' + stringifiedSecHubJson); + + shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); +} + +/** + * Creates a sechub configuration model object for given user input values. + * + * @param includeFolders Which folders should be included + * @param excludeFolders Which folders should be excluded + * + * @returns model + */ +export function createSecHubConfigurationModel(includeFolders: string[] | null, excludeFolders: string[] | null): SecHubConfigurationModel { + const sechubJson: SecHubConfigurationModel = { + 'apiVersion' : '1.0' + }; + + if (sechubJson.codeScan==null){ + sechubJson.codeScan={ + }; + } + if (includeFolders) { + + if (sechubJson.codeScan.fileSystem==null){ + sechubJson.codeScan.fileSystem={ + }; + } + + sechubJson.codeScan.fileSystem.folders = includeFolders; + } + + if (excludeFolders) { + sechubJson.codeScan.excludes = excludeFolders; + } + return sechubJson; +} diff --git a/github-actions/scan/src/configuration-model.ts b/github-actions/scan/src/configuration-model.ts new file mode 100644 index 0000000000..8e2d7cb619 --- /dev/null +++ b/github-actions/scan/src/configuration-model.ts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +/** + * SecHub configuration model + */ +export type SecHubConfigurationModel = { + apiVersion: string; + codeScan?: CodeScan; +}; + +type CodeScan = { + fileSystem?: FileSystem; + excludes?: string[]; +}; + +type FileSystem = { + folders?: string[]; +}; diff --git a/github-actions/scan/src/environment.ts b/github-actions/scan/src/environment.ts new file mode 100644 index 0000000000..3236d0dd59 --- /dev/null +++ b/github-actions/scan/src/environment.ts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +import * as shell from 'shelljs'; +import { GitHubInputData } from './input'; + +/** + * Sets the necessary environment variables with the user input values. + */ +export function initEnvironmentVariables(data: GitHubInputData): void { + shell.env['SECHUB_USERID'] = data.user; + shell.env['SECHUB_APITOKEN'] = data.apiToken; + shell.env['SECHUB_SERVER'] = data.url; + shell.env['SECHUB_PROJECT'] = data.projectName; + shell.env['SECHUB_DEBUG'] = data.debug; + shell.env['SECHUB_TRUSTALL'] = data.trustAll; +} diff --git a/github-actions/scan/src/exitcode.ts b/github-actions/scan/src/exitcode.ts new file mode 100644 index 0000000000..a0476a7716 --- /dev/null +++ b/github-actions/scan/src/exitcode.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +import * as core from '@actions/core'; + + +/* ---------------------------------- */ +/* -------- Exit codes -------------- */ +/* ---------------------------------- */ +// This is a mapping for client exit codes - origin can be found at constants.go +const exitCodeMap = new Map(); +exitCodeMap.set(0, 'OK'); +exitCodeMap.set(1, 'FAILED'); +exitCodeMap.set(3, 'ERROR - Missing parameters'); +exitCodeMap.set(4, 'ERROR - Config file does not exist or is not valid'); +exitCodeMap.set(5, 'ERROR - HTTP error has occurred'); +exitCodeMap.set(6, 'ERROR - Action was illegal'); +exitCodeMap.set(7, 'ERROR - Missing configuration parts'); +exitCodeMap.set(8, 'ERROR - IO error'); +exitCodeMap.set(9, 'ERROR - Config file not in expected format'); +exitCodeMap.set(10, 'ERROR - Job has been canceld on SecHub server'); + + +/** + * Logs the exit code and uses error method if not 0. + * @param code The given exit code + */ +export function logExitCode(code: number) { + const message = 'Exit code: ' + code+' . Description: '+exitCodeMap.get(code); + if (code === 0) { + core.info(message); + } else { + core.error(message); + } +} diff --git a/github-actions/scan/src/fs-helper.ts b/github-actions/scan/src/fs-helper.ts index ac25f22eb3..0b39218f18 100644 --- a/github-actions/scan/src/fs-helper.ts +++ b/github-actions/scan/src/fs-helper.ts @@ -3,6 +3,7 @@ import * as shell from 'shelljs'; import * as core from '@actions/core'; import * as path from 'path'; +import { ShellString } from 'shelljs'; /** * Get workspace directory. @@ -32,3 +33,24 @@ export function getFiles(pattern: string): string[] { return reportFiles; } + +export class ShellFailedWithExitCodeNotZeroError extends Error { + constructor(command: string, shellExecResult: ShellString) { + super(`Shell script call failed.\nExit code: ${shellExecResult.code}\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}`); + } +} + +/** + * Executes given command by shell - errors are handled + * @param command + * @throws ShellFailedWithExitCodeNotZeroError + * @returns shellstring + */ +export function shellExecOrFail(command: string): ShellString { + const shellExecResult = shell.exec(command); + + if ( shellExecResult.code!=0){ + throw new ShellFailedWithExitCodeNotZeroError(command, shellExecResult); + } + return shellExecResult; +} \ No newline at end of file diff --git a/github-actions/scan/src/init-scan.ts b/github-actions/scan/src/init-scan.ts index 558d75b581..6d3e4502f9 100644 --- a/github-actions/scan/src/init-scan.ts +++ b/github-actions/scan/src/init-scan.ts @@ -1,46 +1,33 @@ // SPDX-License-Identifier: MIT -import * as shell from 'shelljs'; -import * as input from './input'; import * as core from '@actions/core'; -import {createSecHubJsonFile} from './cli-helper'; +import { createSecHubConfigJsonFile as createSecHubConfigJsonFile } from './configuration-builder'; import { getValidFormatsFromInput } from './report-formats'; -export interface ScanSettings { - configParameter: string | null; - reportFormats: string[]; -} - -/** - * Sets the necessary environment variables with the user input values. - */ -export function initEnvironmentVariables(): void { - shell.env['SECHUB_USERID'] = input.user; - shell.env['SECHUB_APITOKEN'] = input.apiToken; - shell.env['SECHUB_SERVER'] = input.url; - shell.env['SECHUB_PROJECT'] = input.projectName; - shell.env['SECHUB_DEBUG'] = input.debug; -} - /** * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. - * @param configPath Path to the sechub.json + * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) * @param includeFolders list of folders to include to the scan * @param excludeFolders list of folders to exclude from the scan + * + * @returns resulting configuration file path */ -export function initSecHubJson(configPath: string, includeFolders: string[], excludeFolders: string[]): string | null { +export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFilePath: string, includeFolders: string[], excludeFolders: string[]): string | null { core.startGroup('Set config'); - if (!configPath) { - createSecHubJsonFile(includeFolders, excludeFolders); - return null; - } - core.info(`Config-Path was found: ${configPath}`); - const configParameter = `-configfile '${configPath}'`; + let configFilePath = customSecHubConfigFilePath; + if (configFilePath) { + core.info(`Config-Path was found: ${customSecHubConfigFilePath}`); + }else{ + createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); + configFilePath = secHubJsonFilePath; + } core.endGroup(); - return configParameter; + + return configFilePath; } + /** * Initializes the report formats and ensures there is at least one valid report format selected. * @param reportFormats formats in which the report should be downloaded diff --git a/github-actions/scan/src/input.ts b/github-actions/scan/src/input.ts index 44469d9b57..bdd83560b3 100644 --- a/github-actions/scan/src/input.ts +++ b/github-actions/scan/src/input.ts @@ -2,14 +2,66 @@ import * as core from '@actions/core'; -export const configPath = core.getInput('config-path'); -export const url = core.getInput('url'); -export const apiToken = core.getInput('api-token'); -export const user = core.getInput('user'); -export const projectName = core.getInput('project-name'); -export const sechubCLIVersion = core.getInput('version'); -export const debug = core.getInput('debug'); -export const includeFolders = core.getInput('include-folders'); -export const excludeFolders = core.getInput('exclude-folders'); -export const reportFormats = core.getInput('report-formats'); -export const failJobOnFindings = core.getInput('fail-job-with-findings'); +export const PARAM_CONFIG_PATH = 'config-path'; +export const PARAM_SECHUB_SERVER_URL = 'url'; +export const PARAM_API_TOKEN= 'api-token'; +export const PARAM_SECHUB_USER = 'user'; +export const PARAM_PROJECT_NAME = 'project-name'; +export const PARAM_CLIENT_VERSION='version'; +export const PARAM_DEBUG='debug'; +export const PARAM_INCLUDED_FOLDERS='include-folders'; +export const PARAM_EXCLUDED_FOLDERS='exclude-folders'; +export const PARAM_REPORT_FORMATS='report-formats'; +export const PARAM_FAIL_JOB_ON_FINDING='fail-job-with-findings'; +export const PARAM_TRUST_ALL='trust-all'; + +export interface GitHubInputData{ + configPath: string; + url : string; + apiToken: string; + user: string; + projectName: string; + sechubCLIVersion: string; + debug: string; + includeFolders: string; + excludeFolders: string; + reportFormats: string; + failJobOnFindings: string; + trustAll:string; + +} + +export const INPUT_DATA_DEFAULTS: GitHubInputData = { + configPath: '', + url : '', + apiToken: '', + user: '', + projectName: '', + sechubCLIVersion: '', + debug: '', + includeFolders: '', + excludeFolders: '', + reportFormats: '', + failJobOnFindings: '', + trustAll:'' +}; + +export function resolveGitHubInputData() : GitHubInputData { + return { + configPath : core.getInput(PARAM_CONFIG_PATH), + url : core.getInput(PARAM_SECHUB_SERVER_URL), + apiToken : core.getInput(PARAM_API_TOKEN), + user : core.getInput(PARAM_SECHUB_USER), + projectName : core.getInput(PARAM_PROJECT_NAME), + sechubCLIVersion : core.getInput(PARAM_CLIENT_VERSION), + debug : core.getInput(PARAM_DEBUG), + includeFolders : core.getInput(PARAM_INCLUDED_FOLDERS), + excludeFolders : core.getInput(PARAM_EXCLUDED_FOLDERS), + reportFormats : core.getInput(PARAM_REPORT_FORMATS), + failJobOnFindings : core.getInput(PARAM_FAIL_JOB_ON_FINDING), + trustAll : core.getInput(PARAM_TRUST_ALL), + + }; +} + + diff --git a/github-actions/scan/src/launcher.ts b/github-actions/scan/src/launcher.ts new file mode 100644 index 0000000000..4f17ac2d4f --- /dev/null +++ b/github-actions/scan/src/launcher.ts @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT + +import { failAction } from './action-helper'; +import { scan } from './sechub-cli'; +import { logExitCode } from './exitcode'; +import { getFiles, getWorkspaceParentDir } from './fs-helper'; +import { initReportFormats, initSecHubJson } from './init-scan'; +import { downloadReports, reportOutputs, uploadArtifact } from './post-scan'; +import { GitHubInputData, resolveGitHubInputData, INPUT_DATA_DEFAULTS } from './input'; +import { initEnvironmentVariables } from './environment'; +import { downloadClientRelease } from './client-download'; +import { exit } from 'shelljs'; + + + +/** + * Starts the launch process + * @returns launch context + */ +export async function launch(): Promise { + + const context = createContext(); + + init(context); + + executeScan(context); + + await postScan(context); + + return context; +} + +export interface LaunchContext { + inputData: GitHubInputData; + configFileLocation: string | null; + + /* json, html, spdx */ + reportFormats: string[]; + + clientDownloadFolder: string; + clientExecutablePath: string; + + lastClientExitCode: number; + runtimeFolder: string; + secHubJsonFilePath: string; +} + +export const LAUNCHER_CONTEXT_DEFAULTS: LaunchContext = { + inputData: INPUT_DATA_DEFAULTS, + reportFormats: ['json'], + clientDownloadFolder: '', + configFileLocation: null, + clientExecutablePath: '', + + lastClientExitCode: -1, + + secHubJsonFilePath: '', + runtimeFolder: '', +}; + +/** + * Create scan settings + */ +function createContext(): LaunchContext { + + const gitHubInputData = resolveGitHubInputData(); + + // client + const clientVersion = gitHubInputData.sechubCLIVersion; + + if (clientVersion == null || clientVersion == '') { + throw new Error('No SecHub client version defined!'); + } + + const expression = /\./gi; + const clientVersionSubFolder = clientVersion.replace(expression, '_'); // avoid . inside path from user input + const runtimeFolder = `${getWorkspaceParentDir()}/runtime`; + const clientDownloadFolder = `${runtimeFolder}/client/${clientVersionSubFolder}`; + const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; + + const includeFolders = gitHubInputData.includeFolders?.split(','); + const excludeFolders = gitHubInputData.excludeFolders?.split(','); + + const secHubJsonFilePath = `${runtimeFolder}/sechub.json`; + + const configParameter = initSecHubJson(secHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + + const reportFormats = initReportFormats(gitHubInputData.reportFormats); + + return { + configFileLocation: configParameter, + reportFormats: reportFormats, + inputData: gitHubInputData, + clientDownloadFolder: clientDownloadFolder, + clientExecutablePath: clientExecutablePath, + + lastClientExitCode: LAUNCHER_CONTEXT_DEFAULTS.lastClientExitCode, + + secHubJsonFilePath: secHubJsonFilePath, + runtimeFolder:runtimeFolder, + }; +} + +function init(context: LaunchContext) { + + initEnvironmentVariables(context.inputData); + + downloadClientRelease(context); +} + +/** + * Executes the scan. + * @param configParameter Parameter for the sechub.json path. Can be null if the file was created by the action. + * @param format Report format that should be downloaded + */ +function executeScan(context: LaunchContext) { + // TODO 2024-01-19: de-jcup: here only the first report format is used... is this not a bug? + scan(context.reportFormats[0], context); + + logExitCode(context.lastClientExitCode); +} + +async function postScan(context: LaunchContext): Promise { + if (context.lastClientExitCode > 1) { + // in this case this is an error and we cannot download the report - means fails always + failAction(context.lastClientExitCode); + return; + } + const jsonReport = downloadReports(context, context.reportFormats.slice(1)); + + /* reporting - analysis etc. */ + reportOutputs(jsonReport); + + /* upload artifact */ + await uploadArtifact(context, 'sechub scan-report', getFiles(`${context.runtimeFolder}/sechub_report_*.*`)); + + if (context.lastClientExitCode !== 0 && context.inputData.failJobOnFindings === 'true') { + failAction(context.lastClientExitCode); + } +} + + diff --git a/github-actions/scan/src/log-helper.ts b/github-actions/scan/src/log-helper.ts deleted file mode 100644 index c8347949fd..0000000000 --- a/github-actions/scan/src/log-helper.ts +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT - -import * as core from '@actions/core'; - -/** - * Logs the exit code and uses error method if not 0. - * @param code The given exit code - */ -export function logExitCode(code: number) { - const prefix = 'Exit code: '; - if (code === 0) { - core.info(prefix + code); - } else { - core.error(prefix + code); - } -} diff --git a/github-actions/scan/src/main.ts b/github-actions/scan/src/main.ts index d118084432..bcfbc6813f 100644 --- a/github-actions/scan/src/main.ts +++ b/github-actions/scan/src/main.ts @@ -1,63 +1,14 @@ // SPDX-License-Identifier: MIT -import {failAction, handleError} from './action-helper'; -import {downloadRelease} from './cli-helper'; -import { scan } from './sechub-cli'; -import { logExitCode } from './log-helper'; -import { getFiles } from './fs-helper'; -import {initEnvironmentVariables, initReportFormats, initSecHubJson, ScanSettings} from './init-scan'; -import { downloadReports, reportOutputs, uploadArtifact } from './post-scan'; -import * as input from './input'; -import * as settingsFile from './settings.json'; +import { launch } from './launcher'; +import { handleError } from './action-helper'; main().catch(handleError); async function main(): Promise { - const scanSettings = initScan(); - const exitCode = executeScan(scanSettings.configParameter, scanSettings.reportFormats[0]); - await postScan(scanSettings.reportFormats, exitCode); + // Seperated launcher and main methd. + // Reason: launch mechanism would be loaded on imports + // before we can handle mocking in integration tests! + await launch(); } -/** - * Initializes the scan and returns required scan settings. - */ -function initScan(): ScanSettings { - initEnvironmentVariables(); - downloadRelease(input.sechubCLIVersion); - - const includeFolders = input.includeFolders?.split(','); - const excludeFolders = input.excludeFolders?.split(','); - const configParameter = initSecHubJson(input.configPath, includeFolders, excludeFolders); - - const reportFormats = initReportFormats(input.reportFormats); - return { - configParameter: configParameter, - reportFormats: reportFormats, - }; -} - -/** - * Executes the scan. - * @param configParameter Parameter for the sechub.json path. Can be null if the file was created by the action. - * @param format Report format that should be downloaded - */ -export function executeScan(configParameter: string | null, format: string): number { - const exitCode = scan(configParameter, format).code; - logExitCode(exitCode); - return exitCode; -} - -/** - * Executes several actions after the scan finished. - * @param reportFormats formats in which the report should be downloaded - * @param exitCode exit code from the scan - */ -export async function postScan(reportFormats: string[], exitCode: number): Promise { - const jsonReport = downloadReports(reportFormats.slice(1)); - reportOutputs(jsonReport); - await uploadArtifact(settingsFile.artifactName, getFiles(settingsFile.filePattern)); - - if (exitCode !== 0 && input.failJobOnFindings === 'true') { - failAction(exitCode); - } -} diff --git a/github-actions/scan/src/post-scan.ts b/github-actions/scan/src/post-scan.ts index be8fa06578..69fcc29304 100644 --- a/github-actions/scan/src/post-scan.ts +++ b/github-actions/scan/src/post-scan.ts @@ -1,19 +1,19 @@ // SPDX-License-Identifier: MIT -import * as core from '@actions/core'; import * as artifact from '@actions/artifact'; +import * as core from '@actions/core'; +import * as fs from 'fs'; import * as shell from 'shelljs'; -import { getReport } from './sechub-cli'; import { getWorkspaceDir } from './fs-helper'; -import { logExitCode } from './log-helper'; -import * as input from './input'; -import * as fs from 'fs'; +import { LaunchContext } from './launcher'; +import { logExitCode } from './exitcode'; +import { getReport } from './sechub-cli'; /** * Downloads the reports for the given formats. * @param formats formats in which the report should be downloaded */ -export function downloadReports(formats: string[]): object | undefined { +export function downloadReports(context: LaunchContext, formats: string[]): object | undefined { core.startGroup('Download Reports'); if (formats.length === 0) { core.info('No more formats'); @@ -25,8 +25,8 @@ export function downloadReports(formats: string[]): object | undefined { core.debug('JobUUID: ' + jobUUID); formats.forEach((format) => { core.info(`Get Report as ${format}`); - const exitCode = getReport(jobUUID, input.projectName, format); - logExitCode(exitCode ? exitCode.code : 0); + getReport(jobUUID, format,context); + logExitCode(context.lastClientExitCode); }); } core.endGroup(); @@ -55,19 +55,23 @@ function loadJsonReport(): object | undefined { * @param name Name for the zip file. * @param paths All file paths to include into the artifact. */ -export async function uploadArtifact(name: string, paths: string[]) { +export async function uploadArtifact(context: LaunchContext, name: string, paths: string[]) { core.startGroup('Upload artifacts'); try { const artifactClient = artifact.create(); const artifactName = name; const options = { continueOnError: true }; - const workspace = getWorkspaceDir(); - shell.exec(`ls ${workspace}`); - core.debug('rootDirectory: ' + workspace); - core.debug('files: ' + paths); + const rootDirectory = context.runtimeFolder; + core.debug('rootDirectory: ' + rootDirectory); + if (core.isDebug()){ + shell.exec(`ls ${rootDirectory}`); + } + core.debug('paths: ' + paths); - await artifactClient.uploadArtifact(artifactName, paths, workspace, options); + await artifactClient.uploadArtifact(artifactName, paths, rootDirectory, options); + core.debug('artifact upload done'); + } catch (e: unknown) { const message = e instanceof Error ? e.message : 'Unknown error'; core.error(`ERROR while uploading artifacts: ${message}`); @@ -88,6 +92,7 @@ function getFieldFromJsonReport(field: string, jsonData: any): any { // Traverse the JSON object to find the requested field let currentKey = jsonData; for (const key of keys) { + // eslint-disable-next-line no-prototype-builtins if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { currentKey = currentKey[key]; } else { @@ -122,16 +127,19 @@ function getJsonReportFileName(): string { */ export function reportOutputs(jsonData: any): void { core.startGroup('Reporting outputs to GitHub'); + const findings = analyzeFindings(jsonData); const trafficLight = getFieldFromJsonReport('trafficLight', jsonData); const totalFindings = getFieldFromJsonReport('result.count', jsonData); const humanReadableSummary = buildSummary(trafficLight, totalFindings, findings); + setOutput('scan-trafficlight', trafficLight, 'string'); setOutput('scan-findings-count', totalFindings, 'number'); setOutput('scan-findings-high', findings.highCount, 'number'); setOutput('scan-findings-medium', findings.mediumCount, 'number'); setOutput('scan-findings-low', findings.lowCount, 'number'); setOutput('scan-readable-summary', humanReadableSummary, 'string'); + core.endGroup(); } diff --git a/github-actions/scan/src/sechub-cli.ts b/github-actions/scan/src/sechub-cli.ts index 876e9db193..776ffb0af8 100644 --- a/github-actions/scan/src/sechub-cli.ts +++ b/github-actions/scan/src/sechub-cli.ts @@ -1,34 +1,32 @@ // SPDX-License-Identifier: MIT import * as shell from 'shelljs'; -import { ShellString } from 'shelljs'; -import {getWorkspaceParentDir} from "./fs-helper"; - -export const secHubCli = `${getWorkspaceParentDir()}/platform/linux-386/sechub`; - +import { LaunchContext } from './launcher'; +import * as core from '@actions/core'; /** - * Executes the scan method of the SecHub CLI. + * Executes the scan method of the SecHub CLI. Sets the client exitcode inside context. * @param parameter Parameters to execute the scan with * @param format Report format that should be fetched + * @param context: launch context */ -export function scan(parameter: string | null, format: string): ShellString { - return shell.exec(`${secHubCli} ${parameter} -reportformat ${format} scan`); +export function scan(format: string, context: LaunchContext) { + const shellString = shell.exec(`${context.clientExecutablePath} -configfile ${context.configFileLocation} -output ${context.runtimeFolder} -reportformat ${format} scan`); + context.lastClientExitCode= shellString.code; + + if (context.lastClientExitCode!=0){ + core.error(shellString.stderr); + } } /** - * Executes the getReport method of the SecHub CLI. + * Executes the getReport method of the SecHub CLI. Sets the client exitcode inside context. * @param jobUUID job UUID for which the report should be downloaded * @param projectName name of the project for which the report should be downloaded * @param format format in which the report should be downloaded + * @param context: launch context */ -export function getReport(jobUUID: string, projectName: string, format: string): ShellString { - return shell.exec(`${secHubCli} -jobUUID ${jobUUID} -project ${projectName} --reportformat ${format} getReport`); +export function getReport(jobUUID: string, format: string, context: LaunchContext) { + const shellString = shell.exec(`${context.clientExecutablePath} -jobUUID ${jobUUID} -project ${context.inputData.projectName} --reportformat ${format} getReport`); + context.lastClientExitCode= shellString.code; } -/** - * Executes the markFalsePositives method of the SecHub CLI. - * @param falsePositivePath path to the false positive file - */ -export function markFalsePositives(falsePositivePath: string): ShellString { - return shell.exec(`${secHubCli} -file ${falsePositivePath} markFalsePositives`); -} diff --git a/github-actions/scan/src/sechub.json b/github-actions/scan/src/sechub.json deleted file mode 100644 index 653f069c12..0000000000 --- a/github-actions/scan/src/sechub.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "apiVersion": "1.0", - "codeScan": { - "fileSystem": { - "folders": ["."] - }, - "excludes": [] - } -} diff --git a/github-actions/scan/src/settings.json b/github-actions/scan/src/settings.json deleted file mode 100644 index 22bf9ac00e..0000000000 --- a/github-actions/scan/src/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "artifactName": "sechub scan-report", - "filePattern": "sechub_report_*.*", - "secHubJsonFileName": "sechub.json" -} diff --git a/github-actions/scan/src/types.ts b/github-actions/scan/src/types.ts deleted file mode 100644 index 70387a23b3..0000000000 --- a/github-actions/scan/src/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT - -export type Settings = { - artifactName: string; - filePattern: string; - secHubJsonFileName: string; -}; - -export type SecHubJson = { - apiVersion: string; - codeScan: CodeScan; -}; - -type CodeScan = { - fileSystem: FileSystem; - excludes: string[]; -}; - -type FileSystem = { - folders: string[]; -}; From 46abc6ea975b65a7250bdd31afa7c9857194be85 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Fri, 26 Jan 2024 07:28:24 +0100 Subject: [PATCH 06/30] Automated integration test setup #2839 - switched setup, start, stop parts for integration testing to bash scripts only - improved integration test setup parts - changed CI/CD build behaviors for "feature-" and "gha_feature-*" branches - added documentation - fixed typos in service logs --- .github/workflows/github-action-scan.yml | 75 ++- .github/workflows/gradle.yml | 4 +- .gitignore | 3 + github-actions/scan/README.adoc | 40 +- ....test.ts => configuration-builder.test.ts} | 6 +- .../scan/__test__/init-scan.test.ts | 4 +- .../scan/__test__/integrationtest.test.ts | 95 +++- .../scan/__test__/integrationtest/01-start.sh | 170 +++++++ .../integrationtest/03-init_sechub_data.sh | 80 ++++ .../scan/__test__/integrationtest/05-stop.sh | 26 ++ .../__test__/integrationtest/start_pds.sh | 53 +++ .../integrationtest/start_sechub_server.sh | 48 ++ .../scan/__test__/integrationtest/stop_pds.sh | 13 + .../integrationtest/stop_sechub_server.sh | 13 + .../gha_integrationtest_pds-config.json | 24 + .../test-executor-codescan-green.json | 39 ++ .../test-executor-codescan-red.json | 39 ++ .../test-executor-codescan-yellow.json | 39 ++ .../test-scripts/pds-codescan-demo-green.sh | 5 + .../test-scripts/pds-codescan-demo-red.sh | 5 + .../test-scripts/pds-codescan-demo-yellow.sh | 5 + .../integrationtest/test-sources/testdata.txt | 1 + .../__test__/integrationtest/testframework.ts | 21 + .../integrationtest/wait_server_alive.sh | 31 ++ .../scan/__test__/post-scan.test.ts | 88 +++- .../scan/__test__/report-format.test.ts | 2 +- .../scan/__test__/sechub-cli.test.ts | 58 +++ .../scan/__test__/setup-integrationtest.sh | 44 -- github-actions/scan/dist/exec-child1.js | 39 -- github-actions/scan/dist/index.js | 426 ++++++++++-------- github-actions/scan/package.json | 7 +- github-actions/scan/src/client-download.ts | 12 +- .../scan/src/configuration-builder.ts | 2 +- github-actions/scan/src/exitcode.ts | 4 +- github-actions/scan/src/fs-helper.ts | 57 ++- github-actions/scan/src/json-helper.ts | 26 ++ github-actions/scan/src/launcher.ts | 49 +- github-actions/scan/src/post-scan.ts | 136 +++--- github-actions/scan/src/sechub-cli.ts | 19 +- .../mock/MockedAdapterSetupService.java | 2 +- sechub-developertools/scripts/sdc.sh | 101 ++++- .../documents/techdoc/01_development.adoc | 6 +- ...heduleGrantUserAccessToProjectService.java | 4 +- sechub.json | 46 +- 44 files changed, 1490 insertions(+), 477 deletions(-) rename github-actions/scan/__test__/{ci-helper.test.ts => configuration-builder.test.ts} (58%) create mode 100755 github-actions/scan/__test__/integrationtest/01-start.sh create mode 100755 github-actions/scan/__test__/integrationtest/03-init_sechub_data.sh create mode 100755 github-actions/scan/__test__/integrationtest/05-stop.sh create mode 100755 github-actions/scan/__test__/integrationtest/start_pds.sh create mode 100755 github-actions/scan/__test__/integrationtest/start_sechub_server.sh create mode 100755 github-actions/scan/__test__/integrationtest/stop_pds.sh create mode 100755 github-actions/scan/__test__/integrationtest/stop_sechub_server.sh create mode 100644 github-actions/scan/__test__/integrationtest/test-config/gha_integrationtest_pds-config.json create mode 100644 github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-green.json create mode 100644 github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-red.json create mode 100644 github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-yellow.json create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh create mode 100644 github-actions/scan/__test__/integrationtest/test-sources/testdata.txt create mode 100644 github-actions/scan/__test__/integrationtest/testframework.ts create mode 100755 github-actions/scan/__test__/integrationtest/wait_server_alive.sh create mode 100644 github-actions/scan/__test__/sechub-cli.test.ts delete mode 100755 github-actions/scan/__test__/setup-integrationtest.sh delete mode 100644 github-actions/scan/dist/exec-child1.js create mode 100644 github-actions/scan/src/json-helper.ts diff --git a/.github/workflows/github-action-scan.yml b/.github/workflows/github-action-scan.yml index 77114d385d..72a12e74e5 100644 --- a/.github/workflows/github-action-scan.yml +++ b/.github/workflows/github-action-scan.yml @@ -1,7 +1,10 @@ # SPDX-License-Identifier: MIT -name: Build SecHub GitHub Action +name: Build SecHub GHA (scan) -on: workflow_dispatch +on: + push: + branches: + - 'gha_*' jobs: build-scan: @@ -19,14 +22,76 @@ jobs: # We do not define a dedicated node version here, we just use the default environment # which should be the default environment for the github actions runtime as well uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 - + - name: Clean install run: npm ci - name: Build run: npm run build --if-present - - name: Run tests + - name: Run unit tests run: npm test - + + - name: Setup integration test data + id : version-selector + run: | + echo "sechub_server_version=1.4.1" >> "$GITHUB_ENV" + echo "sechub_server_port=8443" >> "$GITHUB_ENV" + echo "pds_version=1.4.0" >> "$GITHUB_ENV" + echo "pds_port=8444" >> "$GITHUB_ENV" + + #- name: Cache SecHub server download + # # Cache V4 release: 13aacd865c20de90d75de3b17ebe84f7a17d57d2 + # uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 + # with: + # path: ./build/sechub-runtime/server/${{ steps.version-selector.outputs.sechub_server_version }}/ + # key: ${{ runner.os }}-sechub-server-${{ steps.version-selector.outputs.sechub_server_version }} + # + #- name: Cache PDS download + # # Cache V4 release: 13aacd865c20de90d75de3b17ebe84f7a17d57d2 + # uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 + # with: + # path: ./build/sechub-runtime/pds/${{ steps.version-selector.outputs.pds_version }}/ + # key: ${{ runner.os }}-pds-${{ steps.version-selector.outputs.pds_version }} + + - name: Set up JDK 17 (to run servers) + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 + with: + java-version: 17 + distribution: temurin + + + - name: Start integration test servers + working-directory: ./github-actions/scan/__test__/integrationtest/ + run: ./01-start.sh $sechub_server_version $sechub_server_port $pds_version $pds_port + + - name: Init integration test data + working-directory: ./github-actions/scan/__test__/integrationtest/ + run: ./03-init_sechub_data.sh $sechub_server_port $pds_port + + - name: Run integration tests + run: npm run integration-test + + - name: Cleanup integration tests + working-directory: ./github-actions/scan/__test__/integrationtest/ + run: ./05-stop.sh $sechub_server_port $pds_port + + # ------------------------------------ Archive runtime logs------------------- + - name: Archive runtime logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: sechub-runtime-logiles + path: ./build/sechub-runtime/**/*.log + retention-days: 14 + # ------------------------------------ Archive report ----------------------- + - name: Archive report + if: always() + uses: actions/upload-artifact@v3 + with: + name: sechub-report + path: sechub-report*.json + retention-days: 14 + + diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 342f17fa18..79250bddcc 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,8 +9,10 @@ on: # So this branch is only for github pages. See https://github.com/mercedes-benz/sechub/issues/481 # for details - documentation - # We ignore everything where tag starts with v* - this is done by release build! + # ignore branches for github actions only - e.g. "gha_feature-12345-testfeature" + - gha_* tags-ignore: + # We ignore everything where tag starts with v* - this is done by release build! - v* # enable manual triggering of workflow workflow_dispatch: diff --git a/.gitignore b/.gitignore index 53f14a4885..12f6d6ae53 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,6 @@ copy/ # Node node_modules/ + +# github-action integration test +.sechub-gha/ diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc index 822eeca8eb..71bc8b1225 100644 --- a/github-actions/scan/README.adoc +++ b/github-actions/scan/README.adoc @@ -9,8 +9,8 @@ This GitHub action uses the SecHub cli to scan the repository for security issue To be able to use this action you need a SecHub project. Check the https://mercedes-benz.github.io/sechub/[documentation] on how to set one up. -```yaml - +[source,yaml] +---- - uses: mercedes-benz/sechub/github-actions/scan@72a27282da80952e6fadcef452c6a9085971c688 with: # OPTIONAL: Path to sechub.json for manual configuration. If no value is set the input parameters will be used to create it for the scan.' @@ -100,19 +100,47 @@ npm run test ==== Integration-Test As a precondition to run the integration tests locally you have to -- start a new SecHub server in integration test mode -- execute `__test__/setup-integrationtest.sh` +- execute `__test__/01-start.sh $secHubServerVersion $sechubServerPortNr $pdsVersion $pdsPortNr` + +TIP: You can also start a SecHub server and a PDS (both in integration test mode) instead of using the `01-start` script. -When this has been done, you can execute this command multiple times: +After the script has been executed, you can execute integration tests multiple times via following command: [source,npm] ---- npm run integration-test ---- -To enable full debug output: +To enable full debug output in integration tests please execute following before running the integration tests: [source,npm] ---- export SECHUB_DEBUG=true ---- +==== Debug tests +The unit and also the integration tests are written with `jest` test framework. + +===== Setup + +**VSCodium** + +Used extensions + +- Test explorer +- Jest Test explorer +- Jest + +In this setup the tests can be executed from sidebar and from links created inside editor. + +But ... unfortunately, the Jest UI integration works only for npm script "test" which is normally not used for +integration tests (to handle them special). + +If you want to debug an integration test, there is a workaround necessary: + +- open `package.json` and look into section `scripts` +- switch `test-debug-all` to `test` and name former `test` script entry to `test-debug-not-integrationtest` + (but please do not push this - otherwise build will fail on integration test!) +- restart your VSCode/VSCodium instance (if integration tests are not listed in test explorer) +- debug the parts, fix it etc. +- switch `test` script entry to `test-debug-all` and `test-debug-not-integrationtest` to `test`. +- if necessary push fixes/changes to remote... diff --git a/github-actions/scan/__test__/ci-helper.test.ts b/github-actions/scan/__test__/configuration-builder.test.ts similarity index 58% rename from github-actions/scan/__test__/ci-helper.test.ts rename to github-actions/scan/__test__/configuration-builder.test.ts index 983294280c..461a068b51 100644 --- a/github-actions/scan/__test__/ci-helper.test.ts +++ b/github-actions/scan/__test__/configuration-builder.test.ts @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT -import * as cli from '../src/configuration-builder'; +import * as configBuilder from '../src/configuration-builder'; jest.mock('@actions/core'); -describe('cli-helper', function() { +describe('conifguration-builder', function() { it('createSecHubConfigModel creates with null always a model with api version 1.0.0', function () { /* execute */ - const model= cli.createSecHubConfigurationModel(null,null); + const model= configBuilder.createSecHubConfigurationModel(null,null); /* test */ expect(model.apiVersion).toEqual('1.0'); diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts index 80d224e35b..c1af048faf 100644 --- a/github-actions/scan/__test__/init-scan.test.ts +++ b/github-actions/scan/__test__/init-scan.test.ts @@ -23,7 +23,7 @@ describe('initSecHubJson', function () { const parameter = initSecHubJson('runtime/sechub.json','', [], []); /* test */ - expect(parameter).toBeNull(); + expect(parameter).toEqual('runtime/sechub.json'); expect(createSecHubConfigJsonFile).toHaveBeenCalledTimes(1); }); }); @@ -37,7 +37,7 @@ describe('initReportFormats', function () { expect(() => initReportFormats(reportFormats)).toThrow(Error); }); - it('adds missing json report at the beginning', function () { + it('json rp missing json report at the beginning', function () { /* prepare */ const reportFormats = 'html'; diff --git a/github-actions/scan/__test__/integrationtest.test.ts b/github-actions/scan/__test__/integrationtest.test.ts index 83bca8f889..f3a9cf2af6 100644 --- a/github-actions/scan/__test__/integrationtest.test.ts +++ b/github-actions/scan/__test__/integrationtest.test.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT import * as launcher from '../src/launcher'; +import { IntegrationTestContext as IntegrationTestContext } from './integrationtest/testframework'; import * as shell from 'shelljs'; import { isDebug, debug, getInput } from '@actions/core'; import { info } from '@actions/core'; @@ -9,16 +10,38 @@ import { warning } from '@actions/core'; import * as input from '../src/input'; import { LaunchContext } from '../src/launcher'; import { create } from '@actions/artifact'; +import { getWorkspaceDir } from '../src/fs-helper'; +import { getFieldFromJsonReport } from '../src/json-helper'; + jest.mock('@actions/core'); jest.mock('@actions/artifact'); + /* - * This is an integration test suite for github-action "scan". - * As precondition you have to start a local sechub server in integration test mode and execute "setup-integrationtest.sh". - * After this is done, you can execute these tests. +* This is an integration test suite for github-action "scan". +* As precondition you have to call "01-start.sh" and "03-init_sechub_data.sh" (please look into scripts for an example and more details, or +* call 'sdc -bgh' to do a full build for github action which does automatically execute the scripts and this test) +* +* After start and prepare scripts have finished you can execute the integration tests via "npm run integration-test" +* +* At the end the servers can be stopped with "05-stop.sh" (please look into script for an example and more details) +* (This is an explanation to start the tests locally - the github action workflow "github-action-scan.yml" does it in exact same way for CI/CD) +* */ - const sechub_debug = shell.env['SECHUB_DEBUG']; -const debug_enabled = sechub_debug=='true'; +const debug_enabled = sechub_debug == 'true'; + +const integrationTestContext = new IntegrationTestContext(); + +integrationTestContext.workspaceDir = getWorkspaceDir(); + +integrationTestContext.serverVersion = '1.4.0'; // TODO make this configurable - in our start script it is already configurable +integrationTestContext.serverPort = 8443; // TODO make this configurable - in our start script it is already configurable +integrationTestContext.serverUserId = 'int-test_superadmin'; // TODO make this configurable - in our start script it is already configurable +integrationTestContext.serverApiToken = 'int-test_superadmin-pwd'; // TODO make this configurable - in our start script it is already configurable + +integrationTestContext.finish(); + +const mockedInputMap = new Map(); beforeEach(() => { jest.resetAllMocks(); @@ -26,7 +49,7 @@ beforeEach(() => { (getInput as jest.Mock).mockImplementation((name) => { return mockedInputMap.get(name); }); - if (debug_enabled){ + if (debug_enabled) { (debug as jest.Mock).mockImplementation((message) => { console.debug('gh-debug: %s', message); }); @@ -34,7 +57,6 @@ beforeEach(() => { return true; }); } - (info as jest.Mock).mockImplementation((message) => { console.log('gh-info: %s', message); @@ -49,21 +71,18 @@ beforeEach(() => { (create as jest.Mock).mockName('artifactClient'); (create as jest.Mock).mockImplementation(() => { return { - 'uploadArtifact' : jest.fn(), + 'uploadArtifact': jest.fn(), }; }); }); -const mockedInputMap = new Map(); function initInputMap() { mockedInputMap.clear(); - - mockedInputMap.set(input.PARAM_SECHUB_SERVER_URL, 'https://localhost:8443'); - mockedInputMap.set(input.PARAM_SECHUB_USER, 'int-test_superadmin'); - mockedInputMap.set(input.PARAM_API_TOKEN, 'int-test_superadmin-pwd'); - mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project'); + mockedInputMap.set(input.PARAM_SECHUB_SERVER_URL, `https://localhost:${integrationTestContext.serverPort}`); + mockedInputMap.set(input.PARAM_SECHUB_USER, `${integrationTestContext.serverUserId}`); + mockedInputMap.set(input.PARAM_API_TOKEN, `${integrationTestContext.serverApiToken}`); mockedInputMap.set(input.PARAM_CLIENT_VERSION, '1.2.0'); @@ -71,25 +90,63 @@ function initInputMap() { mockedInputMap.set(input.PARAM_TRUST_ALL, 'true'); // self signed certificate in test... } +describe('integrationtest codescan generated config', () => { + test('codescan green', () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-1'); + + /* execute */ + const launchPromise = launcher.launch(); + + /* test */ + assertLastClientExitCode(launchPromise, 0); + assertTrafficLight(launchPromise, 'GREEN'); -describe('integrationtest', function () { - test('integrationtest 1', function () { + }); + test('codescan yellow', function () { /* prepare */ initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-2'); /* execute */ const launchPromise = launcher.launch(); /* test */ - assertExitCode(launchPromise, 0); + assertLastClientExitCode(launchPromise, 0); + assertTrafficLight(launchPromise, 'YELLOW'); + + }); + + test('codescan red', function () { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-3'); + /* execute */ + const launchPromise = launcher.launch(); + + /* test */ + assertLastClientExitCode(launchPromise, 1); // exit code 1, because RED + assertTrafficLight(launchPromise, 'RED'); }); }); -async function assertExitCode(launchPromise: Promise, exitCode: number) { +async function assertLastClientExitCode(launchPromise: Promise, exitCode: number) { const context = await launchPromise; - expect(context.lastClientExitCode).toEqual(exitCode); +} + +async function assertTrafficLight(launchPromise: Promise, trafficLight: string) { + const context = await launchPromise; + const found = getFieldFromJsonReport('trafficLight', context.secHubReportJsonObject); + expect(found).toEqual(trafficLight); + } \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/01-start.sh b/github-actions/scan/__test__/integrationtest/01-start.sh new file mode 100755 index 0000000000..ecc0123aa6 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/01-start.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +set -e + +# Purpose for this script: +# * Preparation for integration tests +# +# Details: +# - Calculates pathes +# - Downloads PDS and SecHub server version +# - removes former temp data automatically (e.g. old reports etc.) +# - Starts SecHubServer and PDS +# - Waits for the servers to be alive +# - After this a standard setup is done for SecHub to be able to communicate with PDS, project setup etc. +# - exit of script is done at the end - means synchronous execution +# +# Usage: 01-start.sh $secHubServerVersion $sechubServerPortNr $pdsVersion $pdsPortNr +# Example: +# ``` +# cd $gitRoot/github-actions/scan +# ./01-start.sh 1.4.1 8443 1.4.0 8444 +# ``` +# +SERVER_VERSION=$1 +SERVER_PORT=$2 + +PDS_SERVER_VERSION=$3 +PDS_SERVER_PORT=$4 + +DEBUG=$SECHUB_DEBUG + +if [ "$SERVER_VERSION" = "" ]; then + echo "first argument not set - is used as server verion!" + exit 1 +fi +if [ "$SERVER_PORT" = "" ]; then + echo "second argument not set - is used as server port!" + exit 1 +fi + +if [ "$PDS_SERVER_VERSION" = "" ]; then + echo "third argument not set - is used as PDS server verion!" + exit 1 +fi +if [ "$PDS_SERVER_PORT" = "" ]; then + echo "fourth argument not set - is used as PDS server port!" + exit 1 +fi + +## ---------------------------------- +## Prepare variables +## ---------------------------------- +echo "> Prepare variables" +SECHUB_BASE_URL="https://localhost:$SERVER_PORT" +PDS_BASE_URL="https://localhost:$PDS_SERVER_PORT" +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" # absolute directory of this script + +if [ "$SCRIPT_DIR" = "." ]; then + pwd + SCRIPT_DIR="$(pwd)" +fi +cd ${SCRIPT_DIR} + +cd ../.. #github action scan folder +GHA_SCAN_FOLDER_PATH="$(pwd)" + +SANITY_PATH_CHECK_FOR_SCRIPT="$GHA_SCAN_FOLDER_PATH/__test__/integrationtest/01-start.sh" +if [ ! -f "$SANITY_PATH_CHECK_FOR_SCRIPT" ]; then + echo "Sanity check failed - not found: $SANITY_PATH_CHECK_FOR_SCRIPT" + exit 1 +fi + +# Remote: +# GHA_SCANFOLDER_PATH= /home/runner/work/sechub/github-actions/scan +# RUNTIME: /home/runner/work/sechub/runtime +# WORKSPACE: /home/runner/work/sechub +WORKSPACE_DIR="${GHA_SCAN_FOLDER_PATH}/../../" +RUNTIME_DIR="${WORKSPACE_DIR}/build/sechub-runtime"; +SHARED_VOLUME="${RUNTIME_DIR}/shared-volume" +mkdir "$SHARED_VOLUME" -p + +echo "SECHUB_BASE_URL=$SECHUB_BASE_URL" +echo "PDS_BASE_URL =$PDS_BASE_URL" +echo "SCRIPT_DIR =$SCRIPT_DIR" +echo "RUNTIME_DIR =$RUNTIME_DIR" +echo "SHARED_VOLUME =$RUNTIME_DIR" + +## ---------------------------------- +## SecHub Server +## ---------------------------------- +echo "> Current working directory :$(pwd)" +echo "> SecHub Server" + +SERVER_FOLDER_PATH="${RUNTIME_DIR}/server/${SERVER_VERSION}" +SERVER_EXECUTABLE_NAME="sechub-server-${SERVER_VERSION}.jar" +SERVER_EXECUTABLE_PATH="${SERVER_FOLDER_PATH}/${SERVER_EXECUTABLE_NAME}" +SERVER_DOWNLOAD_URL="https://github.com/mercedes-benz/sechub/releases/download/v${SERVER_VERSION}-server/${SERVER_EXECUTABLE_NAME}" +SERVER_CERTFILE_PATH="${SERVER_FOLDER_PATH}/generated-localhost-certificate.p12" + +#echo "SERVER_FOLDER_PATH=$SERVER_FOLDER_PATH" + + + +## download server if not available +if [ ! -f $SERVER_EXECUTABLE_PATH ]; then + mkdir "${SERVER_FOLDER_PATH}" -p + echo "Start download from $SERVER_DOWNLOAD_URL" + curl -L ${SERVER_DOWNLOAD_URL} -o ${SERVER_EXECUTABLE_PATH} +else + echo "$SERVER_EXECUTABLE_NAME exists already - skip download" +fi + +## generate SecHub test certificate +if [ ! -f $SERVER_CERTFILE_PATH ]; then + mkdir "${SERVER_FOLDER_PATH}" -p + keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore "${SERVER_CERTFILE_PATH}" -validity 3650 -storepass 123456 --dname "CN=localhost, OU=ID" +fi + + +# Start SecHub async +SECHUB_LOGFILE=$SERVER_FOLDER_PATH/server.log + +rm $SECHUB_LOGFILE -f # remove old log files on start +echo "./start_sechub_server.sh $SERVER_PORT $SERVER_EXECUTABLE_PATH $SERVER_CERTFILE_PATH $SECHUB_LOGFILE $SHARED_VOLUME" > $SECHUB_LOGFILE +$SCRIPT_DIR/start_sechub_server.sh $SERVER_PORT $SERVER_EXECUTABLE_PATH $SERVER_CERTFILE_PATH $SECHUB_LOGFILE $SHARED_VOLUME + +## ---------------------------------- +## PDS +## ---------------------------------- +echo "> PDS" + +PDS_SERVER_FOLDER_PATH="${RUNTIME_DIR}/pds/${PDS_SERVER_VERSION}" +PDS_SERVER_EXECUTABLE_NAME="sechub-pds-${PDS_SERVER_VERSION}.jar" +PDS_SERVER_EXECUTABLE_PATH="${PDS_SERVER_FOLDER_PATH}/${PDS_SERVER_EXECUTABLE_NAME}" +PDS_SERVER_DOWNLOAD_URL="https://github.com/mercedes-benz/sechub/releases/download/v${PDS_SERVER_VERSION}-pds/${PDS_SERVER_EXECUTABLE_NAME}" +PDS_SERVER_CERTFILE_PATH="${PDS_SERVER_FOLDER_PATH}/generated-localhost-certificate.p12" + +#echo "PDS_SERVER_FOLDER_PATH=$PDS_SERVER_FOLDER_PATH" + +## download PDS if not available +if [ ! -f $PDS_SERVER_EXECUTABLE_PATH ]; then + mkdir "${PDS_SERVER_FOLDER_PATH}" -p + echo "Start download from $PDS_SERVER_DOWNLOAD_URL" + curl -L ${PDS_SERVER_DOWNLOAD_URL} -o ${PDS_SERVER_EXECUTABLE_PATH} +else + echo "$PDS_SERVER_EXECUTABLE_NAME exists already - skip download" +fi + +## generate PDS test certificate +if [ ! -f $PDS_SERVER_CERTFILE_PATH ]; then + mkdir "${PDS_SERVER_FOLDER_PATH}" -p + keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore "${PDS_SERVER_CERTFILE_PATH}" -validity 3650 -storepass 123456 --dname "CN=localhost, OU=ID" +fi + +## create config file for pds +PDS_CONFIG_FILE="$PDS_SERVER_FOLDER_PATH/pds-config.json" +cp $SCRIPT_DIR/test-config/gha_integrationtest_pds-config.json $PDS_CONFIG_FILE + + +# Start PDS async +PDS_LOGFILE=$PDS_SERVER_FOLDER_PATH/pds.log +rm $PDS_LOGFILE -f # remove old log files on start + +echo "./start_pds.sh $PDS_SERVER_PORT $PDS_SERVER_EXECUTABLE_PATH $PDS_SERVER_CERTFILE_PATH $PDS_LOGFILE $SHARED_VOLUME $PDS_CONFIG_FILE" > $PDS_LOGFILE +$SCRIPT_DIR/start_pds.sh $PDS_SERVER_PORT $PDS_SERVER_EXECUTABLE_PATH $PDS_SERVER_CERTFILE_PATH $PDS_LOGFILE $SHARED_VOLUME $PDS_CONFIG_FILE + +echo "> Wait for SecHub and PDS" +$SCRIPT_DIR/wait_server_alive.sh "SecHub Server" $SECHUB_BASE_URL/api/anonymous/check/alive +$SCRIPT_DIR/wait_server_alive.sh "PDS" $PDS_BASE_URL/api/anonymous/check/alive \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/03-init_sechub_data.sh b/github-actions/scan/__test__/integrationtest/03-init_sechub_data.sh new file mode 100755 index 0000000000..cb5fb9f544 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/03-init_sechub_data.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +set -e +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" # absolute directory of this script + +cd $(dirname "$0") +SECHUB_SERVER_PORT=$1 +PDS_PORT=$2 # currently not really used, reserved for later access + +echo "[START] setup integration test scenario for github action 'scan' " +echo " precondition: SecHub server mut be started locally" + +echo "> Handle settings" +if [[ "$SECHUB_SERVER_PORT" == "" ]]; then + SECHUB_SERVER_PORT=8443 + echo "SECHUB_SERVER_PORT was not defined - use fallback: $SECHUB_SERVER_PORT" +fi +if [[ "$PDS_PORT" == "" ]]; then + PDS_PORT=8444 + echo "PDS_PORT was not defined - use fallback: $PDS_PORT" +fi +if [[ "$SECHUB_SERVER" == "" ]]; then + SECHUB_SERVER="https://localhost:$SECHUB_SERVER_PORT" + echo "SECHUB_SERVER was not defined - use fallback: $SECHUB_SERVER" +fi +if [[ "$SECHUB_USERID" == "" ]]; then + SECHUB_USERID="int-test_superadmin" + echo "SECHUB_USERID was not defined - use fallback: $SECHUB_USERID" +fi +if [[ "$SECHUB_APITOKEN" == "" ]]; then + SECHUB_APITOKEN="int-test_superadmin-pwd" + echo "SECHUB_APITOKEN was not defined - use fallback: $SECHUB_APITOKEN" +fi + +## export for calls: SECHUB_SERVER, SECHUB_USERID and SECHUB_APITOKEN as environment variables +export SECHUB_SERVER +export SECHUB_USERID +export SECHUB_APITOKEN + +# we use the given sechub user (integration test admin) as user itself +# means we need no user creation,signup etc. +user=$SECHUB_USERID + +function createData(){ + number=$1 + type=$2 + trafficLight=$3 + + project="test-project-$number" + profile="test-profile-$number" + executor="test-executor-$type-$trafficLight" + + echo "> Create test project:$project for user:$user" + ./sechub-api.sh project_create $project $user "Testproject $number for integration tests" + ./sechub-api.sh project_assign_user $project $user # assign user to project + + echo "> Create executor config" + ./sechub-api.sh executor_create "$SCRIPT_DIR/test-config/${executor}.json" + + echo "> Create profile" + ./sechub-api.sh profile_create $profile $executor + + echo "> Assign profile to project" + ./sechub-api.sh project_assign_profile $project $profile +} + +echo "> Prepare sechub api script usage" +cd ../../../.. +# at root level now + +cd sechub-developertools/scripts +pwd + +echo "> Check server alive" +./sechub-api.sh alive_check + +createData 1 codescan green +createData 2 codescan yellow +createData 3 codescan red diff --git a/github-actions/scan/__test__/integrationtest/05-stop.sh b/github-actions/scan/__test__/integrationtest/05-stop.sh new file mode 100755 index 0000000000..81f0368817 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/05-stop.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +set -e + +# Purpose for this script: +# * Cleanup after integration tests +# +# Details: +# - Stops running PDS and SecHub servers (asynchronous) +# +# Usage: 05-stop.sh $sechubServerPortNr $pdsPortNr +# Example: +# ``` +# cd $gitRoot/github-actions/scan +# ./05-stop.sh 8443 8444 +# ``` +SERVER_PORT=$1 +PDS_PORT=$2 + +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" # absolute directory of this script +echo "SCRIPT_DIR = $SCRIPT_DIR" +cd ${SCRIPT_DIR} + +./stop_sechub_server.sh $SERVER_PORT +./stop_pds.sh $PDS_PORT \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/start_pds.sh b/github-actions/scan/__test__/integrationtest/start_pds.sh new file mode 100755 index 0000000000..cb4acc2916 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/start_pds.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +SERVER_PORT=$1 +PATH_TO_EXECUTABLE=$2 +PATH_TO_CERTIFICATE=$3 +PATH_TO_LOGFILE=$4 +SHARED_VOLUME=$5 +PDS_CONFIG_FILE=$6 + +echo "SERVER_PORT=$SERVER_PORT" >> $PATH_TO_LOGFILE + +echo "[ START ] PDS" + +if [ "$SERVER_PORT" = "" ]; then + echo "first argument not set - is used as server port!" + exit 1 +fi +if [ "$PATH_TO_EXECUTABLE" = "" ]; then + echo "second argument not set - is used as server jar executable path!" + exit 1 +fi + +if [ "$PATH_TO_CERTIFICATE" = "" ]; then + echo "third argument not set - is used as server certificate path!" + exit 1 +fi +if [ "$PATH_TO_LOGFILE" = "" ]; then + echo "fourth argument not set - is used as server log file path!" + exit 1 +fi +if [ "$SHARED_VOLUME" = "" ]; then + echo "fifth argument not set - is used as shared volume path!" + exit 1 +fi +if [ "$PDS_CONFIG_FILE" = "" ]; then + echo "sixth argument not set - is used as PDS config file path!" + exit 1 +fi + +SCRIPT_DIR="$(dirname -- "$0")" + +echo "Start PDS at localhost:${SERVER_PORT}, executable at: ${PATH_TO_EXECUTABLE}" +# `curl -s --insecure https://localhost:${this.serverPort}/api/anonymous/check/alive`; +java \ + -Dfile.encoding=UTF-8 \ + -Dspring.profiles.active=pds_integrationtest,pds_h2 \ + -Dpds.config.heartbeat.verbose.logging.enabled=false \ + -Dserver.ssl.key-store=${PATH_TO_CERTIFICATE} \ + -Dserver.port=${SERVER_PORT} \ + -Dpds.storage.sharedvolume.upload.dir=$SHARED_VOLUME \ + -Dpds.config.file=$PDS_CONFIG_FILE \ + -jar ${PATH_TO_EXECUTABLE}>>${PATH_TO_LOGFILE} & diff --git a/github-actions/scan/__test__/integrationtest/start_sechub_server.sh b/github-actions/scan/__test__/integrationtest/start_sechub_server.sh new file mode 100755 index 0000000000..79ed6a977b --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/start_sechub_server.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +SERVER_PORT=$1 +PATH_TO_EXECUTABLE=$2 +PATH_TO_CERTIFICATE=$3 +PATH_TO_LOGFILE=$4 +SHARED_VOLUME=$5 +echo "SERVER_PORT=$SERVER_PORT" >> $PATH_TO_LOGFILE + +echo "[ START ] SecHub" + +if [ "$SERVER_PORT" = "" ]; then + echo "first argument not set - is used as server port!" + exit 1 +fi +if [ "$PATH_TO_EXECUTABLE" = "" ]; then + echo "second argument not set - is used as server jar executable path!" + exit 1 +fi + +if [ "$PATH_TO_CERTIFICATE" = "" ]; then + echo "third argument not set - is used as server certificate path!" + exit 1 +fi +if [ "$PATH_TO_LOGFILE" = "" ]; then + echo "fourth argument not set - is used as server log file path!" + exit 1 +fi +if [ "$SHARED_VOLUME" = "" ]; then + echo "fifth argument not set - is used as shared volume path!" + exit 1 +fi + + +SCRIPT_DIR="$(dirname -- "$0")" + +echo "Start SecHub server at localhost:${SERVER_PORT}, executable at: ${PATH_TO_EXECUTABLE}" +# `curl -s --insecure https://localhost:${this.serverPort}/api/anonymous/check/alive`; +java \ + -Dfile.encoding=UTF-8 \ + -Dspring.profiles.active=dev,mocked_products,h2,integrationtest \ + -Dserver.ssl.key-store=${PATH_TO_CERTIFICATE} \ + -Dsechub.server.debug=true \ + -Dserver.port=${SERVER_PORT} \ + -Dsechub.integrationtest.ignore.missing.serverproject=true \ + -Dsechub.storage.sharedvolume.upload.dir=$SHARED_VOLUME \ + -jar ${PATH_TO_EXECUTABLE}>>${PATH_TO_LOGFILE} & diff --git a/github-actions/scan/__test__/integrationtest/stop_pds.sh b/github-actions/scan/__test__/integrationtest/stop_pds.sh new file mode 100755 index 0000000000..23dc20c97b --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/stop_pds.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +# $1 = server port +SERVER_PORT=$1 +echo "[ STOP ] PDS" +echo "Shutdown PDS at localhost:${SERVER_PORT}" +if [ "$SERVER_PORT" = "" ]; then + echo "first argument not set - is used as server port!" + exit 1 +fi +curl -s --insecure https://localhost:${SERVER_PORT}/api/anonymous/integrationtest/shutdown +echo "Shutdown initiated" diff --git a/github-actions/scan/__test__/integrationtest/stop_sechub_server.sh b/github-actions/scan/__test__/integrationtest/stop_sechub_server.sh new file mode 100755 index 0000000000..a5affe0032 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/stop_sechub_server.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +# $1 = server port +SERVER_PORT=$1 +echo "[ STOP ] SecHub" +echo "Shutdown SecHub server at localhost:${SERVER_PORT}" +if [ "$SERVER_PORT" = "" ]; then + echo "first argument not set - is used as server port!" + exit 1 +fi +curl -s --insecure https://localhost:${SERVER_PORT}/api/anonymous/integrationtest/shutdown +echo "Shutdown initiated" diff --git a/github-actions/scan/__test__/integrationtest/test-config/gha_integrationtest_pds-config.json b/github-actions/scan/__test__/integrationtest/test-config/gha_integrationtest_pds-config.json new file mode 100644 index 0000000000..a0022863e4 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-config/gha_integrationtest_pds-config.json @@ -0,0 +1,24 @@ +{ + "apiVersion": "1.0", + "serverId": "gha_integrationtest_server", + "products": [ + { + "id": "codescan_demo_green", + "path": "./__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh", + "scanType": "codeScan", + "description": "This is only a fake code scan - used by integration tests. The code scan will just return one info vulnerability" + }, + { + "id": "codescan_demo_yellow", + "path": "./__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh", + "scanType": "codeScan", + "description": "This is only a fake code scan - used by integration tests. The code scan will just return one medium vulnerability" + }, + { + "id": "codescan_demo_red", + "path": "./__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh", + "scanType": "codeScan", + "description": "This is only a fake code scan - used by integration tests. The code scan will just return one high vulnerability" + } + ] +} \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-green.json b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-green.json new file mode 100644 index 0000000000..4adfb05aa3 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-green.json @@ -0,0 +1,39 @@ +{ + "name": "test-executor-codescan-green", + "productIdentifier": "PDS_CODESCAN", + "setup": { + "baseURL": "https://localhost:8444", + "credentials": { + "user": "pds-inttest-techuser", + "password": "pds-inttest-apitoken" + }, + "jobParameters": [ + { + "key": "sechub.productexecutor.pds.timetowait.nextcheck.milliseconds", + "value": "500" + }, + { + "key": "sechub.productexecutor.pds.trustall.certificates", + "value": "true" + }, + { + "key": "pds.mocking.disabled", + "value": "true" + }, + { + "key": "pds.config.productidentifier", + "value": "codescan_demo_green" + }, + { + "key": "pds.config.use.sechub.storage", + "value": "true" + }, + { + "key": "pds.config.supported.datatypes", + "value": "SOURCE" + } + ] + }, + "executorVersion": 1, + "enabled": true +} \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-red.json b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-red.json new file mode 100644 index 0000000000..75e58e75c1 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-red.json @@ -0,0 +1,39 @@ +{ + "name": "test-executor-codescan-red", + "productIdentifier": "PDS_CODESCAN", + "setup": { + "baseURL": "https://localhost:8444", + "credentials": { + "user": "pds-inttest-techuser", + "password": "pds-inttest-apitoken" + }, + "jobParameters": [ + { + "key": "sechub.productexecutor.pds.timetowait.nextcheck.milliseconds", + "value": "500" + }, + { + "key": "sechub.productexecutor.pds.trustall.certificates", + "value": "true" + }, + { + "key": "pds.mocking.disabled", + "value": "true" + }, + { + "key": "pds.config.productidentifier", + "value": "codescan_demo_red" + }, + { + "key": "pds.config.use.sechub.storage", + "value": "true" + }, + { + "key": "pds.config.supported.datatypes", + "value": "SOURCE" + } + ] + }, + "executorVersion": 1, + "enabled": true +} \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-yellow.json b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-yellow.json new file mode 100644 index 0000000000..f8bd4133f4 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-config/test-executor-codescan-yellow.json @@ -0,0 +1,39 @@ +{ + "name": "test-executor-codescan-yellow", + "productIdentifier": "PDS_CODESCAN", + "setup": { + "baseURL": "https://localhost:8444", + "credentials": { + "user": "pds-inttest-techuser", + "password": "pds-inttest-apitoken" + }, + "jobParameters": [ + { + "key": "sechub.productexecutor.pds.timetowait.nextcheck.milliseconds", + "value": "500" + }, + { + "key": "sechub.productexecutor.pds.trustall.certificates", + "value": "true" + }, + { + "key": "pds.mocking.disabled", + "value": "true" + }, + { + "key": "pds.config.productidentifier", + "value": "codescan_demo_yellow" + }, + { + "key": "pds.config.use.sechub.storage", + "value": "true" + }, + { + "key": "pds.config.supported.datatypes", + "value": "SOURCE" + } + ] + }, + "executorVersion": 1, + "enabled": true +} \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh new file mode 100755 index 0000000000..e8732414a9 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +echo "#PDS_INTTEST_PRODUCT_CODESCAN +info:result1" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh new file mode 100755 index 0000000000..358cada8f0 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +echo "#PDS_INTTEST_PRODUCT_CODESCAN +high:result3" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh new file mode 100755 index 0000000000..42a334221b --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +echo "#PDS_INTTEST_PRODUCT_CODESCAN +medium:result2" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-sources/testdata.txt b/github-actions/scan/__test__/integrationtest/test-sources/testdata.txt new file mode 100644 index 0000000000..2995a4d0e7 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-sources/testdata.txt @@ -0,0 +1 @@ +dummy \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/testframework.ts b/github-actions/scan/__test__/integrationtest/testframework.ts new file mode 100644 index 0000000000..dd8600d321 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/testframework.ts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +import * as shell from 'shelljs'; + +export class IntegrationTestContext { + + workspaceDir: string|undefined; + + serverVersion: string|undefined; + serverPort: number|undefined; + + serverUserId: string|undefined; + serverApiToken: string|undefined; + + public finish() { + shell.env['SECHUB_SERVER'] = `https://localhost:${this.serverPort}`; + shell.env['SECHUB_USERID'] = `${this.serverUserId}`; + shell.env['SECHUB_APITOKEN'] = `${this.serverApiToken}`; + } + +} diff --git a/github-actions/scan/__test__/integrationtest/wait_server_alive.sh b/github-actions/scan/__test__/integrationtest/wait_server_alive.sh new file mode 100755 index 0000000000..6ccf4678a8 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/wait_server_alive.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +SERVER_TYPE=$1 +CHECK_ALIVE_URL=$2 + +if [ "$CHECK_ALIVE_URL" = "" ]; then + echo "first argument not set - is used as url to check alive via head!" + exit 1 +fi + +echo "[ WAIT ] Until $SERVER_TYPE alive at $CHECK_ALIVE_URL" + +declare -i MAX_WAIT_SECONDS=30 +declare -i waitCount=0 + +## Wait until available +printf '.' +until $(curl --output /dev/null --silent --head --fail --insecure $CHECK_ALIVE_URL); do + printf '.' + if [ $waitCount -gt $MAX_WAIT_SECONDS ]; then + echo "" + echo "[ERROR] WAIT max time exceeded: $MAX_WAIT_SECONDS seconds" + exit 1 + fi + sleep 1 + waitCount=$waitCount+1 +done + +echo "" +echo "> $SERVER_TYPE is alive" diff --git a/github-actions/scan/__test__/post-scan.test.ts b/github-actions/scan/__test__/post-scan.test.ts index 03973f4c63..8f1d49ce3e 100644 --- a/github-actions/scan/__test__/post-scan.test.ts +++ b/github-actions/scan/__test__/post-scan.test.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT import * as core from '@actions/core'; -import { downloadReports, reportOutputs } from '../src/post-scan'; +import { collectReportData, reportOutputs } from '../src/post-scan'; import { getReport } from '../src/sechub-cli'; import { LAUNCHER_CONTEXT_DEFAULTS } from '../src/launcher'; @@ -11,38 +11,99 @@ const mockedCore = core as jest.Mocked; jest.mock('../src/sechub-cli'); const mockedGetReport = getReport as jest.MockedFunction; -describe('downloadReports', function () { +describe('collectReportData', function () { afterEach(() => { jest.clearAllMocks(); }); - it('writes to log if formats is empty', function () { - downloadReports(LAUNCHER_CONTEXT_DEFAULTS, []); + it('format empty - logs called, getReport not called', function () { + + /* prepare */ + const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS); + testContext.reportFormats= []; + + /* execute */ + collectReportData(testContext); + + /* test */ + expect(mockedCore.info).toHaveBeenCalledTimes(1); + expect(mockedGetReport).toHaveBeenCalledTimes(0); + }); + + it('format "json" - logs called 1 time , getReport never called', function () { + /* prepare */ + const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS); + testContext.reportFormats= ['json']; + + /* execute */ + collectReportData(testContext); + + /* test */ expect(mockedCore.info).toHaveBeenCalledTimes(1); expect(mockedGetReport).toHaveBeenCalledTimes(0); }); - it('calls getReport with correct parameters for non-empty formats', function () { + it('format "html" - logs called 2 times, getReport called 1 time', function () { + + /* prepare */ + const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS); + testContext.reportFormats= ['json','html']; + testContext.jobUUID=1234; // necessary for download + + collectReportData(testContext); + + /* test */ + expect(mockedCore.info).toHaveBeenCalledTimes(2); + expect(mockedGetReport).toHaveBeenCalledTimes(1); + }); + + it('format "json,html" - logs called 2 times , getReport called 1 time', function () { + + /* prepare */ + const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS); + testContext.reportFormats= ['json','html']; + testContext.jobUUID=1234; // necessary for download + + /* execute */ + collectReportData(testContext); + + /* test */ + expect(mockedCore.info).toHaveBeenCalledTimes(2); + expect(mockedGetReport).toHaveBeenCalledTimes(1); + }); + + it('calls getReport with parameters (except json) and report json object is as expected', function () { // eslint-disable-next-line @typescript-eslint/no-var-requires const fsMock = require('fs'); + + /* prepare */ + const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS); + testContext.reportFormats= ['json','html','xyz','bla']; + testContext.jobUUID=1234; // necessary for download fsMock.readFileSync = jest.fn(() => '{"test": "test"}'); // Mock an empty JSON report - const formats = ['json', 'html']; const sampleJson = {'test': 'test'}; - const actualJson = downloadReports(LAUNCHER_CONTEXT_DEFAULTS, formats); - expect(mockedCore.info).toHaveBeenCalledTimes(2); // Assumes 3 formats, adjust based on the number of formats in the array - expect(mockedGetReport).toHaveBeenCalledTimes(2); - expect(actualJson).toEqual(sampleJson); + /* execute */ + collectReportData(testContext); + + /* test */ + expect(mockedCore.info).toHaveBeenCalledTimes(4); // "json, html, xyz, bla" - 4 times logged (valid format check is not done here) + expect(mockedGetReport).toHaveBeenCalledTimes(3); // we fetch not json via getReport again (already done before), so only "html, xyz, bla" used + + expect(testContext.secHubReportJsonObject).toEqual(sampleJson); // json object is available + }); }); describe('reportOutputs', function () { + /* prepare */ beforeEach(() => { jest.clearAllMocks(); }); it('calls set github output with correct values when JSON report is correct', function () { + /* prepare */ const sampleJson = { 'result': { 'count': 2, @@ -70,8 +131,10 @@ describe('reportOutputs', function () { 'messages': [] }; + /* execute */ reportOutputs(sampleJson); + /* test */ expect(mockedCore.debug).toHaveBeenCalledTimes(6); expect(mockedCore.setOutput).toHaveBeenCalledTimes(6); expect(mockedCore.setOutput).toBeCalledWith('scan-trafficlight', 'RED'); @@ -83,8 +146,10 @@ describe('reportOutputs', function () { }); it('calls set github output with correct values when JSON report did not exist', function () { + /* execute */ reportOutputs(undefined); + /* test */ expect(mockedCore.debug).toHaveBeenCalledTimes(7); expect(mockedCore.debug).toBeCalledWith('No findings reported to be categorized.'); expect(mockedCore.setOutput).toHaveBeenCalledTimes(6); @@ -97,6 +162,7 @@ describe('reportOutputs', function () { }); it('calls set github output with correct values when traffic light is green without findings.', function () { + /* prepare */ const sampleJson = { 'result': { 'count': 0, @@ -109,8 +175,10 @@ describe('reportOutputs', function () { 'messages': [] }; + /* execute */ reportOutputs(sampleJson); + /* test */ expect(mockedCore.debug).toHaveBeenCalledTimes(6); expect(mockedCore.setOutput).toHaveBeenCalledTimes(6); expect(mockedCore.setOutput).toBeCalledWith('scan-trafficlight', 'GREEN'); diff --git a/github-actions/scan/__test__/report-format.test.ts b/github-actions/scan/__test__/report-format.test.ts index 17d4eda521..3221eb7f26 100644 --- a/github-actions/scan/__test__/report-format.test.ts +++ b/github-actions/scan/__test__/report-format.test.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -import {getValidFormatsFromInput} from "../src/report-formats"; +import {getValidFormatsFromInput} from '../src/report-formats'; describe('getValidFormatsFromInput', function() { it('correctly return report formats for json', function () { diff --git a/github-actions/scan/__test__/sechub-cli.test.ts b/github-actions/scan/__test__/sechub-cli.test.ts new file mode 100644 index 0000000000..bd5aa75d40 --- /dev/null +++ b/github-actions/scan/__test__/sechub-cli.test.ts @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +import * as cli from '../src/sechub-cli'; +jest.mock('@actions/core'); + +describe('sechub-cli', function() { + it('extractJobUUID returns job uuid from sechub client output snippet', function () { + + const output = ` + WARNING: Configured to trust all - means unknown service certificate is accepted. Don't use this in production! + 2024-03-08 13:58:18 (+01:00) Zipping folder: __test__/integrationtest/test-sources (/home/xyzgithub-actions/scan/__test__/integrationtest/test-sources) + 2024-03-08 13:58:18 (+01:00) Creating new SecHub job: 6880e518-88db-406a-bc67-851933e7e5b7 + 2024-03-08 13:58:18 (+01:00) Uploading source zip file + 2024-03-08 13:58:18 (+01:00) Approve sechub job + 2024-03-08 13:58:18 (+01:00) Waiting for job 6880e518-88db-406a-bc67-851933e7e5b7 to be done + . + 2024-03-08 13:58:20 (+01:00) Fetching result (format=json) for job 6880e518-88db-406a-bc67-851933e7e5b7 + other + `; + + /* execute */ + const jobUUID= cli.extractJobUUID(output); + + /* test */ + expect(jobUUID).toEqual('6880e518-88db-406a-bc67-851933e7e5b7'); + }); + it('extractJobUUID returns job uuid from string with "job: xxxx"', function () { + + const output = ` + The uuid for job:1234 + can be extracted + `; + + /* execute */ + const jobUUID= cli.extractJobUUID(output); + + /* test */ + expect(jobUUID).toEqual('1234'); + }); + + it('extractJobUUID returns empty string when no job id is available', function () { + + const output = ` + WARNING: Configured to trust all - means unknown service certificate is accepted. Don't use this in production! + 2024-03-08 13:58:18 (+01:00) Zipping folder: __test__/integrationtest/test-sources (/home/xyzgithub-actions/scan/__test__/integrationtest/test-sources) + 2024-03-08 13:58:18 (+01:00) Uploading source zip file + 2024-03-08 13:58:18 (+01:00) Approve sechub job + + `; + + /* execute */ + const jobUUID= cli.extractJobUUID(output); + + /* test */ + expect(jobUUID).toEqual(''); + }); + +}); \ No newline at end of file diff --git a/github-actions/scan/__test__/setup-integrationtest.sh b/github-actions/scan/__test__/setup-integrationtest.sh deleted file mode 100755 index 25beda4896..0000000000 --- a/github-actions/scan/__test__/setup-integrationtest.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: MIT - -cd $(dirname "$0") - -echo "[START] setup integration test scenario for github action 'scan' " -echo " precondition: SecHub server mut be started locally" - -echo "----- Handle settings" -if [[ "$SECHUB_SERVER" == "" ]]; then - export SECHUB_SERVER="https://localhost:8443" - echo "SECHUB_SERVER was not defined - use fallback" -fi -if [[ "$SECHUB_USERID" == "" ]]; then - export SECHUB_USERID="int-test_superadmin" - echo "SECHUB_USERID was not defined - use fallback" -fi -if [[ "$SECHUB_APITOKEN" == "" ]]; then - export SECHUB_APITOKEN="int-test_superadmin-pwd" - echo "SECHUB_APITOKEN was not defined - use fallback" -fi -echo "----- Prepare sechub api script usage" -cd ../../.. -# at root level now - -cd sechub-developertools/scripts -pwd - -# we use the given sechub user (integration test admin) as user itself -# means we need no user creation,signup etc. -user=$SECHUB_USERID -project="test-project" - -echo "----- Check server alive" -./sechub-api.sh alive_check - -echo "----- Create test project:$project for user:$user" -./sechub-api.sh project_create $project $user "Testproject for integration tests" -./sechub-api.sh project_assign_user $project $user # assign user to project - - - - - diff --git a/github-actions/scan/dist/exec-child1.js b/github-actions/scan/dist/exec-child1.js deleted file mode 100644 index eab86ed37b..0000000000 --- a/github-actions/scan/dist/exec-child1.js +++ /dev/null @@ -1,39 +0,0 @@ -if (require.main !== module) { - throw new Error('This file should not be required'); -} - -var childProcess = require('child_process'); -var fs = require('fs'); - -var paramFilePath = process.argv[2]; - -var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); -var params = JSON.parse(serializedParams); - -var cmd = params.command; -var execOptions = params.execOptions; -var pipe = params.pipe; -var stdoutFile = params.stdoutFile; -var stderrFile = params.stderrFile; - -var c = childProcess.exec(cmd, execOptions, function (err) { - if (!err) { - process.exitCode = 0; - } else if (err.code === undefined) { - process.exitCode = 1; - } else { - process.exitCode = err.code; - } -}); - -var stdoutStream = fs.createWriteStream(stdoutFile); -var stderrStream = fs.createWriteStream(stderrFile); - -c.stdout.pipe(stdoutStream); -c.stderr.pipe(stderrStream); -c.stdout.pipe(process.stdout); -c.stderr.pipe(process.stderr); - -if (pipe) { - c.stdin.end(pipe); -} diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index 5cca6e5c93..912ee4fb06 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -13552,53 +13552,6 @@ module.exports = require("zlib"); /******/ } /******/ /************************************************************************/ -/******/ /* webpack/runtime/create fake namespace object */ -/******/ (() => { -/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); -/******/ var leafPrototypes; -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 16: return value when it's Promise-like -/******/ // mode & 8|1: behave like require -/******/ __nccwpck_require__.t = function(value, mode) { -/******/ if(mode & 1) value = this(value); -/******/ if(mode & 8) return value; -/******/ if(typeof value === 'object' && value) { -/******/ if((mode & 4) && value.__esModule) return value; -/******/ if((mode & 16) && typeof value.then === 'function') return value; -/******/ } -/******/ var ns = Object.create(null); -/******/ __nccwpck_require__.r(ns); -/******/ var def = {}; -/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; -/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { -/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); -/******/ } -/******/ def['default'] = () => (value); -/******/ __nccwpck_require__.d(ns, def); -/******/ return ns; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __nccwpck_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports @@ -13657,68 +13610,116 @@ var shell = __nccwpck_require__(3516); ;// CONCATENATED MODULE: ./src/sechub-cli.ts // SPDX-License-Identifier: MIT + /** - * Executes the scan method of the SecHub CLI. + * Executes the scan method of the SecHub CLI. Sets the client exitcode inside context. * @param parameter Parameters to execute the scan with - * @param format Report format that should be fetched * @param context: launch context */ -function scan(format, context) { - return shell.exec(`${context.clientExecutablePath} ${context.configParameter} -reportformat ${format} scan`); +function scan(context) { + const shellString = shell.exec(`${context.clientExecutablePath} -configfile ${context.configFileLocation} -output ${context.workspaceFolder} scan`); + context.lastClientExitCode = shellString.code; + if (context.lastClientExitCode != 0) { + core.error(shellString.stderr); + } + context.jobUUID = extractJobUUID(shellString.stdout); +} +function extractJobUUID(output) { + const jobPrefix = 'job:'; + const index1 = output.indexOf(jobPrefix); + if (index1 > -1) { + const index2 = output.indexOf('\n', index1); + if (index2 > -1) { + const extracted = output.substring(index1 + jobPrefix.length, index2); + return extracted.trim(); + } + } + return ''; } /** - * Executes the getReport method of the SecHub CLI. + * Executes the getReport method of the SecHub CLI. Sets the client exitcode inside context. * @param jobUUID job UUID for which the report should be downloaded * @param projectName name of the project for which the report should be downloaded * @param format format in which the report should be downloaded * @param context: launch context */ function getReport(jobUUID, format, context) { - return shell.exec(`${context.clientExecutablePath} -jobUUID ${jobUUID} -project ${context.inputData.projectName} --reportformat ${format} getReport`); + const shellString = shell.exec(`${context.clientExecutablePath} -jobUUID ${jobUUID} -project ${context.inputData.projectName} --reportformat ${format} getReport`); + context.lastClientExitCode = shellString.code; } -// /** -// * Executes the markFalsePositives method of the SecHub CLI. -// * @param falsePositivePath path to the false positive file -// */ -// export function markFalsePositives(falsePositivePath: string, context: LaunchContext): ShellString { -// return shell.exec(`${context.clientExecutablePath} -file ${falsePositivePath} markFalsePositives`); -// } -;// CONCATENATED MODULE: ./src/log-helper.ts +;// CONCATENATED MODULE: ./src/exitcode.ts // SPDX-License-Identifier: MIT +/* ---------------------------------- */ +/* -------- Exit codes -------------- */ +/* ---------------------------------- */ +// This is a mapping for client exit codes - origin can be found at constants.go +const exitCodeMap = new Map(); +exitCodeMap.set(0, 'OK'); +exitCodeMap.set(1, 'FAILED'); +exitCodeMap.set(3, 'ERROR - Missing parameters'); +exitCodeMap.set(4, 'ERROR - Config file does not exist or is not valid'); +exitCodeMap.set(5, 'ERROR - HTTP error has occurred'); +exitCodeMap.set(6, 'ERROR - Action was illegal'); +exitCodeMap.set(7, 'ERROR - Missing configuration parts'); +exitCodeMap.set(8, 'ERROR - IO error'); +exitCodeMap.set(9, 'ERROR - Config file not in expected format'); +exitCodeMap.set(10, 'ERROR - Job has been canceld on SecHub server'); /** - * Logs the exit code and uses error method if not 0. + * Creates a log mesage with the exit code and a description. The message will be loged by calling core.info or core.error (when exit code !=0) * @param code The given exit code */ function logExitCode(code) { - const prefix = 'Exit code: '; + const message = 'Exit code: ' + code + ' . Description: ' + exitCodeMap.get(code); if (code === 0) { - core.info(prefix + code); + core.info(message); } else { - core.error(prefix + code); + core.error(message); } } // EXTERNAL MODULE: external "path" var external_path_ = __nccwpck_require__(1017); +// EXTERNAL MODULE: external "child_process" +var external_child_process_ = __nccwpck_require__(2081); ;// CONCATENATED MODULE: ./src/fs-helper.ts // SPDX-License-Identifier: MIT + /** * Get workspace directory. */ function getWorkspaceDir() { - return shell.env.GITHUB_WORKSPACE || ''; + /* github workspace is something like: + * /home/runner/work/sechub/ + * means we are at root level when the action is used + * from outside + * Means: we have a /home/runner/work/sechub/runtime folder + * /home/runner/work/other-repo/runtime + * + * For local builds/runs this must be done as well. + * + */ + const workspace = shell.env.GITHUB_WORKSPACE; + if (workspace == null) { + /* not set, means local,we are inside github-actions/scan */ + return '../../'; + } + else { + return `${workspace}`; + } } /** * Get parent folder of workspace directory. */ -function getWorkspaceParentDir() { - return external_path_.dirname(getWorkspaceDir()); +function ensuredWorkspaceFolder() { + const ensuredWorkspaceFolder = path.dirname(getWorkspaceDir()); + // TODO check folder exists or fal + return ensuredWorkspaceFolder; } /** * Get all files in current directory for given pattern. @@ -13732,48 +13733,53 @@ function getFiles(pattern) { }); return reportFiles; } -class ShellFailedWithExitCodeNotZeroError extends Error { - constructor(command, shellExecResult) { - super(`Shell script call failed.\nExit code: ${shellExecResult.code}\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}`); +class ShellFailedWithExitCodeNotAcceptedError extends Error { + constructor(command, shellExecResult, acceptedExitCodes) { + super(`Shell script call failed.\nExit code: ${shellExecResult.code} - accepted would be: ${acceptedExitCodes}.\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}\nStdOut: ${shellExecResult.stdout}`); } } /** - * Executes given command by shell - errors are handled - * @param command + * Executes given command by shell synchronous - errors are handled. + * Attention: This mechanism has problems with script execution where child processes are created! + * In this case the script execution by shelljs freezes! Workaround here: Use shellExecAsync(..) in + * this case! + * @param command command to execute + * @param acceptedExitCodes - an array with accepted exit codes. if not defined only 0 is accepted * @throws ShellFailedWithExitCodeNotZeroError * @returns shellstring */ -function shellExecOrFail(command) { +function shellExecSynchOrFail(command, acceptedExitCodes = [0]) { const shellExecResult = shell.exec(command); - if (shellExecResult.code != 0) { - throw new ShellFailedWithExitCodeNotZeroError(command, shellExecResult); + if (!acceptedExitCodes.includes(shellExecResult.code)) { + throw new ShellFailedWithExitCodeNotAcceptedError(command, shellExecResult, acceptedExitCodes); } return shellExecResult; } +/** + * Executes given command asynchronous + * @param command command to execute + * @returns child process + */ +function shellExecAsync(command) { + return child.exec(command); +} -;// CONCATENATED MODULE: ./src/sechub.json -const sechub_namespaceObject = JSON.parse('{"apiVersion":"1.0","codeScan":{"fileSystem":{"folders":["."]},"excludes":[]}}'); -var src_sechub_namespaceObject = /*#__PURE__*/__nccwpck_require__.t(sechub_namespaceObject, 2); -;// CONCATENATED MODULE: ./src/settings.json -const settings_namespaceObject = JSON.parse('{"vz":"sechub scan-report","nl":"sechub_report_*.*","Pz":"sechub.json"}'); ;// CONCATENATED MODULE: ./src/configuration-builder.ts // SPDX-License-Identifier: MIT - - /** * Creates the sechub.json configuration file with the given user input values. * * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -function createSecHubConfigJsonFile(includeFolders, excludeFolders) { - core.info('Config-Path was not found. Config will be manually created...'); +function createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders) { + core.info('Config-Path was not found. Config will be created at ' + secHubJsonFilePath); const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); - shell.ShellString(stringifiedSecHubJson).to(settings_namespaceObject.Pz); + shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); } /** * Creates a sechub configuration model object for given user input values. @@ -13784,8 +13790,16 @@ function createSecHubConfigJsonFile(includeFolders, excludeFolders) { * @returns model */ function createSecHubConfigurationModel(includeFolders, excludeFolders) { - const sechubJson = src_sechub_namespaceObject; + const sechubJson = { + 'apiVersion': '1.0' + }; + if (sechubJson.codeScan == null) { + sechubJson.codeScan = {}; + } if (includeFolders) { + if (sechubJson.codeScan.fileSystem == null) { + sechubJson.codeScan.fileSystem = {}; + } sechubJson.codeScan.fileSystem.folders = includeFolders; } if (excludeFolders) { @@ -13816,22 +13830,24 @@ function getValidFormatsFromInput(inputFormats) { /** * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. - * @param configPath Path to the sechub.json + * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) * @param includeFolders list of folders to include to the scan * @param excludeFolders list of folders to exclude from the scan * - * @returns parameter or null if config path is null + * @returns resulting configuration file path */ -function initSecHubJson(configPath, includeFolders, excludeFolders) { +function initSecHubJson(secHubJsonFilePath, customSecHubConfigFilePath, includeFolders, excludeFolders) { core.startGroup('Set config'); - if (!configPath) { - createSecHubConfigJsonFile(includeFolders, excludeFolders); - return null; + let configFilePath = customSecHubConfigFilePath; + if (configFilePath) { + core.info(`Config-Path was found: ${customSecHubConfigFilePath}`); + } + else { + createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); + configFilePath = secHubJsonFilePath; } - core.info(`Config-Path was found: ${configPath}`); - const configParameter = `-configfile '${configPath}'`; core.endGroup(); - return configParameter; + return configFilePath; } /** * Initializes the report formats and ensures there is at least one valid report format selected. @@ -13865,6 +13881,32 @@ function ensureJsonReportAtBeginning(reportFormats) { var artifact_client = __nccwpck_require__(2605); // EXTERNAL MODULE: external "fs" var external_fs_ = __nccwpck_require__(7147); +;// CONCATENATED MODULE: ./src/json-helper.ts + +/** + * Reads the given field from the SecHub JSON report. + * @param {string} field - The field relative to root, where the value should be found. The field can be a nested field, e.g. result.count. + * @param jsonData - The json data to read the field from. + * @returns {*} - The value found for the given field or undefined if not found. + */ +function getFieldFromJsonReport(field, jsonData) { + // Split the given field into individual keys + const keys = field.split('.'); + // Traverse the JSON object to find the requested field + let currentKey = jsonData; + for (const key of keys) { + // eslint-disable-next-line no-prototype-builtins + if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { + currentKey = currentKey[key]; + } + else { + core.warning(`Field "${key}" not found in the JSON report.`); + return undefined; + } + } + return currentKey; +} + ;// CONCATENATED MODULE: ./src/post-scan.ts // SPDX-License-Identifier: MIT @@ -13874,42 +13916,58 @@ var external_fs_ = __nccwpck_require__(7147); + /** - * Downloads the reports for the given formats. - * @param formats formats in which the report should be downloaded + * Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary */ -function downloadReports(context, formats) { - core.startGroup('Download Reports'); - if (formats.length === 0) { - core.info('No more formats'); - return; +core.startGroup('Collect report data'); +function collectReportData(context) { + core.startGroup('Collect report data'); + collectJsonReportData(context); + downloadOtherReportsThanJson(context); + core.endGroup(); +} +function collectJsonReportData(context) { + /* json - already downloaded by client on scan, here we just ensure it exists and fetch the data from the model */ + const fileName = getFirstJsonReportFileName(context); + const filePath = `${getWorkspaceDir()}/${fileName}`; + let text = ''; + try { + core.info('Get Report as json'); + text = external_fs_.readFileSync(filePath, 'utf8'); } - const json = loadJsonReport(); - if (json) { - const jobUUID = getFieldFromJsonReport('jobUUID', json); + catch (error) { + core.warning(`Error reading JSON file: ${error}`); + return undefined; + } + const jsonObject = asJsonObject(text); + /* setup data in context */ + context.secHubReportJsonObject = jsonObject; +} +function downloadOtherReportsThanJson(context) { + if (context.jobUUID) { + const jobUUID = context.jobUUID; core.debug('JobUUID: ' + jobUUID); - formats.forEach((format) => { - core.info(`Get Report as ${format}`); - const exitCode = getReport(jobUUID, format, context); - logExitCode(exitCode ? exitCode.code : 0); + context.reportFormats.forEach((format) => { + if (format != 'json') { // json is skipped, because already downloaded + core.info(`Get Report as ${format}`); + getReport(jobUUID, format, context); + logExitCode(context.lastClientExitCode); + } }); } - core.endGroup(); - return json; } /** - * Load and parse the SecHub JSON report. + * Parse the SecHub JSON report. * @returns {object | undefined} - The parsed JSON report or undefined if not found or there was an error. */ -function loadJsonReport() { - const fileName = getJsonReportFileName(); - const filePath = `${getWorkspaceDir()}/${fileName}`; +function asJsonObject(text) { try { - const jsonData = JSON.parse(external_fs_.readFileSync(filePath, 'utf8')); + const jsonData = JSON.parse(text); return jsonData; } catch (error) { - core.warning(`Error reading or parsing JSON file: ${error}`); + core.warning(`Error parsing JSON file: ${error}`); return undefined; } } @@ -13918,17 +13976,20 @@ function loadJsonReport() { * @param name Name for the zip file. * @param paths All file paths to include into the artifact. */ -async function uploadArtifact(name, paths) { +async function uploadArtifact(context, name, paths) { core.startGroup('Upload artifacts'); try { const artifactClient = artifact_client/* create */.U(); const artifactName = name; const options = { continueOnError: true }; - const workspace = getWorkspaceDir(); - shell.exec(`ls ${workspace}`); - core.debug('rootDirectory: ' + workspace); - core.debug('files: ' + paths); - await artifactClient.uploadArtifact(artifactName, paths, workspace, options); + const rootDirectory = context.workspaceFolder; + core.debug('rootDirectory: ' + rootDirectory); + if (core.isDebug()) { + shell.exec(`ls ${rootDirectory}`); + } + core.debug('paths: ' + paths); + await artifactClient.uploadArtifact(artifactName, paths, rootDirectory, options); + core.debug('artifact upload done'); } catch (e) { const message = e instanceof Error ? e.message : 'Unknown error'; @@ -13936,38 +13997,21 @@ async function uploadArtifact(name, paths) { } core.endGroup(); } -/** - * Reads the given field from the SecHub JSON report. - * @param {string} field - The field relative to root, where the value should be found. The field can be a nested field, e.g. result.count. - * @param jsonData - The json data to read the field from. - * @returns {*} - The value found for the given field or undefined if not found. - */ -function getFieldFromJsonReport(field, jsonData) { - // Split the given field into individual keys - const keys = field.split('.'); - // Traverse the JSON object to find the requested field - let currentKey = jsonData; - for (const key of keys) { - // eslint-disable-next-line no-prototype-builtins - if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { - currentKey = currentKey[key]; - } - else { - core.warning(`Field "${key}" not found in the JSON report.`); - return undefined; - } - } - return currentKey; -} /** * Get the JSON report file name from the workspace directory. * @returns {string} - The JSON report file name or an empty string if not found. */ -function getJsonReportFileName() { +function getFirstJsonReportFileName(context) { const workspaceDir = getWorkspaceDir(); const filesInWorkspace = shell.ls(workspaceDir); + if (!context.jobUUID) { + core.error('Illegal state: No job uuid resolved - not allowed at this point'); + return ''; + } + const jobUUID = context.jobUUID; + const regex = new RegExp(`sechub_report_.*${jobUUID}.*\\.json$`); for (const fileName of filesInWorkspace) { - if (/sechub_report.*\.json$/.test(fileName)) { + if (regex.test(fileName)) { return fileName; } } @@ -14097,7 +14141,8 @@ const PARAM_INCLUDED_FOLDERS = 'include-folders'; const PARAM_EXCLUDED_FOLDERS = 'exclude-folders'; const PARAM_REPORT_FORMATS = 'report-formats'; const PARAM_FAIL_JOB_ON_FINDING = 'fail-job-with-findings'; -const emptyInputDataDefaults = { +const PARAM_TRUST_ALL = 'trust-all'; +const INPUT_DATA_DEFAULTS = { configPath: '', url: '', apiToken: '', @@ -14109,6 +14154,7 @@ const emptyInputDataDefaults = { excludeFolders: '', reportFormats: '', failJobOnFindings: '', + trustAll: '' }; function resolveGitHubInputData() { return { @@ -14123,6 +14169,7 @@ function resolveGitHubInputData() { excludeFolders: core.getInput(PARAM_EXCLUDED_FOLDERS), reportFormats: core.getInput(PARAM_REPORT_FORMATS), failJobOnFindings: core.getInput(PARAM_FAIL_JOB_ON_FINDING), + trustAll: core.getInput(PARAM_TRUST_ALL), }; } @@ -14138,6 +14185,7 @@ function initEnvironmentVariables(data) { shell.env.SECHUB_SERVER = data.url; shell.env.SECHUB_PROJECT = data.projectName; shell.env.SECHUB_DEBUG = data.debug; + shell.env.SECHUB_TRUSTALL = data.trustAll; } ;// CONCATENATED MODULE: ./src/client-download.ts @@ -14152,9 +14200,6 @@ function initEnvironmentVariables(data) { */ function downloadClientRelease(context) { const clientVersion = context.inputData.sechubCLIVersion; - if (clientVersion == null || clientVersion == '') { - throw new Error('No SecHub client version defined!'); - } if (external_fs_.existsSync(context.clientExecutablePath)) { core.debug(`Client already downloaded - skip download. Path:${context.clientExecutablePath}`); return; @@ -14163,10 +14208,10 @@ function downloadClientRelease(context) { const zipDownloadUrl = `https://github.com/mercedes-benz/sechub/releases/download/v${clientVersion}-client/sechub-cli-${clientVersion}.zip`; core.debug(`SecHub-Client download URL: ${zipDownloadUrl}`); core.debug(`SecHub-Client download folder: ${context.clientDownloadFolder}`); - shellExecOrFail(`mkdir ${context.clientDownloadFolder} -p`); - shellExecOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); - shellExecOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); - shellExecOrFail(`chmod +x ${secHubZipFilePath}`); + shellExecSynchOrFail(`mkdir ${context.clientDownloadFolder} -p`); + shellExecSynchOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); + shellExecSynchOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); + shellExecSynchOrFail(`chmod +x ${secHubZipFilePath}`); } ;// CONCATENATED MODULE: ./src/launcher.ts @@ -14180,42 +14225,62 @@ function downloadClientRelease(context) { - +/** + * Starts the launch process + * @returns launch context + */ async function launch() { const context = createContext(); init(context); - const exitCode = executeScan(context); - await postScan(context, exitCode); + executeScan(context); + await postScan(context); + return context; } const LAUNCHER_CONTEXT_DEFAULTS = { - inputData: emptyInputDataDefaults, + jobUUID: undefined, + inputData: INPUT_DATA_DEFAULTS, reportFormats: ['json'], clientDownloadFolder: '', - configParameter: null, + configFileLocation: null, clientExecutablePath: '', + lastClientExitCode: -1, + secHubJsonFilePath: '', + workspaceFolder: '', + secHubReportJsonObject: undefined, }; /** - * Create scan settings + * Create launch context + * @returns launch context */ function createContext() { var _a, _b; const gitHubInputData = resolveGitHubInputData(); - const clientVersion = gitHubInputData.sechubCLIVersion; // client + const clientVersion = gitHubInputData.sechubCLIVersion; + if (clientVersion == null || clientVersion == '') { + throw new Error('No SecHub client version defined!'); + } const expression = /\./gi; const clientVersionSubFolder = clientVersion.replace(expression, '_'); // avoid . inside path from user input - const clientDownloadFolder = `${getWorkspaceParentDir()}/runtime/client/${clientVersionSubFolder}`; + const workspaceFolder = `${getWorkspaceDir()}`; + const clientDownloadFolder = `${workspaceFolder}/.sechub-gha/client/${clientVersionSubFolder}`; const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; const includeFolders = (_a = gitHubInputData.includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); const excludeFolders = (_b = gitHubInputData.excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); - const configParameter = initSecHubJson(gitHubInputData.configPath, includeFolders, excludeFolders); + const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; + const configParameter = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); const reportFormats = initReportFormats(gitHubInputData.reportFormats); return { - configParameter: configParameter, + jobUUID: LAUNCHER_CONTEXT_DEFAULTS.jobUUID, + secHubReportJsonObject: LAUNCHER_CONTEXT_DEFAULTS.secHubReportJsonObject, + configFileLocation: configParameter, reportFormats: reportFormats, inputData: gitHubInputData, clientDownloadFolder: clientDownloadFolder, clientExecutablePath: clientExecutablePath, + lastClientExitCode: LAUNCHER_CONTEXT_DEFAULTS.lastClientExitCode, + secHubJsonFilePath: generatedSecHubJsonFilePath, + workspaceFolder: workspaceFolder, }; } function init(context) { @@ -14228,17 +14293,22 @@ function init(context) { * @param format Report format that should be downloaded */ function executeScan(context) { - // TODO 2024-01-19: de-jcup: here only the first report format is used... is this not a bug? - const exitCode = scan(context.reportFormats[0], context).code; - logExitCode(exitCode); - return exitCode; -} -async function postScan(context, exitCode) { - const jsonReport = downloadReports(context, context.reportFormats.slice(1)); - reportOutputs(jsonReport); - await uploadArtifact(settings_namespaceObject.vz, getFiles(settings_namespaceObject.nl)); - if (exitCode !== 0 && context.inputData.failJobOnFindings === 'true') { - failAction(exitCode); + scan(context); + logExitCode(context.lastClientExitCode); +} +async function postScan(context) { + if (context.lastClientExitCode > 1) { + // in this case this is an error and we cannot download the report - means fails always + failAction(context.lastClientExitCode); + return; + } + collectReportData(context); + /* reporting - analysis etc. */ + reportOutputs(context.secHubReportJsonObject); + /* upload artifact */ + await uploadArtifact(context, 'sechub scan-report', getFiles(`${context.workspaceFolder}/sechub_report_*.*`)); + if (context.lastClientExitCode !== 0 && context.inputData.failJobOnFindings === 'true') { + failAction(context.lastClientExitCode); } } diff --git a/github-actions/scan/package.json b/github-actions/scan/package.json index b1eca1b0f1..3dbeab3c22 100644 --- a/github-actions/scan/package.json +++ b/github-actions/scan/package.json @@ -8,10 +8,9 @@ "cleanBuild": "ncc cache clean;ncc build src/main.ts", "lint": "eslint src", "prettier": "npx prettier --write src", - "test": "npx jest", - "test-x": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", - "integration-test": "npx jest --runInBand --testPathPattern='integrationtest.test.ts'" - + "test-debug-all": "npx jest", + "test": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", + "integration-test": "jest --runInBand --testPathPattern='integrationtest.test.ts'" }, "license": "MIT", "dependencies": { diff --git a/github-actions/scan/src/client-download.ts b/github-actions/scan/src/client-download.ts index 8cb27da3f2..8b3042ebdd 100644 --- a/github-actions/scan/src/client-download.ts +++ b/github-actions/scan/src/client-download.ts @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -import * as fs from 'fs'; import * as core from '@actions/core'; -import { shellExecOrFail } from './fs-helper'; +import * as fs from 'fs'; +import { shellExecSynchOrFail } from './fs-helper'; import { LaunchContext } from './launcher'; /** @@ -24,10 +24,10 @@ export function downloadClientRelease(context: LaunchContext): void { core.debug(`SecHub-Client download URL: ${zipDownloadUrl}`); core.debug(`SecHub-Client download folder: ${context.clientDownloadFolder}`); - shellExecOrFail(`mkdir ${context.clientDownloadFolder} -p`); + shellExecSynchOrFail(`mkdir ${context.clientDownloadFolder} -p`); - shellExecOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); - shellExecOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); - shellExecOrFail(`chmod +x ${secHubZipFilePath}`); + shellExecSynchOrFail(`curl -L ${zipDownloadUrl} -o ${secHubZipFilePath}`); + shellExecSynchOrFail(`unzip -o ${secHubZipFilePath} -d ${context.clientDownloadFolder}`); + shellExecSynchOrFail(`chmod +x ${secHubZipFilePath}`); } diff --git a/github-actions/scan/src/configuration-builder.ts b/github-actions/scan/src/configuration-builder.ts index 495e1ddf12..fb9511142d 100644 --- a/github-actions/scan/src/configuration-builder.ts +++ b/github-actions/scan/src/configuration-builder.ts @@ -11,7 +11,7 @@ import { SecHubConfigurationModel } from './configuration-model'; * @param excludeFolders Which folders should be excluded */ export function createSecHubConfigJsonFile(secHubJsonFilePath:string, includeFolders: string[] | null, excludeFolders: string[] | null) { - core.info('Config-Path was not found. Config will be created.'); + core.info('Config-Path was not found. Config will be created at '+ secHubJsonFilePath); const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); diff --git a/github-actions/scan/src/exitcode.ts b/github-actions/scan/src/exitcode.ts index a0476a7716..e82c1f5dee 100644 --- a/github-actions/scan/src/exitcode.ts +++ b/github-actions/scan/src/exitcode.ts @@ -21,11 +21,11 @@ exitCodeMap.set(10, 'ERROR - Job has been canceld on SecHub server'); /** - * Logs the exit code and uses error method if not 0. + * Creates a log mesage with the exit code and a description. The message will be loged by calling core.info or core.error (when exit code !=0) * @param code The given exit code */ export function logExitCode(code: number) { - const message = 'Exit code: ' + code+' . Description: '+exitCodeMap.get(code); + const message = 'Exit code: ' + code + ' . Description: ' + exitCodeMap.get(code); if (code === 0) { core.info(message); } else { diff --git a/github-actions/scan/src/fs-helper.ts b/github-actions/scan/src/fs-helper.ts index 0b39218f18..435cbdb4b7 100644 --- a/github-actions/scan/src/fs-helper.ts +++ b/github-actions/scan/src/fs-helper.ts @@ -3,20 +3,41 @@ import * as shell from 'shelljs'; import * as core from '@actions/core'; import * as path from 'path'; +import * as child from 'child_process'; + import { ShellString } from 'shelljs'; /** * Get workspace directory. */ export function getWorkspaceDir(): string { - return shell.env['GITHUB_WORKSPACE'] || ''; + /* github workspace is something like: + * /home/runner/work/sechub/ + * means we are at root level when the action is used + * from outside + * Means: we have a /home/runner/work/sechub/runtime folder + * /home/runner/work/other-repo/runtime + * + * For local builds/runs this must be done as well. + * + */ + const workspace=shell.env['GITHUB_WORKSPACE']; + if (workspace==null){ + /* not set, means local,we are inside github-actions/scan */ + return '../../'; + }else{ + return `${workspace}`; + } + } /** * Get parent folder of workspace directory. */ -export function getWorkspaceParentDir() { - return path.dirname(getWorkspaceDir()); +export function ensuredWorkspaceFolder() { + const ensuredWorkspaceFolder= path.dirname(getWorkspaceDir()); + // TODO check folder exists or fal + return ensuredWorkspaceFolder; } /** @@ -34,23 +55,37 @@ export function getFiles(pattern: string): string[] { return reportFiles; } -export class ShellFailedWithExitCodeNotZeroError extends Error { - constructor(command: string, shellExecResult: ShellString) { - super(`Shell script call failed.\nExit code: ${shellExecResult.code}\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}`); +export class ShellFailedWithExitCodeNotAcceptedError extends Error { + constructor(command: string, shellExecResult: ShellString, acceptedExitCodes: number[]) { + super(`Shell script call failed.\nExit code: ${shellExecResult.code} - accepted would be: ${acceptedExitCodes}.\nCommand: "${command}"\nStdErr: ${shellExecResult.stderr}\nStdOut: ${shellExecResult.stdout}`); } } /** - * Executes given command by shell - errors are handled - * @param command + * Executes given command by shell synchronous - errors are handled. + * Attention: This mechanism has problems with script execution where child processes are created! + * In this case the script execution by shelljs freezes! Workaround here: Use shellExecAsync(..) in + * this case! + * @param command command to execute + * @param acceptedExitCodes - an array with accepted exit codes. if not defined only 0 is accepted * @throws ShellFailedWithExitCodeNotZeroError * @returns shellstring */ -export function shellExecOrFail(command: string): ShellString { +export function shellExecSynchOrFail(command: string, acceptedExitCodes: number[] = [0]): ShellString { + const shellExecResult = shell.exec(command); - if ( shellExecResult.code!=0){ - throw new ShellFailedWithExitCodeNotZeroError(command, shellExecResult); + if (! acceptedExitCodes.includes(shellExecResult.code)){ + throw new ShellFailedWithExitCodeNotAcceptedError(command, shellExecResult, acceptedExitCodes); } return shellExecResult; +} + +/** + * Executes given command asynchronous + * @param command command to execute + * @returns child process + */ +export function shellExecAsync(command: string): child.ChildProcess { + return child.exec(command); } \ No newline at end of file diff --git a/github-actions/scan/src/json-helper.ts b/github-actions/scan/src/json-helper.ts new file mode 100644 index 0000000000..db5c991290 --- /dev/null +++ b/github-actions/scan/src/json-helper.ts @@ -0,0 +1,26 @@ +import * as core from '@actions/core'; + +/** + * Reads the given field from the SecHub JSON report. + * @param {string} field - The field relative to root, where the value should be found. The field can be a nested field, e.g. result.count. + * @param jsonData - The json data to read the field from. + * @returns {*} - The value found for the given field or undefined if not found. + */ +export function getFieldFromJsonReport(field: string, jsonData: any): any { + // Split the given field into individual keys + const keys = field.split('.'); + + // Traverse the JSON object to find the requested field + let currentKey = jsonData; + for (const key of keys) { + // eslint-disable-next-line no-prototype-builtins + if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { + currentKey = currentKey[key]; + } else { + core.warning(`Field "${key}" not found in the JSON report.`); + return undefined; + } + } + + return currentKey; +} diff --git a/github-actions/scan/src/launcher.ts b/github-actions/scan/src/launcher.ts index 4f17ac2d4f..66c217a362 100644 --- a/github-actions/scan/src/launcher.ts +++ b/github-actions/scan/src/launcher.ts @@ -3,15 +3,12 @@ import { failAction } from './action-helper'; import { scan } from './sechub-cli'; import { logExitCode } from './exitcode'; -import { getFiles, getWorkspaceParentDir } from './fs-helper'; +import { getFiles, getWorkspaceDir } from './fs-helper'; import { initReportFormats, initSecHubJson } from './init-scan'; -import { downloadReports, reportOutputs, uploadArtifact } from './post-scan'; +import { collectReportData, reportOutputs, uploadArtifact } from './post-scan'; import { GitHubInputData, resolveGitHubInputData, INPUT_DATA_DEFAULTS } from './input'; import { initEnvironmentVariables } from './environment'; import { downloadClientRelease } from './client-download'; -import { exit } from 'shelljs'; - - /** * Starts the launch process @@ -31,6 +28,8 @@ export async function launch(): Promise { } export interface LaunchContext { + jobUUID: string|undefined; + inputData: GitHubInputData; configFileLocation: string | null; @@ -41,25 +40,32 @@ export interface LaunchContext { clientExecutablePath: string; lastClientExitCode: number; - runtimeFolder: string; + workspaceFolder: string; secHubJsonFilePath: string; + + secHubReportJsonObject: object|undefined; } export const LAUNCHER_CONTEXT_DEFAULTS: LaunchContext = { + jobUUID : undefined, + inputData: INPUT_DATA_DEFAULTS, reportFormats: ['json'], clientDownloadFolder: '', configFileLocation: null, clientExecutablePath: '', - lastClientExitCode: -1, + lastClientExitCode: -1, secHubJsonFilePath: '', - runtimeFolder: '', + workspaceFolder: '', + secHubReportJsonObject: undefined, }; + /** - * Create scan settings + * Create launch context + * @returns launch context */ function createContext(): LaunchContext { @@ -74,20 +80,23 @@ function createContext(): LaunchContext { const expression = /\./gi; const clientVersionSubFolder = clientVersion.replace(expression, '_'); // avoid . inside path from user input - const runtimeFolder = `${getWorkspaceParentDir()}/runtime`; - const clientDownloadFolder = `${runtimeFolder}/client/${clientVersionSubFolder}`; + const workspaceFolder = `${getWorkspaceDir()}`; + const clientDownloadFolder = `${workspaceFolder}/.sechub-gha/client/${clientVersionSubFolder}`; const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; const includeFolders = gitHubInputData.includeFolders?.split(','); const excludeFolders = gitHubInputData.excludeFolders?.split(','); - const secHubJsonFilePath = `${runtimeFolder}/sechub.json`; + const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; - const configParameter = initSecHubJson(secHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + const configParameter = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); const reportFormats = initReportFormats(gitHubInputData.reportFormats); return { + jobUUID: LAUNCHER_CONTEXT_DEFAULTS.jobUUID, + secHubReportJsonObject: LAUNCHER_CONTEXT_DEFAULTS.secHubReportJsonObject, + configFileLocation: configParameter, reportFormats: reportFormats, inputData: gitHubInputData, @@ -96,8 +105,8 @@ function createContext(): LaunchContext { lastClientExitCode: LAUNCHER_CONTEXT_DEFAULTS.lastClientExitCode, - secHubJsonFilePath: secHubJsonFilePath, - runtimeFolder:runtimeFolder, + secHubJsonFilePath: generatedSecHubJsonFilePath, + workspaceFolder:workspaceFolder, }; } @@ -114,8 +123,7 @@ function init(context: LaunchContext) { * @param format Report format that should be downloaded */ function executeScan(context: LaunchContext) { - // TODO 2024-01-19: de-jcup: here only the first report format is used... is this not a bug? - scan(context.reportFormats[0], context); + scan(context); logExitCode(context.lastClientExitCode); } @@ -126,13 +134,14 @@ async function postScan(context: LaunchContext): Promise { failAction(context.lastClientExitCode); return; } - const jsonReport = downloadReports(context, context.reportFormats.slice(1)); + + collectReportData(context); /* reporting - analysis etc. */ - reportOutputs(jsonReport); + reportOutputs(context.secHubReportJsonObject); /* upload artifact */ - await uploadArtifact(context, 'sechub scan-report', getFiles(`${context.runtimeFolder}/sechub_report_*.*`)); + await uploadArtifact(context, 'sechub scan-report', getFiles(`${context.workspaceFolder}/sechub_report_*.*`)); if (context.lastClientExitCode !== 0 && context.inputData.failJobOnFindings === 'true') { failAction(context.lastClientExitCode); diff --git a/github-actions/scan/src/post-scan.ts b/github-actions/scan/src/post-scan.ts index 69fcc29304..6591173388 100644 --- a/github-actions/scan/src/post-scan.ts +++ b/github-actions/scan/src/post-scan.ts @@ -8,44 +8,68 @@ import { getWorkspaceDir } from './fs-helper'; import { LaunchContext } from './launcher'; import { logExitCode } from './exitcode'; import { getReport } from './sechub-cli'; +import { getFieldFromJsonReport } from './json-helper'; /** - * Downloads the reports for the given formats. - * @param formats formats in which the report should be downloaded + * Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary */ -export function downloadReports(context: LaunchContext, formats: string[]): object | undefined { - core.startGroup('Download Reports'); - if (formats.length === 0) { - core.info('No more formats'); - return; +core.startGroup('Collect report data'); +export function collectReportData(context: LaunchContext) { + core.startGroup('Collect report data'); + + collectJsonReportData(context); + downloadOtherReportsThanJson(context); + + core.endGroup(); +} + +function collectJsonReportData(context: LaunchContext) { + + /* json - already downloaded by client on scan, here we just ensure it exists and fetch the data from the model */ + const fileName = getFirstJsonReportFileName(context); + const filePath = `${getWorkspaceDir()}/${fileName}`; + let text = ''; + try { + core.info('Get Report as json'); + text = fs.readFileSync(filePath, 'utf8'); + } catch (error) { + core.warning(`Error reading JSON file: ${error}`); + return undefined; } - const json = loadJsonReport(); - if (json) { - const jobUUID = getFieldFromJsonReport('jobUUID', json); + + const jsonObject = asJsonObject(text); + + /* setup data in context */ + context.secHubReportJsonObject = jsonObject; + +} + + +function downloadOtherReportsThanJson(context: LaunchContext) { + if (context.jobUUID) { + const jobUUID=context.jobUUID; core.debug('JobUUID: ' + jobUUID); - formats.forEach((format) => { - core.info(`Get Report as ${format}`); - getReport(jobUUID, format,context); - logExitCode(context.lastClientExitCode); + + context.reportFormats.forEach((format) => { + if (format != 'json') { // json is skipped, because already downloaded + core.info(`Get Report as ${format}`); + getReport(jobUUID, format, context); + logExitCode(context.lastClientExitCode); + } }); } - core.endGroup(); - return json; } /** - * Load and parse the SecHub JSON report. + * Parse the SecHub JSON report. * @returns {object | undefined} - The parsed JSON report or undefined if not found or there was an error. */ -function loadJsonReport(): object | undefined { - const fileName = getJsonReportFileName(); - const filePath = `${getWorkspaceDir()}/${fileName}`; - +function asJsonObject(text: string): object | undefined { try { - const jsonData = JSON.parse(fs.readFileSync(filePath, 'utf8')); + const jsonData = JSON.parse(text); return jsonData; } catch (error) { - core.warning(`Error reading or parsing JSON file: ${error}`); + core.warning(`Error parsing JSON file: ${error}`); return undefined; } } @@ -62,16 +86,16 @@ export async function uploadArtifact(context: LaunchContext, name: string, paths const artifactName = name; const options = { continueOnError: true }; - const rootDirectory = context.runtimeFolder; + const rootDirectory = context.workspaceFolder; core.debug('rootDirectory: ' + rootDirectory); - if (core.isDebug()){ + if (core.isDebug()) { shell.exec(`ls ${rootDirectory}`); } core.debug('paths: ' + paths); await artifactClient.uploadArtifact(artifactName, paths, rootDirectory, options); core.debug('artifact upload done'); - + } catch (e: unknown) { const message = e instanceof Error ? e.message : 'Unknown error'; core.error(`ERROR while uploading artifacts: ${message}`); @@ -79,41 +103,23 @@ export async function uploadArtifact(context: LaunchContext, name: string, paths core.endGroup(); } -/** - * Reads the given field from the SecHub JSON report. - * @param {string} field - The field relative to root, where the value should be found. The field can be a nested field, e.g. result.count. - * @param jsonData - The json data to read the field from. - * @returns {*} - The value found for the given field or undefined if not found. - */ -function getFieldFromJsonReport(field: string, jsonData: any): any { - // Split the given field into individual keys - const keys = field.split('.'); - - // Traverse the JSON object to find the requested field - let currentKey = jsonData; - for (const key of keys) { - // eslint-disable-next-line no-prototype-builtins - if (currentKey && currentKey.hasOwnProperty && typeof currentKey.hasOwnProperty === 'function' && currentKey.hasOwnProperty(key)) { - currentKey = currentKey[key]; - } else { - core.warning(`Field "${key}" not found in the JSON report.`); - return undefined; - } - } - - return currentKey; -} - /** * Get the JSON report file name from the workspace directory. * @returns {string} - The JSON report file name or an empty string if not found. */ -function getJsonReportFileName(): string { +function getFirstJsonReportFileName(context: LaunchContext): string { const workspaceDir = getWorkspaceDir(); const filesInWorkspace = shell.ls(workspaceDir); + if (! context.jobUUID){ + core.error('Illegal state: No job uuid resolved - not allowed at this point'); + return ''; + } + const jobUUID = context.jobUUID; + const regex = new RegExp(`sechub_report_.*${jobUUID}.*\\.json$`); + for (const fileName of filesInWorkspace) { - if (/sechub_report.*\.json$/.test(fileName)) { + if (regex.test(fileName)) { return fileName; } } @@ -169,18 +175,18 @@ function analyzeFindings(jsonData: any): { mediumCount: number; highCount: numbe findings.forEach((finding: { severity: string; }) => { switch (finding.severity) { - case 'MEDIUM': - mediumCount++; - break; - case 'HIGH': - highCount++; - break; - case 'LOW': - lowCount++; - break; - default: - unmapped++; - break; + case 'MEDIUM': + mediumCount++; + break; + case 'HIGH': + highCount++; + break; + case 'LOW': + lowCount++; + break; + default: + unmapped++; + break; } }); diff --git a/github-actions/scan/src/sechub-cli.ts b/github-actions/scan/src/sechub-cli.ts index 776ffb0af8..e073cb9793 100644 --- a/github-actions/scan/src/sechub-cli.ts +++ b/github-actions/scan/src/sechub-cli.ts @@ -6,16 +6,29 @@ import * as core from '@actions/core'; /** * Executes the scan method of the SecHub CLI. Sets the client exitcode inside context. * @param parameter Parameters to execute the scan with - * @param format Report format that should be fetched * @param context: launch context */ -export function scan(format: string, context: LaunchContext) { - const shellString = shell.exec(`${context.clientExecutablePath} -configfile ${context.configFileLocation} -output ${context.runtimeFolder} -reportformat ${format} scan`); +export function scan(context: LaunchContext) { + const shellString = shell.exec(`${context.clientExecutablePath} -configfile ${context.configFileLocation} -output ${context.workspaceFolder} scan`); context.lastClientExitCode= shellString.code; if (context.lastClientExitCode!=0){ core.error(shellString.stderr); } + context.jobUUID=extractJobUUID(shellString.stdout); +} + +export function extractJobUUID(output: string): string{ + const jobPrefix='job:'; + const index1 =output.indexOf(jobPrefix); + if (index1>-1){ + const index2 = output.indexOf('\n', index1); + if (index2>-1){ + const extracted=output.substring(index1+jobPrefix.length,index2); + return extracted.trim(); + } + } + return ''; } /** diff --git a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/mock/MockedAdapterSetupService.java b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/mock/MockedAdapterSetupService.java index 6582e6ba2d..83c671c055 100644 --- a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/mock/MockedAdapterSetupService.java +++ b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/mock/MockedAdapterSetupService.java @@ -82,7 +82,7 @@ private void ensureSetupLoaded() { private void loadConfiguredSetup() { try { - LOG.info("Loading conifgured setup from {}", filePath); + LOG.info("Loading configured setup from {}", filePath); String json = mockSupport.loadResourceString(filePath); staticMockSetup = JSONAdapterSupport.FOR_UNKNOWN_ADAPTER.fromJSON(MockedAdapterSetup.class, json); diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh index 130b733338..0828d29a80 100755 --- a/sechub-developertools/scripts/sdc.sh +++ b/sechub-developertools/scripts/sdc.sh @@ -4,13 +4,32 @@ set -e lastCommandHandled="" +RED='\033[0;31m' +LIGHT_RED='\033[1;31m' +LIGHT_GREEN='\033[1;32m' +BROWN='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' + +NC='\033[0m' # No Color + + function startJob (){ - echo "**************************************************************************************************" - echo "* Start job: $1" - echo "**************************************************************************************************" + echo -e "${BROWN}---------------------------------------------------${NC}" + echo -e "${BROWN} Start job: $1" + echo -e "${BROWN}---------------------------------------------------${NC}" export lastCommandHandled=$1 } +function startTask (){ + echo -e "${BLUE}[ $1 ]${NC}" +} + +function specialTask (){ + echo -e "${PURPLE}[ $1 ]${NC}" +} + + function step (){ echo "- ++++++++++++++++++++++++++++++++++" echo "- STEP: $1" @@ -18,14 +37,15 @@ function step (){ } function showHelp () { - echo "-------------------------------------" - echo "- SDC - SecHub developer command line" - echo "-------------------------------------" + echo -e "${BROWN}---------------------------------------------------${NC}" + echo -e "${BROWN}- SDC - SecHub developer command line${NC}" + echo -e "${BROWN}---------------------------------------------------${NC}" echo "Usage: Usage sdc" echo " Option s: " echo " -f, --format-all : format all source code files" echo " -b, --build-full : full build" echo " -bpt, --build-pds-tools : build pds tools" + echo " -bgh, --build-github-action : build github action (node js)" echo " -d, --document-full : full document build" echo " -u, --unit-tests : execute all unit tests" echo " -i, --integrationtest-all : execute all integration tests" @@ -40,7 +60,9 @@ function showHelp () { echo " -gj, --generate-java-api : generates parts for java api" echo "" echo " -syg, --start-systemtest-sanity-check-gosec : start systemtest 'sanity-check' for gosec with local build pds tools (0.0.0)" + echo "" echo " -h, --help : show this help" + } SCRIPT_DIR="$(dirname -- "$0")" @@ -108,6 +130,10 @@ do PDS_TOOLS_BUILD="YES" shift # past argument ;; + -bgh|--build-github-action) + GITHUB_ACTION_BUILD="YES" + shift # past argument + ;; -d|--document-full) DOCUMENT_FULL="YES" shift # past argument @@ -272,6 +298,67 @@ if [[ "$START_SYSTEMTEST_SANITYCHECK_GOSEC" = "YES" ]]; then cd $SECHUB_ROOT_DIR fi +# Builds github action ("scan") like done in workflow, means the integration tests are executed as well) +# We do here the same steps as done in 'github-action-scan.yml' +if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then + ### -------------------------- + ### Build GitHub action "scan" + ### -------------------------- + startJob "Build GitHub action 'scan'" + + # Set working directory (to default) + cd $SECHUB_ROOT_DIR + cd ./github-actions/scan + + specialTask "Use Node.js" + echo "Not done locally. Please setup this on your machine by nvm. For example: 'nvm use node' (sets to latest)" + + startTask "Clean install" + npm ci + + startTask "Build" + npm run build --if-present + + startTask "Run unit tests" + npm test + + startTask "Setup integration test data" + # Define variables + sechub_server_version=1.4.1 + sechub_server_port=8443 + pds_version=1.4.0 + pds_port=8444 + echo "Version and port variables are now defined" + + # Set working directory + cd ./__test__/integrationtest/ + + # next lines only for our local build: we stop always former running integration test servers (to call it multiple times) + specialTask "Stop former running test servers" + ./05-stop.sh $sechub_server_port $pds_port + + # Start integration test servers + startTask "Start integration test servers" + ./01-start.sh $sechub_server_version $sechub_server_port $pds_version $pds_port + + # Init integration test data + startTask "Init integration test data" + ./03-init_sechub_data.sh $sechub_server_port $pds_port + + + # Set working directory (to default) + cd $SECHUB_ROOT_DIR + cd ./github-actions/scan + + # Run integration tests + startTask "Run integration tests" + npm run integration-test + + # Cleanup integration tests + startTask "Cleanup integration tests" + ./05-stop.sh $sechub_server_port $pds_port +fi + # ----------------------- # Handle unknown commands @@ -281,4 +368,4 @@ if [[ "${lastCommandHandled}" = "" ]]; then exit 1 fi - \ No newline at end of file + diff --git a/sechub-doc/src/docs/asciidoc/documents/techdoc/01_development.adoc b/sechub-doc/src/docs/asciidoc/documents/techdoc/01_development.adoc index 1dda6a2080..ea6cbb27fc 100644 --- a/sechub-doc/src/docs/asciidoc/documents/techdoc/01_development.adoc +++ b/sechub-doc/src/docs/asciidoc/documents/techdoc/01_development.adoc @@ -184,7 +184,9 @@ Overview of branch types: to `develop` branch as well. |`develop` |master | Development branch. This branch will be part of the next release. Do not commit into this branch. Instead create a dedicated feature-branch. -|`feature-${issue}` |develop | For each feature we create a `feature-1234-xyz` branch. It will be merged into the `develop` branch when finished. +|`feature-${issue}` |develop | For each feature we create a `feature-1234-xyz` branch. It will be merged into the `develop` branch when finished. A git push to remote will trigger a full CI/CD build for SecHub client, server and PDS but not for SecHub github actions. +|`gha_feature-${issue}` |develop | For each github action feature we create a `gha_feature-1234-xyz` branch. It will be merged into the `develop` branch when finished. A git push to remote will trigger CI/CD build for SecHub github actions, but NOT a full CI/CD build for SecHub client, server and PDS. + |=== @@ -243,4 +245,4 @@ NOTE: This will disable ssl encryption and also Spring security which requires s If you want to administrate this by developer admin ui, you should also switch to the HTTP protocol as described in section -<> \ No newline at end of file +<> diff --git a/sechub-schedule/src/main/java/com/mercedesbenz/sechub/domain/schedule/access/ScheduleGrantUserAccessToProjectService.java b/sechub-schedule/src/main/java/com/mercedesbenz/sechub/domain/schedule/access/ScheduleGrantUserAccessToProjectService.java index 3b9b02afb2..6b348df8e5 100644 --- a/sechub-schedule/src/main/java/com/mercedesbenz/sechub/domain/schedule/access/ScheduleGrantUserAccessToProjectService.java +++ b/sechub-schedule/src/main/java/com/mercedesbenz/sechub/domain/schedule/access/ScheduleGrantUserAccessToProjectService.java @@ -31,10 +31,10 @@ public void grantUserAccessToProject(String userId, String projectId) { ScheduleAccess scheduleAccess = new ScheduleAccess(userId, projectId); Optional potentialAlreadyFound = repository.findById(scheduleAccess.getKey()); if (potentialAlreadyFound.isPresent()) { - LOG.debug("User {} has already acces to {} so skipped", userId, projectId); + LOG.debug("User {} has already access to {} so skipped", userId, projectId); return; } - LOG.debug("User {} has now gained acces to {}", userId, projectId); + LOG.debug("User {} has now gained access to {}", userId, projectId); repository.save(scheduleAccess); } diff --git a/sechub.json b/sechub.json index d5b0a48fca..7dee0222f8 100644 --- a/sechub.json +++ b/sechub.json @@ -1,45 +1 @@ -{ - "apiVersion": "1.0", - "codeScan": { - "use": [ - "sechub-sources" - ] - }, - "data": { - "sources": [ - { - "name": "sechub-sources", - "fileSystem": { - "folders": [ - "." - ] - }, - "excludes": [ - "**/.project", - "**/bin/**", - "**/build/**", - "**/examples/**", - "**/gen/**", - "**/tests/**", - "*_test.go", - "*.gradle", - "*.json", - "*-testframework/**", - ".gradle/**", - "buildSrc/**", - "docs/**", - "gradle/**", - "sechub-cli/pkg/mod/**", - "sechub-developertools/**", - "sechub-doc/**", - "sechub-examples/**", - "sechub-integrationtest/**", - "sechub-other/**", - "sechub-storage-s3-aws-test/**", - "sechub-systemtest/**", - "sechub-test/**" - ] - } - ] - } -} \ No newline at end of file +{"apiVersion":"1.0","codeScan":{"fileSystem":{"folders":["__test__/integrationtest/test-sources"]}}} \ No newline at end of file From f38799e4bf371fbe647d6d54e3cee3835faa45f9 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Fri, 8 Mar 2024 15:32:01 +0100 Subject: [PATCH 07/30] Upgrade workflow for integration test, uses newer version #2441 - server 1.7.0 - pds 1.4.0 - fixed some minor linter warnings - renamed a method --- .github/workflows/github-action-scan.yml | 2 +- github-actions/scan/README.adoc | 21 ++++++++----- .../scan/__test__/integrationtest.test.ts | 5 ++- .../scan/__test__/integrationtest/01-start.sh | 2 +- .../__test__/integrationtest/testframework.ts | 2 -- .../scan/__test__/sechub-cli.test.ts | 1 + github-actions/scan/dist/index.js | 7 ++--- github-actions/scan/package.json | 2 +- github-actions/scan/src/post-scan.ts | 31 +++++++++---------- sechub-developertools/scripts/sdc.sh | 2 +- 10 files changed, 38 insertions(+), 37 deletions(-) diff --git a/.github/workflows/github-action-scan.yml b/.github/workflows/github-action-scan.yml index 72a12e74e5..41749badf5 100644 --- a/.github/workflows/github-action-scan.yml +++ b/.github/workflows/github-action-scan.yml @@ -35,7 +35,7 @@ jobs: - name: Setup integration test data id : version-selector run: | - echo "sechub_server_version=1.4.1" >> "$GITHUB_ENV" + echo "sechub_server_version=1.7.0" >> "$GITHUB_ENV" echo "sechub_server_port=8443" >> "$GITHUB_ENV" echo "pds_version=1.4.0" >> "$GITHUB_ENV" echo "pds_port=8444" >> "$GITHUB_ENV" diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc index 71bc8b1225..b0f6f7d493 100644 --- a/github-actions/scan/README.adoc +++ b/github-actions/scan/README.adoc @@ -1,10 +1,14 @@ // SPDX-License-Identifier: MIT +:toc: +:toclevels: 5 == GitHub Action for SecHub scan This GitHub action uses the SecHub cli to scan the repository for security issues. + + === Usage To be able to use this action you need a SecHub project. Check the https://mercedes-benz.github.io/sechub/[documentation] on how to set one up. @@ -121,8 +125,7 @@ export SECHUB_DEBUG=true The unit and also the integration tests are written with `jest` test framework. ===== Setup - -**VSCodium** +====== VSCodium Used extensions @@ -130,17 +133,19 @@ Used extensions - Jest Test explorer - Jest -In this setup the tests can be executed from sidebar and from links created inside editor. +In this setup the tests can be executed from sidebar and from links created inside the editor. -But ... unfortunately, the Jest UI integration works only for npm script "test" which is normally not used for -integration tests (to handle them special). +[TIP] +==== +Unfortunately, the Jest UI integration works only for npm script "test". But to handle integration tests different (the tests shall only be executed when all is build and servers are started) they are not executed by "test" script. -If you want to debug an integration test, there is a workaround necessary: +If you want to **debug an integration test**, there is a temporary workaround necessary while you debug the test: - open `package.json` and look into section `scripts` -- switch `test-debug-all` to `test` and name former `test` script entry to `test-debug-not-integrationtest` +- switch `test-with-integrationtests` to `test` and rename former `test` script entry to something else - e.g. `test-without-integrationtests` (but please do not push this - otherwise build will fail on integration test!) - restart your VSCode/VSCodium instance (if integration tests are not listed in test explorer) - debug the parts, fix it etc. -- switch `test` script entry to `test-debug-all` and `test-debug-not-integrationtest` to `test`. +- switch `test` script entry back to `test-with-integrationtests` and `test-without-integrationtests` to `test`. - if necessary push fixes/changes to remote... +==== \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest.test.ts b/github-actions/scan/__test__/integrationtest.test.ts index f3a9cf2af6..bd7566823e 100644 --- a/github-actions/scan/__test__/integrationtest.test.ts +++ b/github-actions/scan/__test__/integrationtest.test.ts @@ -19,7 +19,7 @@ jest.mock('@actions/artifact'); /* * This is an integration test suite for github-action "scan". * As precondition you have to call "01-start.sh" and "03-init_sechub_data.sh" (please look into scripts for an example and more details, or -* call 'sdc -bgh' to do a full build for github action which does automatically execute the scripts and this test) +* call 'sdc -bgh' to do a full build for github action which does automatically execute the scripts and all integration tests) * * After start and prepare scripts have finished you can execute the integration tests via "npm run integration-test" * @@ -34,7 +34,6 @@ const integrationTestContext = new IntegrationTestContext(); integrationTestContext.workspaceDir = getWorkspaceDir(); -integrationTestContext.serverVersion = '1.4.0'; // TODO make this configurable - in our start script it is already configurable integrationTestContext.serverPort = 8443; // TODO make this configurable - in our start script it is already configurable integrationTestContext.serverUserId = 'int-test_superadmin'; // TODO make this configurable - in our start script it is already configurable integrationTestContext.serverApiToken = 'int-test_superadmin-pwd'; // TODO make this configurable - in our start script it is already configurable @@ -84,7 +83,7 @@ function initInputMap() { mockedInputMap.set(input.PARAM_SECHUB_USER, `${integrationTestContext.serverUserId}`); mockedInputMap.set(input.PARAM_API_TOKEN, `${integrationTestContext.serverApiToken}`); - mockedInputMap.set(input.PARAM_CLIENT_VERSION, '1.2.0'); + mockedInputMap.set(input.PARAM_CLIENT_VERSION, '1.4.0'); mockedInputMap.set(input.PARAM_REPORT_FORMATS, 'json'); mockedInputMap.set(input.PARAM_TRUST_ALL, 'true'); // self signed certificate in test... diff --git a/github-actions/scan/__test__/integrationtest/01-start.sh b/github-actions/scan/__test__/integrationtest/01-start.sh index ecc0123aa6..f20ceee497 100755 --- a/github-actions/scan/__test__/integrationtest/01-start.sh +++ b/github-actions/scan/__test__/integrationtest/01-start.sh @@ -19,7 +19,7 @@ set -e # Example: # ``` # cd $gitRoot/github-actions/scan -# ./01-start.sh 1.4.1 8443 1.4.0 8444 +# ./01-start.sh 1.7.0 8443 1.4.0 8444 # ``` # SERVER_VERSION=$1 diff --git a/github-actions/scan/__test__/integrationtest/testframework.ts b/github-actions/scan/__test__/integrationtest/testframework.ts index dd8600d321..18c7e158b3 100644 --- a/github-actions/scan/__test__/integrationtest/testframework.ts +++ b/github-actions/scan/__test__/integrationtest/testframework.ts @@ -6,9 +6,7 @@ export class IntegrationTestContext { workspaceDir: string|undefined; - serverVersion: string|undefined; serverPort: number|undefined; - serverUserId: string|undefined; serverApiToken: string|undefined; diff --git a/github-actions/scan/__test__/sechub-cli.test.ts b/github-actions/scan/__test__/sechub-cli.test.ts index bd5aa75d40..7798c7cfd1 100644 --- a/github-actions/scan/__test__/sechub-cli.test.ts +++ b/github-actions/scan/__test__/sechub-cli.test.ts @@ -24,6 +24,7 @@ describe('sechub-cli', function() { /* test */ expect(jobUUID).toEqual('6880e518-88db-406a-bc67-851933e7e5b7'); }); + it('extractJobUUID returns job uuid from string with "job: xxxx"', function () { const output = ` diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index 912ee4fb06..ef8a2138dd 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -13920,7 +13920,6 @@ function getFieldFromJsonReport(field, jsonData) { /** * Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary */ -core.startGroup('Collect report data'); function collectReportData(context) { core.startGroup('Collect report data'); collectJsonReportData(context); @@ -13929,7 +13928,7 @@ function collectReportData(context) { } function collectJsonReportData(context) { /* json - already downloaded by client on scan, here we just ensure it exists and fetch the data from the model */ - const fileName = getFirstJsonReportFileName(context); + const fileName = resolveReportNameForScanJob(context); const filePath = `${getWorkspaceDir()}/${fileName}`; let text = ''; try { @@ -13998,10 +13997,10 @@ async function uploadArtifact(context, name, paths) { core.endGroup(); } /** - * Get the JSON report file name from the workspace directory. + * Get the JSON report file name for the scan job from the workspace directory. * @returns {string} - The JSON report file name or an empty string if not found. */ -function getFirstJsonReportFileName(context) { +function resolveReportNameForScanJob(context) { const workspaceDir = getWorkspaceDir(); const filesInWorkspace = shell.ls(workspaceDir); if (!context.jobUUID) { diff --git a/github-actions/scan/package.json b/github-actions/scan/package.json index 3dbeab3c22..7d7659903f 100644 --- a/github-actions/scan/package.json +++ b/github-actions/scan/package.json @@ -8,7 +8,7 @@ "cleanBuild": "ncc cache clean;ncc build src/main.ts", "lint": "eslint src", "prettier": "npx prettier --write src", - "test-debug-all": "npx jest", + "test-with-integrationtests": "npx jest", "test": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", "integration-test": "jest --runInBand --testPathPattern='integrationtest.test.ts'" }, diff --git a/github-actions/scan/src/post-scan.ts b/github-actions/scan/src/post-scan.ts index 6591173388..b1e867a2c4 100644 --- a/github-actions/scan/src/post-scan.ts +++ b/github-actions/scan/src/post-scan.ts @@ -13,7 +13,6 @@ import { getFieldFromJsonReport } from './json-helper'; /** * Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary */ -core.startGroup('Collect report data'); export function collectReportData(context: LaunchContext) { core.startGroup('Collect report data'); @@ -26,7 +25,7 @@ export function collectReportData(context: LaunchContext) { function collectJsonReportData(context: LaunchContext) { /* json - already downloaded by client on scan, here we just ensure it exists and fetch the data from the model */ - const fileName = getFirstJsonReportFileName(context); + const fileName = resolveReportNameForScanJob(context); const filePath = `${getWorkspaceDir()}/${fileName}`; let text = ''; try { @@ -104,10 +103,10 @@ export async function uploadArtifact(context: LaunchContext, name: string, paths } /** - * Get the JSON report file name from the workspace directory. + * Get the JSON report file name for the scan job from the workspace directory. * @returns {string} - The JSON report file name or an empty string if not found. */ -function getFirstJsonReportFileName(context: LaunchContext): string { +function resolveReportNameForScanJob(context: LaunchContext): string { const workspaceDir = getWorkspaceDir(); const filesInWorkspace = shell.ls(workspaceDir); @@ -175,18 +174,18 @@ function analyzeFindings(jsonData: any): { mediumCount: number; highCount: numbe findings.forEach((finding: { severity: string; }) => { switch (finding.severity) { - case 'MEDIUM': - mediumCount++; - break; - case 'HIGH': - highCount++; - break; - case 'LOW': - lowCount++; - break; - default: - unmapped++; - break; + case 'MEDIUM': + mediumCount++; + break; + case 'HIGH': + highCount++; + break; + case 'LOW': + lowCount++; + break; + default: + unmapped++; + break; } }); diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh index 0828d29a80..b1c6a7ee87 100755 --- a/sechub-developertools/scripts/sdc.sh +++ b/sechub-developertools/scripts/sdc.sh @@ -324,7 +324,7 @@ if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then startTask "Setup integration test data" # Define variables - sechub_server_version=1.4.1 + sechub_server_version=1.7.0 sechub_server_port=8443 pds_version=1.4.0 pds_port=8444 From 66ccb1ecd92c19c38091af91bfe3249512e630b7 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Mon, 18 Mar 2024 10:52:42 +0100 Subject: [PATCH 08/30] Added webscan integration test + improved integration tests #2441 --- github-actions/scan/README.adoc | 6 +- .../scan/__test__/init-scan.test.ts | 16 +- .../scan/__test__/integrationtest.test.ts | 64 +- .../integrationtest/03-init_sechub_data.sh | 3 + .../gha_integrationtest_pds-config.json | 6 + .../sechub-config-webscan-project-4.json | 8 + .../test-executor-webscan-red.json | 39 + .../example-owasp-zap-sarif-output-red.json | 1037 +++++++++++++++++ .../test-scripts/pds-codescan-demo-green.sh | 2 +- .../test-scripts/pds-codescan-demo-red.sh | 2 +- .../test-scripts/pds-codescan-demo-yellow.sh | 2 +- .../test-scripts/pds-webscan-demo-red.sh | 4 + .../__test__/test-resources/test-config.json | 3 + github-actions/scan/dist/index.js | 24 +- github-actions/scan/package.json | 2 + github-actions/scan/src/fs-helper.ts | 1 - github-actions/scan/src/init-scan.ts | 15 +- github-actions/scan/src/launcher.ts | 6 +- github-actions/scan/src/main.ts | 2 +- sechub-developertools/scripts/sdc.sh | 125 +- 20 files changed, 1293 insertions(+), 74 deletions(-) create mode 100644 github-actions/scan/__test__/integrationtest/test-config/sechub-config-webscan-project-4.json create mode 100644 github-actions/scan/__test__/integrationtest/test-config/test-executor-webscan-red.json create mode 100644 github-actions/scan/__test__/integrationtest/test-product-output/example-owasp-zap-sarif-output-red.json create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-webscan-demo-red.sh create mode 100644 github-actions/scan/__test__/test-resources/test-config.json diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc index b0f6f7d493..ef6eca428c 100644 --- a/github-actions/scan/README.adoc +++ b/github-actions/scan/README.adoc @@ -142,10 +142,10 @@ Unfortunately, the Jest UI integration works only for npm script "test". But to If you want to **debug an integration test**, there is a temporary workaround necessary while you debug the test: - open `package.json` and look into section `scripts` -- switch `test-with-integrationtests` to `test` and rename former `test` script entry to something else - e.g. `test-without-integrationtests` +- remove 'test' entry + copy `test-with-integrationtests` entry and rename copied part to `test` (but please do not push this - otherwise build will fail on integration test!) -- restart your VSCode/VSCodium instance (if integration tests are not listed in test explorer) +- restart your VSCode/VSCodium instance (only necessary if integration tests are not listed in test explorer) - debug the parts, fix it etc. -- switch `test` script entry back to `test-with-integrationtests` and `test-without-integrationtests` to `test`. +- remove 'test' entry + copy `test-without-integrationtests` entry and rename copied part to `test` - if necessary push fixes/changes to remote... ==== \ No newline at end of file diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts index c1af048faf..7840cc01d4 100644 --- a/github-actions/scan/__test__/init-scan.test.ts +++ b/github-actions/scan/__test__/init-scan.test.ts @@ -7,9 +7,17 @@ import {createSecHubConfigJsonFile} from '../src/configuration-builder'; describe('initSecHubJson', function () { - it('returns parameter if configPath is set', function () { + it('throws error if configPath is set, but file does not exist', function () { /* prepare */ - const configPath = 'sechub.json'; + const configPath = 'not-existing-json.json'; + + /* execute + test */ + expect(() => initSecHubJson('runtime/sechub.json', configPath, [], [])).toThrow(Error); + }); + + it('returns parameter if configPath is set and file exists', function () { + /* prepare */ + const configPath = '__test__/test-resources/test-config.json'; /* execute */ const parameter = initSecHubJson('runtime/sechub.json', configPath, [], []); @@ -29,11 +37,11 @@ describe('initSecHubJson', function () { }); describe('initReportFormats', function () { - it('throws Error if no valid report formats found', function () { + it('throws error if no valid report formats found', function () { /* prepare */ const reportFormats = 'yaml,xml'; - /* execute & test */ + /* execute + test */ expect(() => initReportFormats(reportFormats)).toThrow(Error); }); diff --git a/github-actions/scan/__test__/integrationtest.test.ts b/github-actions/scan/__test__/integrationtest.test.ts index bd7566823e..a5f1c8b81d 100644 --- a/github-actions/scan/__test__/integrationtest.test.ts +++ b/github-actions/scan/__test__/integrationtest.test.ts @@ -1,17 +1,14 @@ // SPDX-License-Identifier: MIT -import * as launcher from '../src/launcher'; -import { IntegrationTestContext as IntegrationTestContext } from './integrationtest/testframework'; -import * as shell from 'shelljs'; -import { isDebug, debug, getInput } from '@actions/core'; -import { info } from '@actions/core'; -import { error } from '@actions/core'; -import { warning } from '@actions/core'; -import * as input from '../src/input'; -import { LaunchContext } from '../src/launcher'; import { create } from '@actions/artifact'; +import { debug, error, getInput, info, isDebug, warning } from '@actions/core'; +import * as shell from 'shelljs'; import { getWorkspaceDir } from '../src/fs-helper'; +import * as input from '../src/input'; import { getFieldFromJsonReport } from '../src/json-helper'; +import * as launcher from '../src/launcher'; +import { LaunchContext } from '../src/launcher'; +import { IntegrationTestContext } from './integrationtest/testframework'; jest.mock('@actions/core'); jest.mock('@actions/artifact'); @@ -103,6 +100,7 @@ describe('integrationtest codescan generated config', () => { /* test */ assertLastClientExitCode(launchPromise, 0); assertTrafficLight(launchPromise, 'GREEN'); + assertReportContains(launchPromise, 'result-green'); }); test('codescan yellow', function () { @@ -118,6 +116,7 @@ describe('integrationtest codescan generated config', () => { /* test */ assertLastClientExitCode(launchPromise, 0); assertTrafficLight(launchPromise, 'YELLOW'); + assertReportContains(launchPromise, 'result-yellow'); }); @@ -134,8 +133,47 @@ describe('integrationtest codescan generated config', () => { /* test */ assertLastClientExitCode(launchPromise, 1); // exit code 1, because RED assertTrafficLight(launchPromise, 'RED'); + assertReportContains(launchPromise, 'result-red'); + }); + +}); + + +describe('integrationtest non-generated config', () => { + test('config-path defined, but file not found', () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-3'); + mockedInputMap.set(input.PARAM_CONFIG_PATH, 'unknown/not-existing-config.json'); + + /* execute + test */ + launcher.launch().catch(error => console.log(`Error handled : ${error}`)); + + }); + + test('config-path defined, file available, web scan with red trafficlight', () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-4'); // we must set the project name here, even when we have a config! GitHub action needs this always. + + const pwd = shell.pwd(); + const configDir = `${pwd}/__test__/integrationtest/test-config`; + + mockedInputMap.set(input.PARAM_CONFIG_PATH, `${configDir}/sechub-config-webscan-project-4.json`); + + /* execute */ + const launchPromise = launcher.launch(); + + /* test */ + assertLastClientExitCode(launchPromise, 1); + assertTrafficLight(launchPromise, 'RED'); + assertReportContains(launchPromise, 'XSS attackable parameter output:

" + } + } + }, + "properties" : { + "attack" : "

" + } + } ], + "message" : { + "text" : "Cross-site Scripting (XSS) is an attack technique that involves echoing attacker-supplied code into a user's browser instance. A browser instance can be a standard web browser client, or a browser object embedded in a software product such as the browser within WinAmp, an RSS reader, or an email client. The code itself is usually written in HTML/JavaScript, but may also extend to VBScript, ActiveX, Java, Flash, or any other browser-supported technology.\nWhen an attacker gets a user's browser to execute his/her code, the code will run within the security context (or zone) of the hosting web site. With this level of privilege, the code has the ability to read, modify and transmit any sensitive data accessible by the browser. A Cross-site Scripted user could have his/her account hijacked (cookie theft), their browser redirected to another location, or possibly shown fraudulent content delivered by the web site they are visiting. Cross-site Scripting attacks essentially compromise the trust relationship between a user and the web site. Applications utilizing browser object instances which load content from the file system may execute code under the local machine zone allowing for system compromise.\n\nThere are three types of Cross-site Scripting attacks: non-persistent, persistent and DOM-based.\nNon-persistent attacks and DOM-based attacks require a user to either visit a specially crafted link laced with malicious code, or visit a malicious web page containing a web form, which when posted to the vulnerable site, will mount the attack. Using a malicious form will oftentimes take place when the vulnerable resource only accepts HTTP POST requests. In such a case, the form can be submitted automatically, without the victim's knowledge (e.g. by using JavaScript). Upon clicking on the malicious link or submitting the malicious form, the XSS payload will get echoed back and will get interpreted by the user's browser and execute. Another technique to send almost arbitrary requests (GET and POST) is by using an embedded client, such as Adobe Flash.\nPersistent attacks occur when the malicious code is submitted to a web site where it's stored for a period of time. Examples of an attacker's favorite targets often include message board posts, web mail messages, and web chat software. The unsuspecting user is not required to interact with any additional site/link (e.g. an attacker site or a malicious link sent via email), just simply view the web page containing the code." + }, + "ruleId" : "40012", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/greeting?name=%3C%2Fp%3E%3Cscript%3Ealert%281%29%3B%3C%2Fscript%3E%3Cp%3E", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Content-Length" : "0", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/hello", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:56:20 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\n Getting Started: Serving Web Content\n \n\n\n \n \n

XSS attackable parameter output:

!

\n\n" + }, + "noResponseReceived" : false + } + }, { + "level" : "warning", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "script-src 'self'" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: \nstyle-src, img-src, connects-src, frame-src, frame-ancestors, font-src, media-src, object-src, manifest-src, prefetch-src, form-action\n\nThe directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything." + }, + "ruleId" : "10055", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n \n Vulnerable web demo application\n \n \n

Attention! This web page has multiple failures inside and is only designed to test web scanners!

\n

But vulnerabilities are only available after login...

\n\n

Click here to see a XSS.

\n \n" + }, + "noResponseReceived" : false + } + }, { + "level" : "warning", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/greeting?name=Test1" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "script-src 'self'" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: \nstyle-src, img-src, connects-src, frame-src, frame-ancestors, font-src, media-src, object-src, manifest-src, prefetch-src, form-action\n\nThe directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything." + }, + "ruleId" : "10055", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/greeting?name=Test1", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/hello", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\n Getting Started: Serving Web Content\n \n\n\n \n \n

XSS attackable parameter output: Test1!

\n\n" + }, + "noResponseReceived" : false + } + }, { + "level" : "warning", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/hello" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "script-src 'self'" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: \nstyle-src, img-src, connects-src, frame-src, frame-ancestors, font-src, media-src, object-src, manifest-src, prefetch-src, form-action\n\nThe directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything." + }, + "ruleId" : "10055", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/hello", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n \n Hello World! Login protected with link to vulnerabilities\n \n \n

Hello !

\n\n

Get your vulnerable greeting here

\n\n
\n \n
\n \n" + }, + "noResponseReceived" : false + } + }, { + "level" : "warning", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/login?logout" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "script-src 'self'" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: \nstyle-src, img-src, connects-src, frame-src, frame-ancestors, font-src, media-src, object-src, manifest-src, prefetch-src, form-action\n\nThe directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything." + }, + "ruleId" : "10055", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/login?logout", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/logout", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=9C796A78F867C4E7F7DC8C61B1499343; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\nSimple vulnerable demo web application\n\n\n\t\n\t
You have been logged out.
\n\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t
\n\n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n \n Vulnerable web demo application\n \n \n

Attention! This web page has multiple failures inside and is only designed to test web scanners!

\n

But vulnerabilities are only available after login...

\n\n

Click here to see a XSS.

\n \n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/greeting?name=Test1" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/greeting?name=Test1", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/hello", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\n Getting Started: Serving Web Content\n \n\n\n \n \n

XSS attackable parameter output: Test1!

\n\n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/hello" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/hello", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n \n Hello World! Login protected with link to vulnerabilities\n \n \n

Hello !

\n\n

Get your vulnerable greeting here

\n\n
\n \n
\n \n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/login?logout" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/login?logout", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/logout", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=9C796A78F867C4E7F7DC8C61B1499343; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\nSimple vulnerable demo web application\n\n\n\t\n\t
You have been logged out.
\n\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t
\n\n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/robots.txt" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/robots.txt", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 404, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "application/json;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "{\"timestamp\":\"2021-11-11T09:55:59.836+0000\",\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/robots.txt\"}" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/sitemap.xml" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/sitemap.xml", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 404, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "application/json;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "{\"timestamp\":\"2021-11-11T09:55:59.781+0000\",\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/sitemap.xml\"}" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/login" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: locale" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "ruleId" : "10011", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/login", + "method" : "POST", + "headers" : { + "Cache-Control" : "no-cache", + "Content-Length" : "68", + "Content-Type" : "application/x-www-form-urlencoded", + "Cookie" : "JSESSIONID=9C796A78F867C4E7F7DC8C61B1499343; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/login?logout", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { + "binary" : "X2NzcmY9ZDg5YWQyNmQtMzA0OC00YWFhLThmZjYtM2VhMTk3OGVhODgyJnVzZXJuYW1lPVpBUCZwYXNzd29yZD1aQVA=" + } + }, + "webResponse" : { + "statusCode" : 405, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Allow" : "GET, HEAD", + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "application/json;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "locale=de; HttpOnly; SameSite=strict", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "{\"timestamp\":\"2021-11-11T09:55:59.876+0000\",\"status\":405,\"error\":\"Method Not Allowed\",\"message\":\"Request method 'POST' not supported\",\"path\":\"/login\"}" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/hello" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: JSESSIONID" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the SameSite attribute, which means that the cookie can be sent as a result of a 'cross-site' request. The SameSite attribute is an effective counter measure to cross-site request forgery, cross-site script inclusion, and timing attacks." + }, + "ruleId" : "10054", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/hello", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n \n Hello World! Login protected with link to vulnerabilities\n \n \n

Hello !

\n\n

Get your vulnerable greeting here

\n\n
\n \n
\n \n" + }, + "noResponseReceived" : false + } + }, { + "level" : "note", + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "https://127.0.0.1:8080/login?logout" + }, + "region" : { + "startLine" : 1, + "snippet" : { + "text" : "Set-Cookie: JSESSIONID" + } + } + }, + "properties" : { + "attack" : "" + } + } ], + "message" : { + "text" : "A cookie has been set without the SameSite attribute, which means that the cookie can be sent as a result of a 'cross-site' request. The SameSite attribute is an effective counter measure to cross-site request forgery, cross-site script inclusion, and timing attacks." + }, + "ruleId" : "10054", + "webRequest" : { + "protocol" : "HTTP", + "version" : "1.1", + "target" : "https://127.0.0.1:8080/login?logout", + "method" : "GET", + "headers" : { + "Cache-Control" : "no-cache", + "Cookie" : "JSESSIONID=38AA1F7A61982DF1073D7F43A3707798; locale=de", + "Host" : "127.0.0.1:8080", + "Pragma" : "no-cache", + "Referer" : "https://127.0.0.1:8080/logout", + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0" + }, + "body" : { } + }, + "webResponse" : { + "statusCode" : 200, + "reasonPhrase" : "", + "protocol" : "HTTP", + "version" : "1.1", + "headers" : { + "Cache-Control" : "no-cache, no-store, max-age=0, must-revalidate", + "Content-Language" : "en-US", + "Content-Security-Policy" : "script-src 'self'", + "Content-Type" : "text/html;charset=UTF-8", + "Date" : "Thu, 11 Nov 2021 09:55:59 GMT", + "Expires" : "0", + "Pragma" : "no-cache", + "Referrer-Policy" : "no-referrer", + "Set-Cookie" : "JSESSIONID=9C796A78F867C4E7F7DC8C61B1499343; Path=/; Secure; HttpOnly", + "Strict-Transport-Security" : "max-age=31536000 ; includeSubDomains", + "X-Content-Type-Options" : "nosniff", + "X-Frame-Options" : "DENY", + "X-XSS-Protection" : "1; mode=block" + }, + "body" : { + "text" : "\n\n\nSimple vulnerable demo web application\n\n\n\t\n\t
You have been logged out.
\n\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\n\t\t
\n\t
\n\n" + }, + "noResponseReceived" : false + } + } ], + "taxonomies" : [ { + "downloadUri" : "https://cwe.mitre.org/data/xml/cwec_v4.4.xml.zip", + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "informationUri" : "https://cwe.mitre.org/data/published/cwe_v4.4.pdf/", + "isComprehensive" : true, + "language" : "en", + "minimumRequiredLocalizedDataSemanticVersion" : "4.4", + "name" : "CWE", + "organization" : "MITRE", + "releaseDateUtc" : "2021-03-15", + "shortDescription" : { + "text" : "The MITRE Common Weakness Enumeration" + }, + "taxa" : [ { + "guid" : "ee0afde2-b609-3788-be35-11871b03e25f", + "helpUri" : "https://cwe.mitre.org/data/definitions/79.html", + "id" : "79" + }, { + "guid" : "fcacd315-2c69-3377-9f53-64346f599cfb", + "helpUri" : "https://cwe.mitre.org/data/definitions/614.html", + "id" : "614" + }, { + "guid" : "a844e996-9798-39fd-abea-676ee88a0df8", + "helpUri" : "https://cwe.mitre.org/data/definitions/693.html", + "id" : "693" + }, { + "guid" : "6f662138-e00a-3712-be6e-f046bddce76e", + "helpUri" : "https://cwe.mitre.org/data/definitions/1275.html", + "id" : "1275" + } ], + "version" : "4.4" + } ], + "tool" : { + "driver" : { + "guid" : "840570e4-2388-38c0-8afe-ed426f2f5199", + "informationUri" : "https://www.zaproxy.org/", + "name" : "OWASP ZAP", + "rules" : [ { + "id" : "10011", + "defaultConfiguration" : { + "level" : "note" + }, + "fullDescription" : { + "text" : "A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections." + }, + "name" : "Cookie Without Secure Flag", + "properties" : { + "references" : [ "https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/06-Session_Management_Testing/02-Testing_for_Cookies_Attributes.html" ], + "solution" : { + "text" : "Whenever a cookie contains sensitive information or is a session token, then it should always be passed using an encrypted channel. Ensure that the secure flag is set for cookies containing such sensitive information." + }, + "confidence" : "medium" + }, + "relationships" : [ { + "kinds" : [ "superset" ], + "target" : { + "guid" : "fcacd315-2c69-3377-9f53-64346f599cfb", + "id" : "614", + "toolComponent" : { + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "name" : "CWE" + } + } + } ], + "shortDescription" : { + "text" : "Cookie Without Secure Flag" + } + }, { + "id" : "10054", + "defaultConfiguration" : { + "level" : "note" + }, + "fullDescription" : { + "text" : "A cookie has been set without the SameSite attribute, which means that the cookie can be sent as a result of a 'cross-site' request. The SameSite attribute is an effective counter measure to cross-site request forgery, cross-site script inclusion, and timing attacks." + }, + "name" : "Cookie without SameSite Attribute", + "properties" : { + "references" : [ "https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site" ], + "solution" : { + "text" : "Ensure that the SameSite attribute is set to either 'lax' or ideally 'strict' for all cookies." + }, + "confidence" : "medium" + }, + "relationships" : [ { + "kinds" : [ "superset" ], + "target" : { + "guid" : "6f662138-e00a-3712-be6e-f046bddce76e", + "id" : "1275", + "toolComponent" : { + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "name" : "CWE" + } + } + } ], + "shortDescription" : { + "text" : "Cookie without SameSite Attribute" + } + }, { + "id" : "10055", + "defaultConfiguration" : { + "level" : "warning" + }, + "fullDescription" : { + "text" : "The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: \nstyle-src, img-src, connects-src, frame-src, frame-ancestors, font-src, media-src, object-src, manifest-src, prefetch-src, form-action\n\nThe directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything." + }, + "name" : "CSP: Wildcard Directive", + "properties" : { + "references" : [ "http://www.w3.org/TR/CSP2/", "http://www.w3.org/TR/CSP/", "http://caniuse.com/#search=content+security+policy", "http://content-security-policy.com/", "https://github.com/shapesecurity/salvation", "https://developers.google.com/web/fundamentals/security/csp#policy_applies_to_a_wide_variety_of_resources" ], + "solution" : { + "text" : "Ensure that your web server, application server, load balancer, etc. is properly configured to set the Content-Security-Policy header." + }, + "confidence" : "medium" + }, + "relationships" : [ { + "kinds" : [ "superset" ], + "target" : { + "guid" : "a844e996-9798-39fd-abea-676ee88a0df8", + "id" : "693", + "toolComponent" : { + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "name" : "CWE" + } + } + } ], + "shortDescription" : { + "text" : "CSP: Wildcard Directive" + } + }, { + "id" : "40012", + "defaultConfiguration" : { + "level" : "error" + }, + "fullDescription" : { + "text" : "Cross-site Scripting (XSS) is an attack technique that involves echoing attacker-supplied code into a user's browser instance. A browser instance can be a standard web browser client, or a browser object embedded in a software product such as the browser within WinAmp, an RSS reader, or an email client. The code itself is usually written in HTML/JavaScript, but may also extend to VBScript, ActiveX, Java, Flash, or any other browser-supported technology.\nWhen an attacker gets a user's browser to execute his/her code, the code will run within the security context (or zone) of the hosting web site. With this level of privilege, the code has the ability to read, modify and transmit any sensitive data accessible by the browser. A Cross-site Scripted user could have his/her account hijacked (cookie theft), their browser redirected to another location, or possibly shown fraudulent content delivered by the web site they are visiting. Cross-site Scripting attacks essentially compromise the trust relationship between a user and the web site. Applications utilizing browser object instances which load content from the file system may execute code under the local machine zone allowing for system compromise.\n\nThere are three types of Cross-site Scripting attacks: non-persistent, persistent and DOM-based.\nNon-persistent attacks and DOM-based attacks require a user to either visit a specially crafted link laced with malicious code, or visit a malicious web page containing a web form, which when posted to the vulnerable site, will mount the attack. Using a malicious form will oftentimes take place when the vulnerable resource only accepts HTTP POST requests. In such a case, the form can be submitted automatically, without the victim's knowledge (e.g. by using JavaScript). Upon clicking on the malicious link or submitting the malicious form, the XSS payload will get echoed back and will get interpreted by the user's browser and execute. Another technique to send almost arbitrary requests (GET and POST) is by using an embedded client, such as Adobe Flash.\nPersistent attacks occur when the malicious code is submitted to a web site where it's stored for a period of time. Examples of an attacker's favorite targets often include message board posts, web mail messages, and web chat software. The unsuspecting user is not required to interact with any additional site/link (e.g. an attacker site or a malicious link sent via email), just simply view the web page containing the code." + }, + "name" : "Cross Site Scripting (Reflected)", + "properties" : { + "references" : [ "http://projects.webappsec.org/Cross-Site-Scripting", "http://cwe.mitre.org/data/definitions/79.html" ], + "solution" : { + "text" : "Phase: Architecture and Design\nUse a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.\nExamples of libraries and frameworks that make it easier to generate properly encoded output include Microsoft's Anti-XSS library, the OWASP ESAPI Encoding module, and Apache Wicket.\n\nPhases: Implementation; Architecture and Design\nUnderstand the context in which your data will be used and the encoding that will be expected. This is especially important when transmitting data between different components, or when generating outputs that can contain multiple encodings at the same time, such as web pages or multi-part mail messages. Study all expected communication protocols and data representations to determine the required encoding strategies.\nFor any data that will be output to another web page, especially any data that was received from external inputs, use the appropriate encoding on all non-alphanumeric characters.\nConsult the XSS Prevention Cheat Sheet for more details on the types of encoding and escaping that are needed.\n\nPhase: Architecture and Design\nFor any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.\n\nIf available, use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated.\n\nPhase: Implementation\nFor every web page that is generated, use and specify a character encoding such as ISO-8859-1 or UTF-8. When an encoding is not specified, the web browser may choose a different encoding by guessing which encoding is actually being used by the web page. This can cause the web browser to treat certain sequences as special, opening up the client to subtle XSS attacks. See CWE-116 for more mitigations related to encoding/escaping.\n\nTo help mitigate XSS attacks against the user's session cookie, set the session cookie to be HttpOnly. In browsers that support the HttpOnly feature (such as more recent versions of Internet Explorer and Firefox), this attribute can prevent the user's session cookie from being accessible to malicious client-side scripts that use document.cookie. This is not a complete solution, since HttpOnly is not supported by all browsers. More importantly, XMLHTTPRequest and other powerful browser technologies provide read access to HTTP headers, including the Set-Cookie header in which the HttpOnly flag is set.\n\nAssume all input is malicious. Use an \"accept known good\" input validation strategy, i.e., use an allow list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. Do not rely exclusively on looking for malicious or malformed inputs (i.e., do not rely on a deny list). However, deny lists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.\n\nWhen performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, \"boat\" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if you are expecting colors such as \"red\" or \"blue.\"\n\nEnsure that you perform input validation at well-defined interfaces within the application. This will help protect the application even if a component is reused or moved elsewhere." + }, + "confidence" : "medium" + }, + "relationships" : [ { + "kinds" : [ "superset" ], + "target" : { + "guid" : "ee0afde2-b609-3788-be35-11871b03e25f", + "id" : "79", + "toolComponent" : { + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "name" : "CWE" + } + } + } ], + "shortDescription" : { + "text" : "Cross Site Scripting (Reflected)" + } + } ], + "semanticVersion" : "Dev Build", + "supportedTaxonomies" : [ { + "guid" : "6cd74e84-94e3-3d01-a45b-08ae89155abe", + "name" : "CWE" + } ], + "version" : "Dev Build" + } + } + } ], + "$schema" : "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version" : "2.1.0" + } \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh index e8732414a9..243937679f 100755 --- a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-green.sh @@ -2,4 +2,4 @@ # SPDX-License-Identifier: MIT echo "#PDS_INTTEST_PRODUCT_CODESCAN -info:result1" > "${PDS_JOB_RESULT_FILE}" +info:result-green" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh index 358cada8f0..7c43863236 100755 --- a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-red.sh @@ -2,4 +2,4 @@ # SPDX-License-Identifier: MIT echo "#PDS_INTTEST_PRODUCT_CODESCAN -high:result3" > "${PDS_JOB_RESULT_FILE}" +high:result-red" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh index 42a334221b..52f846b8b3 100755 --- a/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-codescan-demo-yellow.sh @@ -2,4 +2,4 @@ # SPDX-License-Identifier: MIT echo "#PDS_INTTEST_PRODUCT_CODESCAN -medium:result2" > "${PDS_JOB_RESULT_FILE}" +medium:result-yellow" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/integrationtest/test-scripts/pds-webscan-demo-red.sh b/github-actions/scan/__test__/integrationtest/test-scripts/pds-webscan-demo-red.sh new file mode 100755 index 0000000000..4e8e6b11a6 --- /dev/null +++ b/github-actions/scan/__test__/integrationtest/test-scripts/pds-webscan-demo-red.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +cat "__test__/integrationtest/test-product-output/example-owasp-zap-sarif-output-red.json" > "${PDS_JOB_RESULT_FILE}" diff --git a/github-actions/scan/__test__/test-resources/test-config.json b/github-actions/scan/__test__/test-resources/test-config.json new file mode 100644 index 0000000000..544b7b4ddd --- /dev/null +++ b/github-actions/scan/__test__/test-resources/test-config.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index ef8a2138dd..af5754a43e 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -13823,13 +13823,18 @@ function getValidFormatsFromInput(inputFormats) { return formats.filter((item) => availableFormats.includes(item)); } +// EXTERNAL MODULE: external "fs" +var external_fs_ = __nccwpck_require__(7147); ;// CONCATENATED MODULE: ./src/init-scan.ts // SPDX-License-Identifier: MIT + /** - * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. + * Returns the path to the sechub.json. If no custom config-path is defined, a config file wille be + * generated from the input parameters and this path will be returned. + * * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) * @param includeFolders list of folders to include to the scan * @param excludeFolders list of folders to exclude from the scan @@ -13840,7 +13845,12 @@ function initSecHubJson(secHubJsonFilePath, customSecHubConfigFilePath, includeF core.startGroup('Set config'); let configFilePath = customSecHubConfigFilePath; if (configFilePath) { - core.info(`Config-Path was found: ${customSecHubConfigFilePath}`); + if (external_fs_.existsSync(configFilePath)) { + core.info(`Config-Path was found: ${configFilePath}`); + } + else { + throw new Error(`Config-Path was defined, but no file exists at: ${configFilePath}`); + } } else { createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); @@ -13879,8 +13889,6 @@ function ensureJsonReportAtBeginning(reportFormats) { // EXTERNAL MODULE: ./node_modules/@actions/artifact/lib/artifact-client.js var artifact_client = __nccwpck_require__(2605); -// EXTERNAL MODULE: external "fs" -var external_fs_ = __nccwpck_require__(7147); ;// CONCATENATED MODULE: ./src/json-helper.ts /** @@ -14248,7 +14256,7 @@ const LAUNCHER_CONTEXT_DEFAULTS = { secHubReportJsonObject: undefined, }; /** - * Create launch context + * Creates the initial launch context * @returns launch context */ function createContext() { @@ -14267,12 +14275,12 @@ function createContext() { const includeFolders = (_a = gitHubInputData.includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); const excludeFolders = (_b = gitHubInputData.excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; - const configParameter = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); const reportFormats = initReportFormats(gitHubInputData.reportFormats); return { jobUUID: LAUNCHER_CONTEXT_DEFAULTS.jobUUID, secHubReportJsonObject: LAUNCHER_CONTEXT_DEFAULTS.secHubReportJsonObject, - configFileLocation: configParameter, + configFileLocation: configFileLocation, reportFormats: reportFormats, inputData: gitHubInputData, clientDownloadFolder: clientDownloadFolder, @@ -14317,7 +14325,7 @@ async function postScan(context) { main().catch(handleError); async function main() { - // Seperated launcher and main methd. + // Seperated launcher and main method. // Reason: launch mechanism would be loaded on imports // before we can handle mocking in integration tests! await launch(); diff --git a/github-actions/scan/package.json b/github-actions/scan/package.json index 7d7659903f..924f4d476a 100644 --- a/github-actions/scan/package.json +++ b/github-actions/scan/package.json @@ -9,7 +9,9 @@ "lint": "eslint src", "prettier": "npx prettier --write src", "test-with-integrationtests": "npx jest", + "test-without-integrationtests": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", "test": "npx jest --testPathIgnorePatterns='integrationtest.test.ts'", + "testX": "npx jest", "integration-test": "jest --runInBand --testPathPattern='integrationtest.test.ts'" }, "license": "MIT", diff --git a/github-actions/scan/src/fs-helper.ts b/github-actions/scan/src/fs-helper.ts index 435cbdb4b7..c668b2af27 100644 --- a/github-actions/scan/src/fs-helper.ts +++ b/github-actions/scan/src/fs-helper.ts @@ -36,7 +36,6 @@ export function getWorkspaceDir(): string { */ export function ensuredWorkspaceFolder() { const ensuredWorkspaceFolder= path.dirname(getWorkspaceDir()); - // TODO check folder exists or fal return ensuredWorkspaceFolder; } diff --git a/github-actions/scan/src/init-scan.ts b/github-actions/scan/src/init-scan.ts index 6d3e4502f9..dd1ec2ff77 100644 --- a/github-actions/scan/src/init-scan.ts +++ b/github-actions/scan/src/init-scan.ts @@ -3,9 +3,12 @@ import * as core from '@actions/core'; import { createSecHubConfigJsonFile as createSecHubConfigJsonFile } from './configuration-builder'; import { getValidFormatsFromInput } from './report-formats'; +import * as fs from 'fs'; /** - * Returns the parameter to the sechub.json or creates it from the input parameters if configPath is not set. + * Returns the path to the sechub.json. If no custom config-path is defined, a config file wille be + * generated from the input parameters and this path will be returned. + * * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) * @param includeFolders list of folders to include to the scan * @param excludeFolders list of folders to exclude from the scan @@ -17,8 +20,13 @@ export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFil let configFilePath = customSecHubConfigFilePath; if (configFilePath) { - core.info(`Config-Path was found: ${customSecHubConfigFilePath}`); - }else{ + if (fs.existsSync(configFilePath)) { + core.info(`Config-Path was found: ${configFilePath}`); + } else { + throw new Error(`Config-Path was defined, but no file exists at: ${configFilePath}`); + } + + } else { createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); configFilePath = secHubJsonFilePath; } @@ -27,7 +35,6 @@ export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFil return configFilePath; } - /** * Initializes the report formats and ensures there is at least one valid report format selected. * @param reportFormats formats in which the report should be downloaded diff --git a/github-actions/scan/src/launcher.ts b/github-actions/scan/src/launcher.ts index 66c217a362..280ce760e7 100644 --- a/github-actions/scan/src/launcher.ts +++ b/github-actions/scan/src/launcher.ts @@ -64,7 +64,7 @@ export const LAUNCHER_CONTEXT_DEFAULTS: LaunchContext = { /** - * Create launch context + * Creates the initial launch context * @returns launch context */ function createContext(): LaunchContext { @@ -89,7 +89,7 @@ function createContext(): LaunchContext { const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; - const configParameter = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); const reportFormats = initReportFormats(gitHubInputData.reportFormats); @@ -97,7 +97,7 @@ function createContext(): LaunchContext { jobUUID: LAUNCHER_CONTEXT_DEFAULTS.jobUUID, secHubReportJsonObject: LAUNCHER_CONTEXT_DEFAULTS.secHubReportJsonObject, - configFileLocation: configParameter, + configFileLocation: configFileLocation, reportFormats: reportFormats, inputData: gitHubInputData, clientDownloadFolder: clientDownloadFolder, diff --git a/github-actions/scan/src/main.ts b/github-actions/scan/src/main.ts index bcfbc6813f..f4cb84aa3f 100644 --- a/github-actions/scan/src/main.ts +++ b/github-actions/scan/src/main.ts @@ -6,7 +6,7 @@ import { handleError } from './action-helper'; main().catch(handleError); async function main(): Promise { - // Seperated launcher and main methd. + // Seperated launcher and main method. // Reason: launch mechanism would be loaded on imports // before we can handle mocking in integration tests! await launch(); diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh index b1c6a7ee87..ebd7ffddda 100755 --- a/sechub-developertools/scripts/sdc.sh +++ b/sechub-developertools/scripts/sdc.sh @@ -2,6 +2,8 @@ # SPDX-License-Identifier: MIT set -e +trap handleExitCodes EXIT + lastCommandHandled="" RED='\033[0;31m' @@ -13,6 +15,12 @@ PURPLE='\033[0;35m' NC='\033[0m' # No Color +# Define global variables for GitHub action apts +gha_sechub_server_version=1.7.0 +gha_sechub_server_port=8443 +gha_pds_version=1.4.0 +gha_pds_port=8444 + function startJob (){ echo -e "${BROWN}---------------------------------------------------${NC}" @@ -43,21 +51,27 @@ function showHelp () { echo "Usage: Usage sdc" echo " Option s: " echo " -f, --format-all : format all source code files" + echo "" echo " -b, --build-full : full build" echo " -bpt, --build-pds-tools : build pds tools" - echo " -bgh, --build-github-action : build github action (node js)" echo " -d, --document-full : full document build" + echo " -gj, --generate-java-api : generates parts for java api" + echo "" echo " -u, --unit-tests : execute all unit tests" - echo " -i, --integrationtest-all : execute all integration tests" + echo " -i, --integrationtest-all : execute all integration tests (java)" echo " -ii, --integrationtest-integration : execute integration tests from sechub-integrationtest only" echo " -is, --integrationtest-systemtest : execute integration tests from sechub-systemtest only" echo " -r, --report-combined-all : create combined report for all" + echo "" echo " -c, --clean-all : clean all" echo " -ct, --clean-all-tests : clean all test output" echo " -cu, --clean-unit-tests : clean all unit test output" echo " -ci, --clean-integrationtests : clean all integrationtest output" echo " -si, --stop-inttest-server : stop running integration test servers (SecHub, PDS)" - echo " -gj, --generate-java-api : generates parts for java api" + echo "" + echo " -pigh,--prepare-integrationtest-gh-action : prepare integration test data for github actions ((re)start SecHub, PDS and init data)" + echo " -igh, --integrationtest-github-action : execute integration tests for github action only (nodejs, -pigh initial necessary)" + echo " -bgh, --build-github-action : full build of github action with integration tests (prepare etc. is all done automatically)" echo "" echo " -syg, --start-systemtest-sanity-check-gosec : start systemtest 'sanity-check' for gosec with local build pds tools (0.0.0)" echo "" @@ -65,6 +79,50 @@ function showHelp () { } +function prepareGitHubActionIntegrationTest(){ + # Set working directory (to default) + cd $SECHUB_ROOT_DIR + cd ./github-actions/scan + + startTask "Setup integration test data" + echo "Version and port variables are globally defined" + + # Set working directory + cd ./__test__/integrationtest/ + + # next lines only for our local build: we stop always former running integration test servers (to call it multiple times) + specialTask "Stop former running test servers" + ./05-stop.sh $gha_sechub_server_port $gha_pds_port + + # Start integration test servers + startTask "Start integration test servers" + ./01-start.sh $gha_sechub_server_version $gha_sechub_server_port $gha_pds_version $gha_pds_port + + # Init integration test data + startTask "Init integration test data" + ./03-init_sechub_data.sh $gha_sechub_server_port $gha_pds_port +} + +function runGitHubActionIntegrationTests(){ + # Set working directory (to default) + cd $SECHUB_ROOT_DIR + cd ./github-actions/scan + + # Run integration tests + startTask "Run integration tests" + npm run integration-test +} + +function handleExitCodes(){ + lastExitCode=$? + + if [[ "$lastExitCode" = "0" ]]; then + echo -e "${LIGHT_GREEN}SUCCESSFUL${NC}" + else + echo -e "${RED}FAILED${NC} - exit code: $lastExitCode" + fi +} + SCRIPT_DIR="$(dirname -- "$0")" cd ${SCRIPT_DIR} cd .. @@ -134,6 +192,14 @@ do GITHUB_ACTION_BUILD="YES" shift # past argument ;; + -pigh|--prepare-integrationtest-gh-action) + GITHUB_ACTION_PREPARE_INTEGRATIONTEST="YES" + shift # past argument + ;; + -igh|--integrationtest-github-action) + GITHUB_ACTION_START_INTEGRATIONTEST="YES" + shift # past argument + ;; -d|--document-full) DOCUMENT_FULL="YES" shift # past argument @@ -298,6 +364,20 @@ if [[ "$START_SYSTEMTEST_SANITYCHECK_GOSEC" = "YES" ]]; then cd $SECHUB_ROOT_DIR fi +if [[ "$GITHUB_ACTION_PREPARE_INTEGRATIONTEST" = "YES" ]]; then + startJob "Prepare integration test situation for GitHub action" + + prepareGitHubActionIntegrationTest + +fi + +if [[ "$GITHUB_ACTION_START_INTEGRATIONTEST" = "YES" ]]; then + startJob "Start integration tests for GitHub action" + + runGitHubActionIntegrationTests + +fi + # Builds github action ("scan") like done in workflow, means the integration tests are executed as well) # We do here the same steps as done in 'github-action-scan.yml' if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then @@ -305,8 +385,9 @@ if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then ### Build GitHub action "scan" ### -------------------------- startJob "Build GitHub action 'scan'" - - # Set working directory (to default) + + prepareGitHubActionIntegrationTest + cd $SECHUB_ROOT_DIR cd ./github-actions/scan @@ -322,41 +403,11 @@ if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then startTask "Run unit tests" npm test - startTask "Setup integration test data" - # Define variables - sechub_server_version=1.7.0 - sechub_server_port=8443 - pds_version=1.4.0 - pds_port=8444 - echo "Version and port variables are now defined" - - # Set working directory - cd ./__test__/integrationtest/ - - # next lines only for our local build: we stop always former running integration test servers (to call it multiple times) - specialTask "Stop former running test servers" - ./05-stop.sh $sechub_server_port $pds_port - - # Start integration test servers - startTask "Start integration test servers" - ./01-start.sh $sechub_server_version $sechub_server_port $pds_version $pds_port - - # Init integration test data - startTask "Init integration test data" - ./03-init_sechub_data.sh $sechub_server_port $pds_port - - - # Set working directory (to default) - cd $SECHUB_ROOT_DIR - cd ./github-actions/scan - - # Run integration tests - startTask "Run integration tests" - npm run integration-test + runGitHubActionIntegrationTests # Cleanup integration tests startTask "Cleanup integration tests" - ./05-stop.sh $sechub_server_port $pds_port + ./05-stop.sh $gha_sechub_server_port $gha_pds_port fi From 0122beafede00c1135cd6feeca7f15a8df224779 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Tue, 19 Mar 2024 09:46:42 +0100 Subject: [PATCH 09/30] Prepare for configuration model change #2441 - build is green --- .../__test__/configuration-builder.test.ts | 28 +++++++++-- .../scan/__test__/init-scan.test.ts | 11 +++-- github-actions/scan/dist/index.js | 48 +++++++++++-------- .../scan/src/configuration-builder.ts | 32 ++++++++----- github-actions/scan/src/init-scan.ts | 9 ++-- github-actions/scan/src/launcher.ts | 10 ++-- sechub-developertools/scripts/sdc.sh | 25 ++++++++++ 7 files changed, 113 insertions(+), 50 deletions(-) diff --git a/github-actions/scan/__test__/configuration-builder.test.ts b/github-actions/scan/__test__/configuration-builder.test.ts index 461a068b51..4dc0ed80af 100644 --- a/github-actions/scan/__test__/configuration-builder.test.ts +++ b/github-actions/scan/__test__/configuration-builder.test.ts @@ -1,15 +1,37 @@ // SPDX-License-Identifier: MIT import * as configBuilder from '../src/configuration-builder'; +import { SecHubConfigurationModelBuilderData } from '../src/configuration-builder'; jest.mock('@actions/core'); -describe('conifguration-builder', function() { - it('createSecHubConfigModel creates with null always a model with api version 1.0.0', function () { +describe('configuration-builder', function() { + test('null parameters - a model is created with api version 1.0.0', function () { /* execute */ - const model= configBuilder.createSecHubConfigurationModel(null,null); + const data = new SecHubConfigurationModelBuilderData(); + const model= configBuilder.createSecHubConfigurationModel(data); /* test */ expect(model.apiVersion).toEqual('1.0'); }); + test('codescan green', () => { + + /* prepare */ + const data = new SecHubConfigurationModelBuilderData(); + data.includeFolders= ['folder1']; + + const model= configBuilder.createSecHubConfigurationModel(data); + + /* execute */ + + /* test */ + const json = JSON.stringify(model); + + console.log('json='+json); + expect(model.apiVersion).toEqual('1.0'); + expect(model.codeScan); + + + }); + }); \ No newline at end of file diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts index 7840cc01d4..ef057777ed 100644 --- a/github-actions/scan/__test__/init-scan.test.ts +++ b/github-actions/scan/__test__/init-scan.test.ts @@ -3,24 +3,26 @@ import {initReportFormats, initSecHubJson} from '../src/init-scan'; jest.mock('./../src/configuration-builder'); -import {createSecHubConfigJsonFile} from '../src/configuration-builder'; +import {SecHubConfigurationModelBuilderData, createSecHubConfigJsonFile} from '../src/configuration-builder'; describe('initSecHubJson', function () { it('throws error if configPath is set, but file does not exist', function () { /* prepare */ const configPath = 'not-existing-json.json'; + const builderData = new SecHubConfigurationModelBuilderData(); /* execute + test */ - expect(() => initSecHubJson('runtime/sechub.json', configPath, [], [])).toThrow(Error); + expect(() => initSecHubJson('runtime/sechub.json', configPath, builderData)).toThrow(Error); }); it('returns parameter if configPath is set and file exists', function () { /* prepare */ const configPath = '__test__/test-resources/test-config.json'; + const builderData = new SecHubConfigurationModelBuilderData(); /* execute */ - const parameter = initSecHubJson('runtime/sechub.json', configPath, [], []); + const parameter = initSecHubJson('runtime/sechub.json', configPath, builderData); /* test */ expect(parameter).toContain(configPath); @@ -28,7 +30,8 @@ describe('initSecHubJson', function () { it('creates sechub.json if configPath is not set', function () { /* execute */ - const parameter = initSecHubJson('runtime/sechub.json','', [], []); + const builderData = new SecHubConfigurationModelBuilderData(); + const parameter = initSecHubJson('runtime/sechub.json','', builderData); /* test */ expect(parameter).toEqual('runtime/sechub.json'); diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index af5754a43e..e5779abc36 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -13718,7 +13718,6 @@ function getWorkspaceDir() { */ function ensuredWorkspaceFolder() { const ensuredWorkspaceFolder = path.dirname(getWorkspaceDir()); - // TODO check folder exists or fal return ensuredWorkspaceFolder; } /** @@ -13774,13 +13773,19 @@ function shellExecAsync(command) { * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -function createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders) { +function createSecHubConfigJsonFile(secHubJsonFilePath, data) { core.info('Config-Path was not found. Config will be created at ' + secHubJsonFilePath); - const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); + const secHubJson = createSecHubConfigurationModel(data); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); } +class SecHubConfigurationModelBuilderData { + constructor() { + this.includeFolders = []; + this.excludeFolders = []; + } +} /** * Creates a sechub configuration model object for given user input values. * @@ -13789,23 +13794,23 @@ function createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeF * * @returns model */ -function createSecHubConfigurationModel(includeFolders, excludeFolders) { - const sechubJson = { +function createSecHubConfigurationModel(data) { + const model = { 'apiVersion': '1.0' }; - if (sechubJson.codeScan == null) { - sechubJson.codeScan = {}; + if (model.codeScan == null) { + model.codeScan = {}; } - if (includeFolders) { - if (sechubJson.codeScan.fileSystem == null) { - sechubJson.codeScan.fileSystem = {}; + if (data.includeFolders) { + if (model.codeScan.fileSystem == null) { + model.codeScan.fileSystem = {}; } - sechubJson.codeScan.fileSystem.folders = includeFolders; + model.codeScan.fileSystem.folders = data.includeFolders; } - if (excludeFolders) { - sechubJson.codeScan.excludes = excludeFolders; + if (data.excludeFolders) { + model.codeScan.excludes = data.excludeFolders; } - return sechubJson; + return model; } ;// CONCATENATED MODULE: ./src/report-formats.ts @@ -13836,12 +13841,11 @@ var external_fs_ = __nccwpck_require__(7147); * generated from the input parameters and this path will be returned. * * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) - * @param includeFolders list of folders to include to the scan - * @param excludeFolders list of folders to exclude from the scan + * @param builderData contains builder data which is used when no custom sechub configuration file is defined by user * * @returns resulting configuration file path */ -function initSecHubJson(secHubJsonFilePath, customSecHubConfigFilePath, includeFolders, excludeFolders) { +function initSecHubJson(secHubJsonFilePath, customSecHubConfigFilePath, builderData) { core.startGroup('Set config'); let configFilePath = customSecHubConfigFilePath; if (configFilePath) { @@ -13853,7 +13857,7 @@ function initSecHubJson(secHubJsonFilePath, customSecHubConfigFilePath, includeF } } else { - createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); + createSecHubConfigJsonFile(secHubJsonFilePath, builderData); configFilePath = secHubJsonFilePath; } core.endGroup(); @@ -14232,6 +14236,7 @@ function downloadClientRelease(context) { + /** * Starts the launch process * @returns launch context @@ -14272,10 +14277,11 @@ function createContext() { const workspaceFolder = `${getWorkspaceDir()}`; const clientDownloadFolder = `${workspaceFolder}/.sechub-gha/client/${clientVersionSubFolder}`; const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; - const includeFolders = (_a = gitHubInputData.includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); - const excludeFolders = (_b = gitHubInputData.excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; - const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders = (_a = gitHubInputData.includeFolders) === null || _a === void 0 ? void 0 : _a.split(','); + builderData.excludeFolders = (_b = gitHubInputData.excludeFolders) === null || _b === void 0 ? void 0 : _b.split(','); + const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, builderData); const reportFormats = initReportFormats(gitHubInputData.reportFormats); return { jobUUID: LAUNCHER_CONTEXT_DEFAULTS.jobUUID, diff --git a/github-actions/scan/src/configuration-builder.ts b/github-actions/scan/src/configuration-builder.ts index fb9511142d..f2a2643405 100644 --- a/github-actions/scan/src/configuration-builder.ts +++ b/github-actions/scan/src/configuration-builder.ts @@ -10,15 +10,21 @@ import { SecHubConfigurationModel } from './configuration-model'; * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -export function createSecHubConfigJsonFile(secHubJsonFilePath:string, includeFolders: string[] | null, excludeFolders: string[] | null) { +export function createSecHubConfigJsonFile(secHubJsonFilePath:string, data: SecHubConfigurationModelBuilderData) { core.info('Config-Path was not found. Config will be created at '+ secHubJsonFilePath); - const secHubJson = createSecHubConfigurationModel(includeFolders, excludeFolders); + const secHubJson = createSecHubConfigurationModel(data); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); } +export class SecHubConfigurationModelBuilderData{ + + includeFolders: string[] = []; + excludeFolders: string[] = []; +} + /** * Creates a sechub configuration model object for given user input values. * @@ -27,27 +33,27 @@ export function createSecHubConfigJsonFile(secHubJsonFilePath:string, includeFol * * @returns model */ -export function createSecHubConfigurationModel(includeFolders: string[] | null, excludeFolders: string[] | null): SecHubConfigurationModel { - const sechubJson: SecHubConfigurationModel = { +export function createSecHubConfigurationModel(data: SecHubConfigurationModelBuilderData): SecHubConfigurationModel { + const model: SecHubConfigurationModel = { 'apiVersion' : '1.0' }; - if (sechubJson.codeScan==null){ - sechubJson.codeScan={ + if (model.codeScan==null){ + model.codeScan={ }; } - if (includeFolders) { + if (data.includeFolders) { - if (sechubJson.codeScan.fileSystem==null){ - sechubJson.codeScan.fileSystem={ + if (model.codeScan.fileSystem==null){ + model.codeScan.fileSystem={ }; } - sechubJson.codeScan.fileSystem.folders = includeFolders; + model.codeScan.fileSystem.folders = data.includeFolders; } - if (excludeFolders) { - sechubJson.codeScan.excludes = excludeFolders; + if (data.excludeFolders) { + model.codeScan.excludes = data.excludeFolders; } - return sechubJson; + return model; } diff --git a/github-actions/scan/src/init-scan.ts b/github-actions/scan/src/init-scan.ts index dd1ec2ff77..9f4130cd36 100644 --- a/github-actions/scan/src/init-scan.ts +++ b/github-actions/scan/src/init-scan.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT import * as core from '@actions/core'; -import { createSecHubConfigJsonFile as createSecHubConfigJsonFile } from './configuration-builder'; +import { SecHubConfigurationModelBuilderData, createSecHubConfigJsonFile as createSecHubConfigJsonFile } from './configuration-builder'; import { getValidFormatsFromInput } from './report-formats'; import * as fs from 'fs'; @@ -10,12 +10,11 @@ import * as fs from 'fs'; * generated from the input parameters and this path will be returned. * * @param customSecHubConfigFilePath Path to the custom sechub.json (if defined) - * @param includeFolders list of folders to include to the scan - * @param excludeFolders list of folders to exclude from the scan + * @param builderData contains builder data which is used when no custom sechub configuration file is defined by user * * @returns resulting configuration file path */ -export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFilePath: string, includeFolders: string[], excludeFolders: string[]): string | null { +export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFilePath: string, builderData: SecHubConfigurationModelBuilderData): string | null { core.startGroup('Set config'); let configFilePath = customSecHubConfigFilePath; @@ -27,7 +26,7 @@ export function initSecHubJson(secHubJsonFilePath: string, customSecHubConfigFil } } else { - createSecHubConfigJsonFile(secHubJsonFilePath, includeFolders, excludeFolders); + createSecHubConfigJsonFile(secHubJsonFilePath, builderData); configFilePath = secHubJsonFilePath; } core.endGroup(); diff --git a/github-actions/scan/src/launcher.ts b/github-actions/scan/src/launcher.ts index 280ce760e7..7fe6bb6f53 100644 --- a/github-actions/scan/src/launcher.ts +++ b/github-actions/scan/src/launcher.ts @@ -9,6 +9,7 @@ import { collectReportData, reportOutputs, uploadArtifact } from './post-scan'; import { GitHubInputData, resolveGitHubInputData, INPUT_DATA_DEFAULTS } from './input'; import { initEnvironmentVariables } from './environment'; import { downloadClientRelease } from './client-download'; +import { SecHubConfigurationModelBuilderData } from './configuration-builder'; /** * Starts the launch process @@ -84,12 +85,13 @@ function createContext(): LaunchContext { const clientDownloadFolder = `${workspaceFolder}/.sechub-gha/client/${clientVersionSubFolder}`; const clientExecutablePath = `${clientDownloadFolder}/platform/linux-386/sechub`; - const includeFolders = gitHubInputData.includeFolders?.split(','); - const excludeFolders = gitHubInputData.excludeFolders?.split(','); - const generatedSecHubJsonFilePath = `${workspaceFolder}/sechub.json`; - const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, includeFolders, excludeFolders); + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders = gitHubInputData.includeFolders?.split(','); + builderData.excludeFolders = gitHubInputData.excludeFolders?.split(','); + + const configFileLocation = initSecHubJson(generatedSecHubJsonFilePath, gitHubInputData.configPath, builderData); const reportFormats = initReportFormats(gitHubInputData.reportFormats); diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh index ebd7ffddda..71c093a449 100755 --- a/sechub-developertools/scripts/sdc.sh +++ b/sechub-developertools/scripts/sdc.sh @@ -67,6 +67,8 @@ function showHelp () { echo " -ct, --clean-all-tests : clean all test output" echo " -cu, --clean-unit-tests : clean all unit test output" echo " -ci, --clean-integrationtests : clean all integrationtest output" + echo " -cr, --clean-reports : clean all reports" + echo "" echo " -si, --stop-inttest-server : stop running integration test servers (SecHub, PDS)" echo "" echo " -pigh,--prepare-integrationtest-gh-action : prepare integration test data for github actions ((re)start SecHub, PDS and init data)" @@ -180,6 +182,10 @@ do CLEAN_INTEGRATIONTEST="YES" shift # past argument ;; + -cr|--clean-reports) + CLEAN_REPORTS="YES" + shift # past argument + ;; -b|--build-full) FULL_BUILD="YES" shift # past argument @@ -246,6 +252,10 @@ if [[ "$HELP" = "YES" ]]; then exit 0 fi +function cleanOldReportData() { + rm ./sechub_report_*.json -f +} + CMD_EXEC_ALL_INTEGRATIONTESTS="./gradlew :sechub-integrationtest:startIntegrationTestInstances :sechub-systemtest:integrationtest :sechub-integrationtest:integrationtest :sechub-integrationtest:stopIntegrationTestInstances -Dsechub.build.stage=all --console=plain" CMD_CREATE_COMBINED_REPORT="./gradlew createCombinedTestReport -Dsechub.build.stage=all" @@ -258,7 +268,11 @@ if [[ "$STOP_SERVERS" = "YES" ]]; then fi if [[ "$CLEAN_ALL" = "YES" ]]; then startJob "Clean all" + step "Clean all gradle parts" ./gradlew clean -Dsechub.build.stage=all --console=plain + + step "Clean old report data" + cleanOldReportData fi if [[ "$CLEAN_ALL_TESTS" = "YES" ]]; then startJob "Clean all tests" @@ -271,6 +285,14 @@ fi if [[ "$CLEAN_INTEGRATIONTEST" = "YES" ]]; then startJob "Clean all integration tests" ./gradlew cleanIntegrationtest -Dsechub.build.stage=all --console=plain + + step "Clean old report data" + cleanOldReportData +fi + +if [[ "$CLEAN_REPORTS" = "YES" ]]; then + startJob "Clean all reports" + cleanOldReportData fi if [[ "$FORMAT_CODE_ALL" = "YES" ]]; then @@ -407,6 +429,9 @@ if [[ "$GITHUB_ACTION_BUILD" = "YES" ]]; then # Cleanup integration tests startTask "Cleanup integration tests" + cd $SECHUB_ROOT_DIR + cd ./github-actions/scan + cd ./__test__/integrationtest/ ./05-stop.sh $gha_sechub_server_port $gha_pds_port fi From 8eb0cd93b28f17dd78129c39c831d630392ccc64 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Tue, 19 Mar 2024 15:00:29 +0100 Subject: [PATCH 10/30] Configuration model now supports secret, license and codescan #2441 --- .../__test__/configuration-builder.test.ts | 252 +++++++++++++++++- .../scan/src/configuration-builder.ts | 72 +++-- .../scan/src/configuration-model.ts | 70 ++++- 3 files changed, 353 insertions(+), 41 deletions(-) diff --git a/github-actions/scan/__test__/configuration-builder.test.ts b/github-actions/scan/__test__/configuration-builder.test.ts index 4dc0ed80af..bd995677fb 100644 --- a/github-actions/scan/__test__/configuration-builder.test.ts +++ b/github-actions/scan/__test__/configuration-builder.test.ts @@ -1,37 +1,271 @@ // SPDX-License-Identifier: MIT import * as configBuilder from '../src/configuration-builder'; +import { SecHubConfigurationModel, ContentType, ScanType } from '../src/configuration-model'; import { SecHubConfigurationModelBuilderData } from '../src/configuration-builder'; + jest.mock('@actions/core'); + +function dumpModel(model: SecHubConfigurationModel){ + const json = JSON.stringify(model, null, 2); // pretty printed output + + console.log('json='+json); +} + describe('configuration-builder', function() { test('null parameters - a model is created with api version 1.0.0', function () { /* execute */ - const data = new SecHubConfigurationModelBuilderData(); - const model= configBuilder.createSecHubConfigurationModel(data); + const builderData = new SecHubConfigurationModelBuilderData(); + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + expect(model.apiVersion).toEqual('1.0'); + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + }); + + test('codescan generated per default - source,one folder defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); /* test */ + dumpModel(model); + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(1); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + }); - test('codescan green', () => { + test('codescan generated per default - source, two folders defined', () => { /* prepare */ - const data = new SecHubConfigurationModelBuilderData(); - data.includeFolders= ['folder1']; + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + expect(firstSource?.excludes?.length).toEqual(0); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + + }); + + test('codescan generated per default - source, two folders defined, one excluded', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.excludeFolders= ['folder3']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(firstSource?.excludes?.length).toEqual(1); + expect(firstSource?.excludes?.[0]).toEqual('folder3'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); - const model= configBuilder.createSecHubConfigurationModel(data); + }); + + test('codescan generated per default - binaries, two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.contentType=ContentType.BINARIES; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeUndefined(); + expect(model.data.binaries).toBeDefined(); + + expect(model.data.binaries?.length).toEqual(1); + + const firstBinary = model.data.binaries?.[0]; + expect(firstBinary?.fileSystem.folders?.length).toEqual(2); + expect(firstBinary?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstBinary?.fileSystem.folders?.[1]).toEqual('folder2'); + expect(firstBinary?.excludes?.length).toEqual(0); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + }); + + test('codescan and license scan - two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.scanTypes=[ScanType.CODE_SCAN,ScanType.LICENSE_SCAN]; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.licenseScan).toBeDefined(); + expect(model.licenseScan?.use.length).toEqual(1); + expect(model.licenseScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.secretScan).toBeUndefined(); + + }); + test('codescan and secret scan - two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.scanTypes=[ScanType.CODE_SCAN,ScanType.SECRET_SCAN]; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeDefined(); + expect(model.secretScan?.use.length).toEqual(1); + expect(model.secretScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.licenseScan).toBeUndefined(); + + }); + test('secret scan standalone - source, one folder defined, one excluded', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1']; + builderData.excludeFolders= ['folderX']; + builderData.scanTypes=[ScanType.SECRET_SCAN]; /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); /* test */ - const json = JSON.stringify(model); + dumpModel(model); - console.log('json='+json); expect(model.apiVersion).toEqual('1.0'); - expect(model.codeScan); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(1); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.excludes?.length).toEqual(1); + expect(firstSource?.excludes?.[0]).toEqual('folderX'); + expect(model.codeScan).toBeUndefined(); + + expect(model.secretScan).toBeDefined(); + expect(model.secretScan?.use.length).toEqual(1); + expect(model.secretScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.licenseScan).toBeUndefined(); + }); }); \ No newline at end of file diff --git a/github-actions/scan/src/configuration-builder.ts b/github-actions/scan/src/configuration-builder.ts index f2a2643405..aaff35da68 100644 --- a/github-actions/scan/src/configuration-builder.ts +++ b/github-actions/scan/src/configuration-builder.ts @@ -2,7 +2,8 @@ import * as core from '@actions/core'; import * as shell from 'shelljs'; -import { SecHubConfigurationModel } from './configuration-model'; +import { ScanType, ContentType, SecHubConfigurationModel } from './configuration-model'; +import * as cm from './configuration-model'; /** * Creates the sechub.json configuration file with the given user input values. @@ -10,8 +11,8 @@ import { SecHubConfigurationModel } from './configuration-model'; * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -export function createSecHubConfigJsonFile(secHubJsonFilePath:string, data: SecHubConfigurationModelBuilderData) { - core.info('Config-Path was not found. Config will be created at '+ secHubJsonFilePath); +export function createSecHubConfigJsonFile(secHubJsonFilePath: string, data: SecHubConfigurationModelBuilderData) { + core.info('Config-Path was not found. Config will be created at ' + secHubJsonFilePath); const secHubJson = createSecHubConfigurationModel(data); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); @@ -19,10 +20,13 @@ export function createSecHubConfigJsonFile(secHubJsonFilePath:string, data: SecH shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); } -export class SecHubConfigurationModelBuilderData{ +export class SecHubConfigurationModelBuilderData { includeFolders: string[] = []; excludeFolders: string[] = []; + + contentType: ContentType = ContentType.SOURCE; // per default source + scanTypes: ScanType[] = [ScanType.CODE_SCAN]; // per default only code scan } /** @@ -33,27 +37,51 @@ export class SecHubConfigurationModelBuilderData{ * * @returns model */ -export function createSecHubConfigurationModel(data: SecHubConfigurationModelBuilderData): SecHubConfigurationModel { - const model: SecHubConfigurationModel = { - 'apiVersion' : '1.0' - }; - - if (model.codeScan==null){ - model.codeScan={ - }; - } - if (data.includeFolders) { +export function createSecHubConfigurationModel(builderData: SecHubConfigurationModelBuilderData): SecHubConfigurationModel { + const model = new SecHubConfigurationModel(); - if (model.codeScan.fileSystem==null){ - model.codeScan.fileSystem={ - }; - } + const referenceName = 'reference-data-1'; - model.codeScan.fileSystem.folders = data.includeFolders; - } + createSourceOrBinaryDataReference(referenceName, builderData, model); - if (data.excludeFolders) { - model.codeScan.excludes = data.excludeFolders; + if (builderData.scanTypes?.indexOf(ScanType.CODE_SCAN) != -1) { + const codescan = new cm.CodeScan(); + codescan.use = [referenceName]; + model.codeScan = codescan; + } + if (builderData.scanTypes?.indexOf(ScanType.LICENSE_SCAN) != -1) { + const licenseScan = new cm.LicenseScan(); + licenseScan.use = [referenceName]; + model.licenseScan = licenseScan; } + if (builderData.scanTypes?.indexOf(ScanType.SECRET_SCAN) != -1) { + const secretScan = new cm.SecretScan(); + secretScan.use = [referenceName]; + model.secretScan = secretScan; + } + return model; } + +function createSourceOrBinaryDataReference(referenceName: string, builderData: SecHubConfigurationModelBuilderData, model: SecHubConfigurationModel) { + if (builderData.contentType == cm.ContentType.SOURCE) { + + const sourceData1 = new cm.SourceData(); + sourceData1.name = referenceName; + + sourceData1.fileSystem.folders = builderData.includeFolders; + sourceData1.excludes = builderData.excludeFolders; + + model.data.sources = [sourceData1]; + + } else if (builderData.contentType == cm.ContentType.BINARIES) { + const binaryData1 = new cm.BinaryData(); + binaryData1.name = referenceName; + + binaryData1.fileSystem.folders = builderData.includeFolders; + binaryData1.excludes = builderData.excludeFolders; + + model.data.binaries = [binaryData1]; + } +} + diff --git a/github-actions/scan/src/configuration-model.ts b/github-actions/scan/src/configuration-model.ts index 8e2d7cb619..d03985152f 100644 --- a/github-actions/scan/src/configuration-model.ts +++ b/github-actions/scan/src/configuration-model.ts @@ -1,18 +1,68 @@ // SPDX-License-Identifier: MIT +export enum ContentType{ + + SOURCE = 'source', + + BINARIES = 'binaries' +} + +export enum ScanType{ + + CODE_SCAN = 'code-scan', + + LICENSE_SCAN = 'license-scan', + + SECRET_SCAN = 'secret-scan', + +} + /** * SecHub configuration model */ -export type SecHubConfigurationModel = { - apiVersion: string; +export class SecHubConfigurationModel { + apiVersion='1.0'; + + data = new DataSection(); + codeScan?: CodeScan; -}; + secretScan?: SecretScan; + licenseScan?: LicenseScan; +} + +export class DataSection { + sources: SourceData[]|undefined; + binaries: BinaryData[]|undefined; +} + +export class SourceData { + name = ''; + fileSystem= new FileSystem(); + + excludes: string[]|undefined; + additionalFilenameExtensions: string[]|undefined; +} + +export class BinaryData { + name = ''; + fileSystem= new FileSystem(); + + excludes: string[]|undefined; + additionalFilenameExtensions: string[]|undefined; +} + +export class CodeScan { + use: string[] = []; +} + +export class SecretScan { + use: string[] = []; +} -type CodeScan = { - fileSystem?: FileSystem; - excludes?: string[]; -}; +export class LicenseScan { + use: string[] = []; +} -type FileSystem = { - folders?: string[]; -}; +export class FileSystem{ + folders?: string[] = []; +} From 11fca20856804da4019166931fd5a3ea15faf8d7 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Wed, 20 Mar 2024 08:12:29 +0100 Subject: [PATCH 11/30] Improvements and fixes for gh_action "scan" #2441 --- .../scan/__test__/configuration-model.test.ts | 89 ++ .../scan/__test__/integrationtest.test.ts | 150 ++- .../integrationtest/03-init_sechub_data.sh | 10 +- ...reen.json => executor-codescan-green.json} | 2 +- ...an-red.json => executor-codescan-red.json} | 2 +- ...low.json => executor-codescan-yellow.json} | 2 +- .../executor-licensescan-green.json | 39 + .../executor-secretscan-yellow.json | 39 + ...can-red.json => executor-webscan-red.json} | 2 +- .../gha_integrationtest_pds-config.json | 12 + .../example-gitleaks-sarif-output-yellow.json | 1109 +++++++++++++++++ .../example-scancode-spdx-output.json | 390 ++++++ .../pds-licensescan-demo-green.sh | 4 + .../pds-secretscan-demo-yellow.sh | 4 + github-actions/scan/dist/index.js | 202 ++- github-actions/scan/package.json | 4 +- .../scan/src/configuration-builder.ts | 8 +- .../scan/src/configuration-model.ts | 110 +- github-actions/scan/src/input.ts | 63 +- github-actions/scan/src/launcher.ts | 31 +- github-actions/scan/src/post-scan.ts | 9 +- github-actions/scan/src/report-formats.ts | 2 +- sechub.json | 43 +- 23 files changed, 2204 insertions(+), 122 deletions(-) create mode 100644 github-actions/scan/__test__/configuration-model.test.ts rename github-actions/scan/__test__/integrationtest/test-config/{test-executor-codescan-green.json => executor-codescan-green.json} (95%) rename github-actions/scan/__test__/integrationtest/test-config/{test-executor-codescan-red.json => executor-codescan-red.json} (96%) rename github-actions/scan/__test__/integrationtest/test-config/{test-executor-codescan-yellow.json => executor-codescan-yellow.json} (95%) create mode 100644 github-actions/scan/__test__/integrationtest/test-config/executor-licensescan-green.json create mode 100644 github-actions/scan/__test__/integrationtest/test-config/executor-secretscan-yellow.json rename github-actions/scan/__test__/integrationtest/test-config/{test-executor-webscan-red.json => executor-webscan-red.json} (96%) create mode 100644 github-actions/scan/__test__/integrationtest/test-product-output/example-gitleaks-sarif-output-yellow.json create mode 100644 github-actions/scan/__test__/integrationtest/test-product-output/example-scancode-spdx-output.json create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-licensescan-demo-green.sh create mode 100755 github-actions/scan/__test__/integrationtest/test-scripts/pds-secretscan-demo-yellow.sh diff --git a/github-actions/scan/__test__/configuration-model.test.ts b/github-actions/scan/__test__/configuration-model.test.ts new file mode 100644 index 0000000000..59edc78b3a --- /dev/null +++ b/github-actions/scan/__test__/configuration-model.test.ts @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT + +import { SecHubConfigurationModelBuilderData } from '../src/configuration-builder'; +import { ContentType, ScanType } from '../src/configuration-model'; + +jest.mock('@actions/core'); + + +describe('configuration-model:ScanType', function() { + + test('ScanType.ensureAccepted - no params results in default', () => { + + /* prepare */ + + /* execute */ + const result = ScanType.ensureAccepted([]); + + /* test */ + expect(result).toEqual([SecHubConfigurationModelBuilderData.DEFAULT_SCAN_TYPE]); + + }); + + test('ScanType.ensureAccepted - wrong params results in default', () => { + + /* execute */ + const result = ScanType.ensureAccepted(['x','y']); + + /* test */ + expect(result).toEqual([SecHubConfigurationModelBuilderData.DEFAULT_SCAN_TYPE]); + + }); + + test('ScanType.ensureAccepted - partyl wrong params results in correct one only', () => { + + /* execute */ + const result = ScanType.ensureAccepted(['licensescan','y']); + + /* test */ + expect(result).toEqual([ScanType.LICENSE_SCAN]); + + }); + + test('ScanType.ensureAccepted - wellknown params accepted case insensitive but converted', () => { + + /* execute */ + const result = ScanType.ensureAccepted(['licensescan','SECRETscan','codeScan']); + + /* test */ + expect(result).toContain(ScanType.LICENSE_SCAN); + expect(result).toContain(ScanType.CODE_SCAN); + expect(result).toContain(ScanType.SECRET_SCAN); + + expect(result.length).toBe(3); + + }); + +}); + +describe('configuration-model:ContentType', function() { + + test('ContentType.ensureAccepted - source accepted case insensitive but converted', () => { + + /* execute */ + const result = ContentType.ensureAccepted('souRce'); + + /* test */ + expect(result).toBe(ContentType.SOURCE); + + }); + test('ContentType.ensureAccepted - binaries accepted case insensitive but converted', () => { + + /* execute */ + const result = ContentType.ensureAccepted('BINaries'); + + /* test */ + expect(result).toBe(ContentType.BINARIES); + + }); + test('ContentType.ensureAccepted - other not accepted but converted to source as default', () => { + + /* execute */ + const result = ContentType.ensureAccepted('other'); + + /* test */ + expect(result).toBe(ContentType.SOURCE); + + }); + +}); \ No newline at end of file diff --git a/github-actions/scan/__test__/integrationtest.test.ts b/github-actions/scan/__test__/integrationtest.test.ts index a5f1c8b81d..ca26494d8d 100644 --- a/github-actions/scan/__test__/integrationtest.test.ts +++ b/github-actions/scan/__test__/integrationtest.test.ts @@ -9,6 +9,7 @@ import { getFieldFromJsonReport } from '../src/json-helper'; import * as launcher from '../src/launcher'; import { LaunchContext } from '../src/launcher'; import { IntegrationTestContext } from './integrationtest/testframework'; +import * as fs from 'fs'; jest.mock('@actions/core'); jest.mock('@actions/artifact'); @@ -40,6 +41,11 @@ integrationTestContext.finish(); const mockedInputMap = new Map(); beforeEach(() => { + + shell.echo('----------------------------------------------------------------------------------------------------------------------------------'); + shell.echo('START Integration test: '+ expect.getState().currentTestName); + shell.echo('----------------------------------------------------------------------------------------------------------------------------------'); + jest.resetAllMocks(); (getInput as jest.Mock).mockImplementation((name) => { @@ -87,7 +93,7 @@ function initInputMap() { } describe('integrationtest codescan generated config', () => { - test('codescan green', () => { + test('codescan green', async () => { /* prepare */ initInputMap(); @@ -95,15 +101,15 @@ describe('integrationtest codescan generated config', () => { mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-1'); /* execute */ - const launchPromise = launcher.launch(); + const result = await launcher.launch(); /* test */ - assertLastClientExitCode(launchPromise, 0); - assertTrafficLight(launchPromise, 'GREEN'); - assertReportContains(launchPromise, 'result-green'); + assertLastClientExitCode(result, 0); + assertTrafficLight(result, 'GREEN'); + assertJsonReportContains(result, 'result-green'); }); - test('codescan yellow', function () { + test('codescan yellow', async () => { /* prepare */ initInputMap(); @@ -111,16 +117,16 @@ describe('integrationtest codescan generated config', () => { mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-2'); /* execute */ - const launchPromise = launcher.launch(); + const result = await launcher.launch(); /* test */ - assertLastClientExitCode(launchPromise, 0); - assertTrafficLight(launchPromise, 'YELLOW'); - assertReportContains(launchPromise, 'result-yellow'); + assertLastClientExitCode(result, 0); + assertTrafficLight(result, 'YELLOW'); + assertJsonReportContains(result, 'result-yellow'); }); - test('codescan red', function () { + test('codescan red', async () => { /* prepare */ initInputMap(); @@ -128,19 +134,82 @@ describe('integrationtest codescan generated config', () => { mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-3'); /* execute */ - const launchPromise = launcher.launch(); + const result = await launcher.launch(); + + /* test */ + assertLastClientExitCode(result, 1); // exit code 1, because RED + assertTrafficLight(result, 'RED'); + assertJsonReportContains(result, 'result-red'); + }); + +}); + +describe('integrationtest secretscan generated config', () => { + test('secretscan yellow, json only', async () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-5'); + mockedInputMap.set(input.PARAM_SCAN_TYPES, 'secretscan'); + + /* execute */ + const result = await launcher.launch(); + + /* test */ + assertTrafficLight(result, 'YELLOW'); + assertLastClientExitCode(result, 0); + assertJsonReportContains(result, 'generic-api-key has detected secret for file UnSAFE_Bank/Backend/docker-compose.yml'); + + }); + test('secretscan yellow, html', async () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-5'); + mockedInputMap.set(input.PARAM_SCAN_TYPES, 'secretscan'); + mockedInputMap.set(input.PARAM_REPORT_FORMATS, 'html'); + + /* execute */ + const result = await launcher.launch(); /* test */ - assertLastClientExitCode(launchPromise, 1); // exit code 1, because RED - assertTrafficLight(launchPromise, 'RED'); - assertReportContains(launchPromise, 'result-red'); + assertTrafficLight(result, 'YELLOW'); + assertLastClientExitCode(result, 0); + assertJsonReportContains(result, 'generic-api-key has detected secret for file UnSAFE_Bank/Backend/docker-compose.yml'); + + loadHTMLReportAndAssertItContains(result, 'generic-api-key has detected secret for file UnSAFE_Bank/Backend/docker-compose.yml'); + }); }); +describe('integrationtest licensescan generated config', () => { + test('licensescan green, spdx-json', async () => { + + /* prepare */ + initInputMap(); + mockedInputMap.set(input.PARAM_INCLUDED_FOLDERS, '__test__/integrationtest/test-sources'); + mockedInputMap.set(input.PARAM_PROJECT_NAME, 'test-project-6'); + mockedInputMap.set(input.PARAM_SCAN_TYPES, 'licensescan'); + mockedInputMap.set(input.PARAM_REPORT_FORMATS, 'spdx-json'); + + /* execute */ + const result = await launcher.launch(); + + /* test */ + assertTrafficLight(result, 'GREEN'); + assertLastClientExitCode(result, 0); + assertJsonReportContains(result, 'findings'); // findings in json available - but green, because only licensescan + + loadSpdxJsonReportAndAssertItContains(result, 'LGPL'); + }); + +}); describe('integrationtest non-generated config', () => { - test('config-path defined, but file not found', () => { + test('config-path defined, but file not found', async () => { /* prepare */ initInputMap(); @@ -148,11 +217,11 @@ describe('integrationtest non-generated config', () => { mockedInputMap.set(input.PARAM_CONFIG_PATH, 'unknown/not-existing-config.json'); /* execute + test */ - launcher.launch().catch(error => console.log(`Error handled : ${error}`)); + await launcher.launch().catch(error => console.log(`Error handled : ${error}`)); }); - test('config-path defined, file available, web scan with red trafficlight', () => { + test('config-path defined, file available, web scan with red trafficlight', async () => { /* prepare */ initInputMap(); @@ -164,32 +233,57 @@ describe('integrationtest non-generated config', () => { mockedInputMap.set(input.PARAM_CONFIG_PATH, `${configDir}/sechub-config-webscan-project-4.json`); /* execute */ - const launchPromise = launcher.launch(); + const result = await launcher.launch(); /* test */ - assertLastClientExitCode(launchPromise, 1); - assertTrafficLight(launchPromise, 'RED'); - assertReportContains(launchPromise, 'XSS attackable parameter output: