From d20ace909d5040af3b36c0498e3429ad40a520f9 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 20 Nov 2024 16:59:55 +0000 Subject: [PATCH 01/16] chore: documentation for action / template to check security gate (#2240) --- .github/workflows/publish_docs.yml | 2 +- docs/getting_started/about.md | 22 ++++++++++++++----- .../github_actions_and_templates.md | 9 ++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index 4f894d079..f6ffa92db 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -4,7 +4,7 @@ on: push: branches: - main - - chore/doc_trivy_secrets + - chore/documentation_check_security_gate permissions: read-all diff --git a/docs/getting_started/about.md b/docs/getting_started/about.md index b5c92626b..541a60528 100644 --- a/docs/getting_started/about.md +++ b/docs/getting_started/about.md @@ -36,10 +36,16 @@ sequenceDiagram activate Pipeline Pipeline ->> Pipeline: Run scanners Pipeline ->> SecObserve: Upload results - deactivate Pipeline activate SecObserve SecObserve ->> SecObserve: Apply rules deactivate SecObserve + Pipeline ->> SecObserve: Check security gate + activate SecObserve + SecObserve -->> Pipeline: exit code 0/1 + deactivate SecObserve + Pipeline ->> Pipeline: Stop or continue + Pipeline -->> Developer: Feedback + deactivate Pipeline Developer ->> SecObserve: View observations Developer ->> SecObserve: Assess observations Developer ->> Developer: Implement fixes @@ -51,7 +57,13 @@ sequenceDiagram 3. The pipeline runs several of the supported vulnerability scanners. To make integration easy, SecObserve provides predefined templates for the most relevant scanners, see [GitHub actions and GitLab CI templates](../integrations/github_actions_and_templates.md). 4. The scanners store their results in files, which are [uploaded into SecObserve](../usage/import_observations.md). 5. SecObserve applies [rules](../usage/rule_engine.md) to adjust severity and status of observations during the upload process. -6. The developer can now look at the observations in SecObserve, to see what has changed ... -7. ... and if necessary [assess observations](../usage/assess_observations.md) to change their status (eg. false positive or risk accepted) or severity. -8. If fixes are needed to close vulnerabilities, the developer will implement the fixes ... -9. ... and check them in to the repository. Now the cycle starts again. +6. The pipeline can call SecObserve to check the status of the [security gate](../usage/security_gates.md). +7. SecObserve returns an exit code to the pipeline: + * `1` if the security gate has **failed** + * `0` if the security gate has **passed** or is **disabled** +8. The pipeline can stop or continue based on the exit code, depending on the configuration of the check step. Default is to stop the pipeline if the security gate has failed. +9. The developer can see the result of the pipeline. +10. The developer can now look at the observations in SecObserve, to see what has changed ... +11. ... and if necessary [assess observations](../usage/assess_observations.md) to change their status (eg. false positive or risk accepted) or severity. +12. If fixes are needed to close vulnerabilities, the developer will implement the fixes ... +13. ... and check them in to the repository. Now the cycle starts again. diff --git a/docs/integrations/github_actions_and_templates.md b/docs/integrations/github_actions_and_templates.md index 27d18e5c7..38d65a7f2 100644 --- a/docs/integrations/github_actions_and_templates.md +++ b/docs/integrations/github_actions_and_templates.md @@ -31,6 +31,10 @@ Most of the actions and templates use the same set of variables: | `SO_ORIGIN_DOCKER_IMAGE_NAME_TAG` | *optional* | Name:Tag of Docker image to be set for all imported observations. | | `SO_ORIGIN_ENDPOINT_URL` | *optional* | URL of endpoint to be set for all imported observations. | | `SO_SUPPRESS_LICENSES` | *optional, only for CycloneDX* | Suppress importing license information if value is `true`. Default is `true` for the *Grype*, *Trivy Filesystem* and *Trivy Image* GitHub action / GitLab templates, default is `false` for the *Importer* action/template | +| **Check security gate** | +| `SO_API_BASE_URL` | *mandatory* | Base URL of the SecObserve backend, e.g. `https://secobserve-backend.example.com`. | +| `SO_API_TOKEN` | *mandatory* | API token of the user to be used for the check. | +| `SO_PRODUCT_NAME` | *mandatory* | Name of the product for which the security gate check is being performed. | ## Available actions and templates @@ -58,6 +62,11 @@ Most of the actions and templates use the same set of variables: | [DrHeader](https://github.com/Santandersecurityresearch/DrHeader) | `actions/DAST/drheader` | `templates/DAST/drheader.yml` | [MIT](https://github.com/Santandersecurityresearch/DrHeader/blob/master/LICENSE) | | [ZAP](https://github.com/zaproxy/zaproxy) | `actions/DAST/zap` | `templates/DAST/zap.yml` | [Apache 2.0](https://github.com/zaproxy/zaproxy/blob/main/LICENSE) | +| Task | GitHub Action | GitLab CI Template | +|---------------------------------------|---------------------------|---------------------------------| +| Import existing file into SecObserve | `actions/importer` | `templates/importer.yml` | +| Check security gate of a product (`exit code 1` if security gate **Failed**, `exit code 0` if security gate **Passed** or **Disabled**) | `actions/check_security_gate` | `templates/check_security_gate.yml` | + All GitHub actions and GitLab CI templates use a pre-built Docker image that contains all scanners and the SecObserve importer. ## Examplary workflow for GitHub actions From fcf7feb1dacf0dd5fdff82e740b4271e9db6dcb2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:05:08 +0100 Subject: [PATCH 02/16] fix(deps): update dependency markdown-to-jsx to v7.7.0 (#2235) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8d1916878..c7159795f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,7 +18,7 @@ "@textea/json-viewer": "3.5.0", "axios": "1.7.7", "chart.js": "4.4.6", - "markdown-to-jsx": "7.6.2", + "markdown-to-jsx": "7.7.0", "mermaid": "11.4.0", "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", @@ -6674,9 +6674,9 @@ } }, "node_modules/markdown-to-jsx": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.6.2.tgz", - "integrity": "sha512-gEcyiJXzBxmId2Y/kydLbD6KRNccDiUy/Src1cFGn3s2X0LZZ/hUiEc2VisFyA5kUE3SXclTCczjQiAuqKZiFQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.7.0.tgz", + "integrity": "sha512-130nIMbJY+woOQJ11xTqEtYko60t6EpNkZuqjKMferL3udtob3nRfzXOdsiA26NPemiR7w/hR8M3/B9yiYPGZg==", "license": "MIT", "engines": { "node": ">= 10" diff --git a/frontend/package.json b/frontend/package.json index a5c653f53..67aa98254 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,7 @@ "@textea/json-viewer": "3.5.0", "axios": "1.7.7", "chart.js": "4.4.6", - "markdown-to-jsx": "7.6.2", + "markdown-to-jsx": "7.7.0", "mermaid": "11.4.0", "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", From 0e968715aca721cf3c909fe25d376f0e4ef77bb7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:13:30 +0100 Subject: [PATCH 03/16] chore(deps): update dependency mkdocs-material to v9.5.45 (#2236) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- mkdocs_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs_requirements.txt b/mkdocs_requirements.txt index bf0847075..52be620e3 100644 --- a/mkdocs_requirements.txt +++ b/mkdocs_requirements.txt @@ -1 +1 @@ -mkdocs-material==9.5.44 # https://github.com/squidfunk/mkdocs-material +mkdocs-material==9.5.45 # https://github.com/squidfunk/mkdocs-material From 7a4fb4cbd993fcf960981eee6ab9286254adb986 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:17:51 +0100 Subject: [PATCH 04/16] fix(deps): update emotion monorepo to v11.13.5 (#2237) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 60 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c7159795f..2917a0b13 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,8 +9,8 @@ "version": "1.22.3", "license": "BSD-3-Clause", "dependencies": { - "@emotion/react": "11.13.3", - "@emotion/styled": "11.13.0", + "@emotion/react": "11.13.5", + "@emotion/styled": "11.13.5", "@fortawesome/fontawesome-svg-core": "6.7.0", "@fortawesome/free-brands-svg-icons": "6.7.0", "@fortawesome/free-solid-svg-icons": "6.7.0", @@ -514,16 +514,16 @@ "license": "Apache-2.0" }, "node_modules/@emotion/babel-plugin": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", - "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.2.0", + "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -533,14 +533,14 @@ } }, "node_modules/@emotion/cache": { - "version": "11.13.1", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", - "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.5.tgz", + "integrity": "sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==", "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } @@ -567,17 +567,17 @@ "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.13.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", - "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz", + "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", - "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.1", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, @@ -591,15 +591,15 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", - "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.1", + "@emotion/utils": "^1.4.2", "csstype": "^3.0.2" } }, @@ -610,17 +610,17 @@ "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", - "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz", + "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", + "@emotion/babel-plugin": "^11.13.5", "@emotion/is-prop-valid": "^1.3.0", - "@emotion/serialize": "^1.3.0", + "@emotion/serialize": "^1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0" + "@emotion/utils": "^1.4.2" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -648,9 +648,9 @@ } }, "node_modules/@emotion/utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", - "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", "license": "MIT" }, "node_modules/@emotion/weak-memoize": { diff --git a/frontend/package.json b/frontend/package.json index 67aa98254..a2a152eb6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,8 +5,8 @@ "description": "SecObserve is an open source vulnerability management system for software development and cloud environments.", "private": true, "dependencies": { - "@emotion/react": "11.13.3", - "@emotion/styled": "11.13.0", + "@emotion/react": "11.13.5", + "@emotion/styled": "11.13.5", "@fortawesome/fontawesome-svg-core": "6.7.0", "@fortawesome/free-brands-svg-icons": "6.7.0", "@fortawesome/free-solid-svg-icons": "6.7.0", From 799080e8a43d9a652d3132b91cd4c827051d3311 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:22:49 +0100 Subject: [PATCH 05/16] fix(deps): update font awesome to v6.7.1 (#2239) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 36 ++++++++++++++++++------------------ frontend/package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2917a0b13..afb4cd5fd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,9 +11,9 @@ "dependencies": { "@emotion/react": "11.13.5", "@emotion/styled": "11.13.5", - "@fortawesome/fontawesome-svg-core": "6.7.0", - "@fortawesome/free-brands-svg-icons": "6.7.0", - "@fortawesome/free-solid-svg-icons": "6.7.0", + "@fortawesome/fontawesome-svg-core": "6.7.1", + "@fortawesome/free-brands-svg-icons": "6.7.1", + "@fortawesome/free-solid-svg-icons": "6.7.1", "@fortawesome/react-fontawesome": "0.2.2", "@textea/json-viewer": "3.5.0", "axios": "1.7.7", @@ -1193,45 +1193,45 @@ } }, "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.0.tgz", - "integrity": "sha512-AUetZXU6cQdAe21p8j3mg2aD40MMDKfFNUNgq/G7gR3HMDp0BsQskAudLDSgq6d0SbCY0QKP0g4s5Y02S1kkhw==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.1.tgz", + "integrity": "sha512-gbDz3TwRrIPT3i0cDfujhshnXO9z03IT1UKRIVi/VEjpNHtSBIP2o5XSm+e816FzzCFEzAxPw09Z13n20PaQJQ==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.0.tgz", - "integrity": "sha512-v6YZjSPuxriC7lYxCzKFbgZ1iaf60AVX2CsfZXSc0U9+mqVd8VGVtMEqDqz5GxDpNUQ8bMDfW+gspVMYGlRpUA==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.1.tgz", + "integrity": "sha512-8dBIHbfsKlCk2jHQ9PoRBg2Z+4TwyE3vZICSnoDlnsHA6SiMlTwfmW6yX0lHsRmWJugkeb92sA0hZdkXJhuz+g==", "license": "MIT", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.7.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-brands-svg-icons": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.0.tgz", - "integrity": "sha512-O/9/yKlN4T0bsYCBcx0NKq7YOr/512Yfpk8wZhOhaxg9/OxWLipDKXlP1hfEFE3I26mfYtsqLkbpz1CNu6KYqw==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.1.tgz", + "integrity": "sha512-nJR76eqPzCnMyhbiGf6X0aclDirZriTPRcFm1YFvuupyJOGwlNF022w3YBqu+yrHRhnKRpzFX+8wJKqiIjWZkA==", "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.7.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.0.tgz", - "integrity": "sha512-9ww5hQ3OzEehUrSXAlPTJ73xDub73fnxr+se5PU0MFQor2nZBO0m7HNm5Q4KD9XMYjwRqh2BnBNR2/9EFbGqmg==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.1.tgz", + "integrity": "sha512-BTKc0b0mgjWZ2UDKVgmwaE0qt0cZs6ITcDgjrti5f/ki7aF5zs+N91V6hitGo3TItCFtnKg6cUVGdTmBFICFRg==", "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.7.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" diff --git a/frontend/package.json b/frontend/package.json index a2a152eb6..efe5d30d9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,9 +7,9 @@ "dependencies": { "@emotion/react": "11.13.5", "@emotion/styled": "11.13.5", - "@fortawesome/fontawesome-svg-core": "6.7.0", - "@fortawesome/free-brands-svg-icons": "6.7.0", - "@fortawesome/free-solid-svg-icons": "6.7.0", + "@fortawesome/fontawesome-svg-core": "6.7.1", + "@fortawesome/free-brands-svg-icons": "6.7.1", + "@fortawesome/free-solid-svg-icons": "6.7.1", "@fortawesome/react-fontawesome": "0.2.2", "@textea/json-viewer": "3.5.0", "axios": "1.7.7", From b0f22a91f394393032ba4a04753a0d111297e665 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:31:58 +0100 Subject: [PATCH 06/16] chore(deps): update maibornwolff/secobserve_actions_templates digest to d15c240 (#2213) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_push_dev.yml | 2 +- .github/workflows/build_push_release.yml | 4 ++-- .github/workflows/check_licenses_dev.yml | 4 ++-- .github/workflows/check_vulnerabilities.yml | 2 +- .github/workflows/scan_sca_current.yml | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build_push_dev.yml b/.github/workflows/build_push_dev.yml index a4891cdd5..57b58a048 100644 --- a/.github/workflows/build_push_dev.yml +++ b/.github/workflows/build_push_dev.yml @@ -52,7 +52,7 @@ jobs: VERSION=dev - name: Run SCA vulnerability scanners - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_sca_dev.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} diff --git a/.github/workflows/build_push_release.yml b/.github/workflows/build_push_release.yml index 740aba719..67c013166 100644 --- a/.github/workflows/build_push_release.yml +++ b/.github/workflows/build_push_release.yml @@ -64,13 +64,13 @@ jobs: VERSION=${{ github.event.inputs.release }} - name: Run vulnerability scanners for images - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_sca_current.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} - name: Run vulnerability scanners for endpoints - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_endpoints.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} diff --git a/.github/workflows/check_licenses_dev.yml b/.github/workflows/check_licenses_dev.yml index 9af3383c8..4a73470d8 100644 --- a/.github/workflows/check_licenses_dev.yml +++ b/.github/workflows/check_licenses_dev.yml @@ -37,7 +37,7 @@ jobs: cdxgen ./frontend --type npm --no-babel --required-only --profile license-compliance --no-auto-compositions --project-name secobserve --output sbom_frontend_application.json - name: Import backend SBOM - uses: MaibornWolff/secobserve_actions_templates/actions/importer@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/importer@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_product_name: 'SecObserve' so_file_name: 'sbom_backend_application.json' @@ -47,7 +47,7 @@ jobs: so_api_token: ${{ secrets.SO_API_TOKEN }} - name: Import frontend SBOM - uses: MaibornWolff/secobserve_actions_templates/actions/importer@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/importer@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_product_name: 'SecObserve' so_file_name: 'sbom_frontend_application.json' diff --git a/.github/workflows/check_vulnerabilities.yml b/.github/workflows/check_vulnerabilities.yml index a6b119421..224e82fc9 100644 --- a/.github/workflows/check_vulnerabilities.yml +++ b/.github/workflows/check_vulnerabilities.yml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run vulnerability scanners for code - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_code.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} diff --git a/.github/workflows/scan_sca_current.yml b/.github/workflows/scan_sca_current.yml index f27c01d5c..a6ba9db27 100644 --- a/.github/workflows/scan_sca_current.yml +++ b/.github/workflows/scan_sca_current.yml @@ -18,13 +18,13 @@ jobs: ref: 'v1.22.2' - name: Run SCA vulnerability scanners - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_sca_current.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} - name: Run endpoint vulnerability scanners - uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5606a843f40e25d002053dfd14cd525496c76560 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main with: so_configuration: 'so_configuration_endpoints.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} From e7d94615fc878db5225fa5d6dc8eb5e4c9b0d4dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:17:36 +0100 Subject: [PATCH 07/16] chore(deps): update github/codeql-action action to v3.27.5 (#2238) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 04fe3fe3b..3c43ef4df 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: sarif_file: results.sarif From c8c986cd9aad5ac83c52ab2fc9e745bd67863b6d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:06:04 +0100 Subject: [PATCH 08/16] chore(deps): update traefik docker tag to v3.2.1 (#2241) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose-prod-mysql.yml | 2 +- docker-compose-prod-postgres.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose-prod-mysql.yml b/docker-compose-prod-mysql.yml index f70d9138b..c4431b6a8 100644 --- a/docker-compose-prod-mysql.yml +++ b/docker-compose-prod-mysql.yml @@ -10,7 +10,7 @@ networks: services: traefik: - image: "traefik:v3.2.0" + image: "traefik:v3.2.1" container_name: "prod_traefik" command: - "--log.level=INFO" diff --git a/docker-compose-prod-postgres.yml b/docker-compose-prod-postgres.yml index c6ae0c3c0..98c0617b3 100644 --- a/docker-compose-prod-postgres.yml +++ b/docker-compose-prod-postgres.yml @@ -10,7 +10,7 @@ networks: services: traefik: - image: "traefik:v3.2.0" + image: "traefik:v3.2.1" container_name: "prod_traefik" command: - "--log.level=INFO" From c312c23419d67315ea4008e04fceb370165eebb1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:56:28 +0100 Subject: [PATCH 09/16] fix(deps): update react-admin monorepo to v5.4.0 (#2242) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 56 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index afb4cd5fd..bd707791b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,9 +23,9 @@ "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", "query-string": "9.1.1", - "ra-input-rich-text": "5.3.4", + "ra-input-rich-text": "5.4.0", "react": "18.3.1", - "react-admin": "5.3.4", + "react-admin": "5.4.0", "react-chartjs-2": "5.2.0", "react-dom": "18.3.1", "react-oidc-context": "3.2.0", @@ -7514,12 +7514,12 @@ "license": "MIT" }, "node_modules/ra-core": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/ra-core/-/ra-core-5.3.4.tgz", - "integrity": "sha512-BC6pO8jaUjJESfO0FS6J2CMgeRreJ2kpdPkkySBODM0M5S4ZRC0rOFh1jBXFnjSUcNoPWaVc/WaZPwfAg00Wmw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ra-core/-/ra-core-5.4.0.tgz", + "integrity": "sha512-Gvp7FiItL0fYq0r9C5jU0Gm56096c2FfOY/UaCDnOvshs3UGTLd5cknRZ30lo9Qr+SoZPP8PH8Ef6LblEXkFBA==", "license": "MIT", "dependencies": { - "@tanstack/react-query": "^5.8.4", + "@tanstack/react-query": "^5.21.7", "clsx": "^2.1.1", "date-fns": "^3.6.0", "eventemitter3": "^5.0.1", @@ -7590,19 +7590,19 @@ } }, "node_modules/ra-i18n-polyglot": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/ra-i18n-polyglot/-/ra-i18n-polyglot-5.3.4.tgz", - "integrity": "sha512-9BtWoCHE5LxIN4+VJGOrxL29lDhCTgBjIDkTb/i228vr/CD3+ozjyMiBG8NGeLN5wCqtHpsKDwUNJOcoPtwkiQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ra-i18n-polyglot/-/ra-i18n-polyglot-5.4.0.tgz", + "integrity": "sha512-2bRIa/y1PgZFjMir3bLEo1DcLEkWr7L7jrZuTXc0gXL5E8O6tGMaWkURxJyp1iIeZ0pUiPEahr6rePWwHVeZhA==", "license": "MIT", "dependencies": { "node-polyglot": "^2.2.2", - "ra-core": "^5.3.4" + "ra-core": "^5.4.0" } }, "node_modules/ra-input-rich-text": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/ra-input-rich-text/-/ra-input-rich-text-5.3.4.tgz", - "integrity": "sha512-Ke6Y9iibjAYTIUWKhd7Ajx+YZzjD4n9vF0fKV6qMUPI5o8GOffTRhY2YTF5UZT2uSo6gaFY1AdDjgV+tRKjtmA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ra-input-rich-text/-/ra-input-rich-text-5.4.0.tgz", + "integrity": "sha512-kfVPPQcNGC56Qv6cdJoLH+sQjenHUoFud0YWSML6oGB30yr2YsNJwHr2fGkTlijO26C3UqWJ5sBZh0j+HY0rcw==", "license": "MIT", "dependencies": { "@tiptap/core": "^2.0.3", @@ -7629,21 +7629,21 @@ } }, "node_modules/ra-language-english": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/ra-language-english/-/ra-language-english-5.3.4.tgz", - "integrity": "sha512-QR0ej0JKQaGmtGSh1W+O4HnoaTv/9SQBtpztAkTitPVjlCGJeNBr/IjriAxsp0ezhhCr+uZrwrCfoWjKPkjpDg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ra-language-english/-/ra-language-english-5.4.0.tgz", + "integrity": "sha512-RUV6wo8EIFOjC4UA6d+FbfVslnvnX8f+UhElzuxRvDhXZqmEyRKxsFCLTbeI9DF/IN8Gb6pvKxCoe3jzfUcm5Q==", "license": "MIT", "dependencies": { - "ra-core": "^5.3.4" + "ra-core": "^5.4.0" } }, "node_modules/ra-ui-materialui": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/ra-ui-materialui/-/ra-ui-materialui-5.3.4.tgz", - "integrity": "sha512-ZcZtafeOzKEv2Epr6FJnWW4+Fch9VVehqPdi8CyTEUtBHD/heChkAwW3suRqJqggpykVpZoA0hrD+L02NqqJeg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ra-ui-materialui/-/ra-ui-materialui-5.4.0.tgz", + "integrity": "sha512-FwBIboQrUXyB2ztZH150zcq5v6qMiGn2aNc9OoTcft0hoWuVBS1yIE8B67JfyZyH0azgNW20ImPbC5lYDs1l1w==", "license": "MIT", "dependencies": { - "@tanstack/react-query": "^5.8.4", + "@tanstack/react-query": "^5.21.7", "autosuggest-highlight": "^3.1.1", "clsx": "^2.1.1", "css-mediaquery": "^0.1.2", @@ -7733,19 +7733,19 @@ } }, "node_modules/react-admin": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-admin/-/react-admin-5.3.4.tgz", - "integrity": "sha512-Te2cvt5NIhk5ct0yAaUdXxspyXQKsPb8JwlN4VWzXS14U16PrJ01VYc9N940Avb5Ls/ed76mfbuJNwfoEZUYVg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/react-admin/-/react-admin-5.4.0.tgz", + "integrity": "sha512-tvGyMUSXKzfqkQKf/uRowTpVhNM03Lo9iZq7e3BgO1nTOTFXqK/QcPbECpRH6IsLgH47uSDQoeqViYkB3ut9cA==", "license": "MIT", "dependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", "@mui/icons-material": "^5.15.20", "@mui/material": "^5.15.20", - "ra-core": "^5.3.4", - "ra-i18n-polyglot": "^5.3.4", - "ra-language-english": "^5.3.4", - "ra-ui-materialui": "^5.3.4", + "ra-core": "^5.4.0", + "ra-i18n-polyglot": "^5.4.0", + "ra-language-english": "^5.4.0", + "ra-ui-materialui": "^5.4.0", "react-hook-form": "^7.53.0", "react-router": "^6.22.0", "react-router-dom": "^6.22.0" diff --git a/frontend/package.json b/frontend/package.json index efe5d30d9..82a3c2abb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,9 +19,9 @@ "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", "query-string": "9.1.1", - "ra-input-rich-text": "5.3.4", + "ra-input-rich-text": "5.4.0", "react": "18.3.1", - "react-admin": "5.3.4", + "react-admin": "5.4.0", "react-chartjs-2": "5.2.0", "react-dom": "18.3.1", "react-oidc-context": "3.2.0", From 7c1ffd8db5577d6ab638c78c7765932cc689b28e Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 21 Nov 2024 13:06:48 +0000 Subject: [PATCH 10/16] fix: update access and refresh token if necessary (#2243) --- frontend/src/App.tsx | 11 +++--- .../{ => auth_provider}/OIDCSignInButton.tsx | 0 .../{ => auth_provider}/authProvider.ts | 36 ++++++++++++------- .../{ => auth_provider}/axios_instance.ts | 0 .../access_control/auth_provider/functions.ts | 16 +++++++++ .../src/access_control/{ => login}/Login.tsx | 6 ++-- .../src/access_control/{ => login}/index.ts | 0 .../ra-data-django-rest-framework/index.ts | 3 +- frontend/src/core/products/ExportMenu.tsx | 2 +- frontend/src/vex/csaf/CSAFCreate.tsx | 2 +- frontend/src/vex/csaf/CSAFUpdate.tsx | 2 +- frontend/src/vex/openvex/OpenVEXCreate.tsx | 2 +- frontend/src/vex/openvex/OpenVEXUpdate.tsx | 2 +- 13 files changed, 54 insertions(+), 28 deletions(-) rename frontend/src/access_control/{ => auth_provider}/OIDCSignInButton.tsx (100%) rename frontend/src/access_control/{ => auth_provider}/authProvider.ts (83%) rename frontend/src/access_control/{ => auth_provider}/axios_instance.ts (100%) create mode 100644 frontend/src/access_control/auth_provider/functions.ts rename frontend/src/access_control/{ => login}/Login.tsx (97%) rename frontend/src/access_control/{ => login}/index.ts (100%) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5e9b376a5..fad286a14 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,12 +1,13 @@ -import { Admin, CustomRoutes, Resource } from "react-admin"; +import { Admin, CustomRoutes, Resource, addRefreshAuthToDataProvider } from "react-admin"; import { AuthProvider } from "react-oidc-context"; import { Route } from "react-router"; -import { Login } from "./access_control"; import AccessControlAdministration from "./access_control/access_control_administration/AccessControlAdministration"; -import authProvider from "./access_control/authProvider"; -import { oidcConfig } from "./access_control/authProvider"; +import authProvider from "./access_control/auth_provider/authProvider"; +import { oidcConfig } from "./access_control/auth_provider/authProvider"; +import { updateRefreshToken } from "./access_control/auth_provider/functions"; import authorization_groups from "./access_control/authorization_groups"; +import { Login } from "./access_control/login"; import users from "./access_control/users"; import { Layout } from "./commons/layout"; import { darkTheme, lightTheme } from "./commons/layout/themes"; @@ -45,7 +46,7 @@ const App = () => { > { @@ -56,18 +56,26 @@ const authProvider: AuthProvider = { return Promise.resolve(); }, - checkError: (error) => { - if (error) { - if (error.status === 401) { - if (oidc_signed_in()) { - localStorage.setItem("last_location", location.hash); - const user_manager = new UserManager(oidcConfig); - return user_manager.signinRedirect(); - } - return Promise.reject({ message: error.message }); + checkError: async (error) => { + if (error.status === 401) { + if (oidc_signed_in()) { + const user_manager = new UserManager(oidcConfig); + localStorage.setItem("last_location", location.hash); + await user_manager + .signinSilent() + .then(() => { + error.message = false; + error.logoutUser = false; + error.redirectTo = location.hash; + throw error; + }) + .catch(() => { + localStorage.removeItem(oidcStorageKey); + return user_manager.signinRedirect(); + }); } + throw error; } - return Promise.resolve(); }, checkAuth: () => { if (oidc_signed_in() || jwt_signed_in()) { @@ -124,6 +132,8 @@ export function oidc_signed_in(): boolean { // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-invalid-void-type const onSigninCallback = (_user: User | void): void => { + const user_manager = new UserManager(oidcConfig); + user_manager.clearStaleState(); const last_location = localStorage.getItem("last_location"); if (last_location) { localStorage.removeItem("last_location"); diff --git a/frontend/src/access_control/axios_instance.ts b/frontend/src/access_control/auth_provider/axios_instance.ts similarity index 100% rename from frontend/src/access_control/axios_instance.ts rename to frontend/src/access_control/auth_provider/axios_instance.ts diff --git a/frontend/src/access_control/auth_provider/functions.ts b/frontend/src/access_control/auth_provider/functions.ts new file mode 100644 index 000000000..cb8aa8c01 --- /dev/null +++ b/frontend/src/access_control/auth_provider/functions.ts @@ -0,0 +1,16 @@ +import { UserManager } from "oidc-client-ts"; + +import { oidcConfig, oidcStorageUser } from "./authProvider"; + +export const updateRefreshToken = () => { + const oidcUser = oidcStorageUser(); + if (oidcUser) { + const expires_at = JSON.parse(oidcUser).expires_at * 1000; + if (expires_at < Date.now()) { + localStorage.setItem("user_action", "refreshing token"); + const user_manager = new UserManager(oidcConfig); + user_manager.signinSilent(); + } + } + return Promise.resolve(); +}; diff --git a/frontend/src/access_control/Login.tsx b/frontend/src/access_control/login/Login.tsx similarity index 97% rename from frontend/src/access_control/Login.tsx rename to frontend/src/access_control/login/Login.tsx index 515f1a920..aa5fe38fa 100644 --- a/frontend/src/access_control/Login.tsx +++ b/frontend/src/access_control/login/Login.tsx @@ -8,9 +8,9 @@ import { Form, TextInput, required, useLogin, useNotify, useTheme } from "react- import { useAuth } from "react-oidc-context"; import { Navigate, useLocation } from "react-router-dom"; -import { getTheme } from "../commons/user_settings/functions"; -import { OIDCSignInButton } from "./OIDCSignInButton"; -import { jwt_signed_in } from "./authProvider"; +import { getTheme } from "../../commons/user_settings/functions"; +import { OIDCSignInButton } from "../auth_provider/OIDCSignInButton"; +import { jwt_signed_in } from "../auth_provider/authProvider"; const Login = () => { const [loading, setLoading] = useState(false); diff --git a/frontend/src/access_control/index.ts b/frontend/src/access_control/login/index.ts similarity index 100% rename from frontend/src/access_control/index.ts rename to frontend/src/access_control/login/index.ts diff --git a/frontend/src/commons/ra-data-django-rest-framework/index.ts b/frontend/src/commons/ra-data-django-rest-framework/index.ts index d8b7017a8..1b7493208 100644 --- a/frontend/src/commons/ra-data-django-rest-framework/index.ts +++ b/frontend/src/commons/ra-data-django-rest-framework/index.ts @@ -6,8 +6,7 @@ import queryString from "query-string"; import { DataProvider, Identifier, fetchUtils } from "react-admin"; -import { jwt_signed_in, oidc_signed_in } from "../../access_control/authProvider"; -import { get_oidc_id_token } from "../../access_control/authProvider"; +import { get_oidc_id_token, jwt_signed_in, oidc_signed_in } from "../../access_control/auth_provider/authProvider"; const base_url = window.__RUNTIME_CONFIG__.API_BASE_URL; diff --git a/frontend/src/core/products/ExportMenu.tsx b/frontend/src/core/products/ExportMenu.tsx index 7fc84ae6c..26d254ab2 100644 --- a/frontend/src/core/products/ExportMenu.tsx +++ b/frontend/src/core/products/ExportMenu.tsx @@ -9,7 +9,7 @@ import MenuItem from "@mui/material/MenuItem"; import { Fragment, MouseEvent, useState } from "react"; import { useNotify } from "react-admin"; -import axios_instance from "../../access_control/axios_instance"; +import axios_instance from "../../access_control/auth_provider/axios_instance"; import { feature_license_management, getIconAndFontColor } from "../../commons/functions"; interface ExportMenuProps { diff --git a/frontend/src/vex/csaf/CSAFCreate.tsx b/frontend/src/vex/csaf/CSAFCreate.tsx index 476c68106..97f4f9a5a 100644 --- a/frontend/src/vex/csaf/CSAFCreate.tsx +++ b/frontend/src/vex/csaf/CSAFCreate.tsx @@ -24,7 +24,7 @@ import { useRefresh, } from "react-admin"; -import axios_instance from "../../access_control/axios_instance"; +import axios_instance from "../../access_control/auth_provider/axios_instance"; import { validate_255, validate_required, validate_required_255 } from "../../commons/custom_validators"; import { AutocompleteInputMedium, AutocompleteInputWide, TextInputWide } from "../../commons/layout/themes"; import { CSAF_PUBLISHER_CATEGORY_CHOICES, CSAF_TLP_LABEL_CHOICES, CSAF_TRACKING_STATUS_CHOICES } from "../types"; diff --git a/frontend/src/vex/csaf/CSAFUpdate.tsx b/frontend/src/vex/csaf/CSAFUpdate.tsx index 48451849c..799926bbf 100644 --- a/frontend/src/vex/csaf/CSAFUpdate.tsx +++ b/frontend/src/vex/csaf/CSAFUpdate.tsx @@ -13,7 +13,7 @@ import { import { Fragment, useState } from "react"; import { SaveButton, SimpleForm, Toolbar, useNotify, useRefresh } from "react-admin"; -import axios_instance from "../../access_control/axios_instance"; +import axios_instance from "../../access_control/auth_provider/axios_instance"; import { validate_required, validate_required_255 } from "../../commons/custom_validators"; import { AutocompleteInputMedium, TextInputWide } from "../../commons/layout/themes"; import { CSAF_PUBLISHER_CATEGORY_CHOICES, CSAF_TLP_LABEL_CHOICES, CSAF_TRACKING_STATUS_CHOICES } from "../types"; diff --git a/frontend/src/vex/openvex/OpenVEXCreate.tsx b/frontend/src/vex/openvex/OpenVEXCreate.tsx index 51324020f..fe6ea0d9f 100644 --- a/frontend/src/vex/openvex/OpenVEXCreate.tsx +++ b/frontend/src/vex/openvex/OpenVEXCreate.tsx @@ -24,7 +24,7 @@ import { useRefresh, } from "react-admin"; -import axios_instance from "../../access_control/axios_instance"; +import axios_instance from "../../access_control/auth_provider/axios_instance"; import { validate_255, validate_required_255 } from "../../commons/custom_validators"; import { AutocompleteInputWide, TextInputWide } from "../../commons/layout/themes"; diff --git a/frontend/src/vex/openvex/OpenVEXUpdate.tsx b/frontend/src/vex/openvex/OpenVEXUpdate.tsx index ee3018554..5ad301b68 100644 --- a/frontend/src/vex/openvex/OpenVEXUpdate.tsx +++ b/frontend/src/vex/openvex/OpenVEXUpdate.tsx @@ -4,7 +4,7 @@ import { Backdrop, Button, CircularProgress, Dialog, DialogContent, DialogTitle, import { Fragment, useState } from "react"; import { SaveButton, SimpleForm, Toolbar, useNotify, useRefresh } from "react-admin"; -import axios_instance from "../../access_control/axios_instance"; +import axios_instance from "../../access_control/auth_provider/axios_instance"; import { validate_required_255 } from "../../commons/custom_validators"; import { TextInputWide } from "../../commons/layout/themes"; From 22939be5480a60a6221ed328a99a7eaedc85c6b7 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 21 Nov 2024 20:49:54 +0000 Subject: [PATCH 11/16] feat: import license groups from ScanCode LicenseDB data (#2244) * feat: import license groups from ScanCode LicenseDB data * chore: black and pylint * chore: amendment for documentation --- backend/application/licenses/api/views.py | 22 ++++++- .../licenses/services/license_group.py | 47 ++++++++++++++- .../access_control/api/test_authentication.py | 3 + .../api/test_authorization_license_groups.py | 25 ++++++++ .../images/secobserve_integrations.drawio | 24 ++++++-- .../assets/images/secobserve_integrations.svg | 2 +- docs/getting_started/features.md | 3 +- .../{spdx_licenses.md => license_data.md} | 10 +++- docs/usage/license_management.md | 2 +- .../ImportScanCodeLicenseDB.tsx | 60 +++++++++++++++++++ .../LicenseGroupEmbeddedList.tsx | 15 ++++- mkdocs.yml | 2 +- 12 files changed, 200 insertions(+), 15 deletions(-) rename docs/integrations/{spdx_licenses.md => license_data.md} (61%) create mode 100644 frontend/src/licenses/license_groups/ImportScanCodeLicenseDB.tsx diff --git a/backend/application/licenses/api/views.py b/backend/application/licenses/api/views.py index d4b0945f6..9c7b69fd0 100644 --- a/backend/application/licenses/api/views.py +++ b/backend/application/licenses/api/views.py @@ -86,7 +86,10 @@ get_license_policy_member, get_license_policy_members, ) -from application.licenses.services.license_group import copy_license_group +from application.licenses.services.license_group import ( + copy_license_group, + import_scancode_licensedb, +) from application.licenses.services.license_policy import ( apply_license_policy, copy_license_policy, @@ -259,6 +262,23 @@ def remove_license(self, request, pk): return Response(status=HTTP_204_NO_CONTENT) + @extend_schema( + methods=["POST"], + request=None, + responses={HTTP_204_NO_CONTENT: None}, + ) + @action(detail=False, methods=["post"]) + def import_scancode_licensedb(self, request): + user = request.user + if not user.is_superuser: + raise PermissionDenied( + "User is not allowed to import license groups from ScanCode LicenseDB" + ) + + import_scancode_licensedb() + + return Response(status=HTTP_204_NO_CONTENT) + class LicenseGroupMemberViewSet(ModelViewSet): serializer_class = LicenseGroupMemberSerializer diff --git a/backend/application/licenses/services/license_group.py b/backend/application/licenses/services/license_group.py index 870ff2ee2..b29c2378b 100644 --- a/backend/application/licenses/services/license_group.py +++ b/backend/application/licenses/services/license_group.py @@ -1,4 +1,8 @@ -from application.licenses.models import License_Group, License_Group_Member +from json import loads + +import requests + +from application.licenses.models import License, License_Group, License_Group_Member def copy_license_group(source_license_group: License_Group, name: str) -> License_Group: @@ -20,3 +24,44 @@ def copy_license_group(source_license_group: License_Group, name: str) -> Licens ) return new_license_group + + +def import_scancode_licensedb() -> None: + license_groups: dict[str, License_Group] = {} + + response = requests.get( + "https://scancode-licensedb.aboutcode.org/index.json", + timeout=60, + stream=True, + ) + response.raise_for_status() + data = loads(response.content) + + for db_license in data: + category = db_license.get("category") + spdx_license_key = db_license.get("spdx_license_key") + other_spdx_license_keys = db_license.get("other_spdx_license_keys", []) + + if category and spdx_license_key: + _add_license_to_group(license_groups, category, spdx_license_key) + for other_spdx_license_key in other_spdx_license_keys: + _add_license_to_group(license_groups, category, other_spdx_license_key) + + +def _add_license_to_group(license_groups, category, spdx_license_key): + try: + spdx_license = License.objects.get(spdx_id=spdx_license_key) + license_group = license_groups.get(category) + if not license_group: + license_group, _ = License_Group.objects.get_or_create( + name=f"{category} (ScanCode LicenseDB)", + description="Do not edit! " + + "Imported from [ScanCode LicenseDB](https://scancode-licensedb.aboutcode.org/) " + + "under the CC-BY-4.0 license.", + is_public=True, + ) + license_groups[category] = license_group + license_group.licenses.clear() + license_group.licenses.add(spdx_license) + except License.DoesNotExist: + pass diff --git a/backend/unittests/access_control/api/test_authentication.py b/backend/unittests/access_control/api/test_authentication.py index 842bada4c..5d1f5d443 100644 --- a/backend/unittests/access_control/api/test_authentication.py +++ b/backend/unittests/access_control/api/test_authentication.py @@ -328,6 +328,9 @@ def test_authentication(self, mock_user): self._check_authentication(["post"], "/api/license_groups/1/copy/") self._check_authentication(["post"], "/api/license_groups/1/add_license/") self._check_authentication(["post"], "/api/license_groups/1/remove_license/") + self._check_authentication( + ["post"], "/api/license_groups/import_scancode_licensedb/" + ) self._check_authentication(["get", "post"], "/api/license_group_members/") self._check_authentication( diff --git a/backend/unittests/access_control/api/test_authorization_license_groups.py b/backend/unittests/access_control/api/test_authorization_license_groups.py index e9745733f..a0f0ebdde 100644 --- a/backend/unittests/access_control/api/test_authorization_license_groups.py +++ b/backend/unittests/access_control/api/test_authorization_license_groups.py @@ -353,3 +353,28 @@ def test_authorization_license_groups(self): no_second_user=True, ) ) + + expected_data = "{'message': 'User is not allowed to import license groups from ScanCode LicenseDB'}" + self._test_api( + APITest( + "db_internal_write", + "post", + "/api/license_groups/import_scancode_licensedb/", + post_data, + 403, + expected_data, + no_second_user=True, + ) + ) + + self._test_api( + APITest( + "db_admin", + "post", + "/api/license_groups/import_scancode_licensedb/", + post_data, + 204, + None, + no_second_user=True, + ) + ) diff --git a/docs/assets/images/secobserve_integrations.drawio b/docs/assets/images/secobserve_integrations.drawio index c858cbf62..1bf73e796 100644 --- a/docs/assets/images/secobserve_integrations.drawio +++ b/docs/assets/images/secobserve_integrations.drawio @@ -123,7 +123,7 @@ - + @@ -138,7 +138,7 @@ - + @@ -160,16 +160,30 @@ - + - + - + + + + + + + + + + + + + + + diff --git a/docs/assets/images/secobserve_integrations.svg b/docs/assets/images/secobserve_integrations.svg index 01a9b5269..fb3ebd2d7 100644 --- a/docs/assets/images/secobserve_integrations.svg +++ b/docs/assets/images/secobserve_integrations.svg @@ -1,3 +1,3 @@ -
Export
Issues
Code link
Notifications
Microsoft Teams
Email
GitLab
CodeCharta
Microsoft Excel
CSV
Jira (Cloud)
Azure DevOps
Slack
NVD
Information
link
GitHub
GitHub
Advisories
open/source/
insights
CSAF  (VEX)
OpenVEX
Import/
Export
SecObserve
OpenID Connect
SPDX
Licenses
Open Source
Vulnerability
Scanners
Licenses
Vulnerabilities
Authentication
EPSS
Scores
\ No newline at end of file +
Export
Issues
Code link
Notifications
Microsoft Teams
Email
GitLab
CodeCharta
Microsoft Excel
CSV
Jira (Cloud)
Azure DevOps
Slack
NVD
Information
link
GitHub
GitHub
Advisories
open/source/
insights
CSAF  (VEX)
OpenVEX
Import/
Export
SecObserve
OpenID Connect
ScanCode
LicenseDB
Open Source
Vulnerability
Scanners
License
Groups
Vulnerabilities
Authentication
SPDX
Licenses
Scores
EPSS
Licenses
\ No newline at end of file diff --git a/docs/getting_started/features.md b/docs/getting_started/features.md index f230921a9..3ed7baa52 100644 --- a/docs/getting_started/features.md +++ b/docs/getting_started/features.md @@ -30,7 +30,8 @@ | [Import from many SAST, SCA, DAST, infrastructure and secrets scanners](../integrations/supported_scanners.md) | :material-plus-circle-outline: | | [GitLab CI integration of scanners with predefined templates](../integrations/github_actions_and_templates.md#examplary-pipeline-for-gitlab-ci-templates)
[GitHub integration of scanners with predefined actions](../integrations/github_actions_and_templates.md#examplary-workflow-for-github-actions) | :material-plus-circle-outline: | | [Data enrichment from Exploit Prediction Scoring System (EPSS)](../integrations/epss.md) | :material-plus-circle-outline: | -| [Always up-to-date SPDX licenses](../integrations/spdx_licenses.md) | :material-plus-circle-outline: | +| [Always up-to-date SPDX licenses](../integrations/license_data.md#spdx-licenses) | :material-plus-circle-outline: | +| [License groups generated from ScanCode LicenseDB data](../integrations/license_data.md#scancode-licensedb) | :material-plus-circle-outline: | | [Direct link to source code](../integrations/source_code_repositories.md) | :material-plus-circle-outline: | | [Export vulnerabilities to issue trackers (Jira, GitLab, GitHub)](../integrations/issue_trackers.md) | :material-plus-circle-outline: | | [Import/export vulnerabilities from/to VEX documents (CSAF, OpenVEX)](../integrations/vex.md) | :material-plus-circle-outline: | diff --git a/docs/integrations/spdx_licenses.md b/docs/integrations/license_data.md similarity index 61% rename from docs/integrations/spdx_licenses.md rename to docs/integrations/license_data.md index 4d7a1716e..1ddab5de9 100644 --- a/docs/integrations/spdx_licenses.md +++ b/docs/integrations/license_data.md @@ -1,11 +1,17 @@ -# SPDX licenses +# License data import + +## SPDX licenses The [Linux Foundation](https://www.linuxfoundation.org/) gathers a list of commonly found licenses and exceptions used for open source and other collaborative software. The list is called [SPDX License List](https://spdx.org/licenses/) and is imported daily into SecObserve from a JSON file hosted on GitHub. -## Configuration +### Configuration Per default the task to import the SPDX licenses is scheduled to run every night at 01:30 UTC time. This default can be changed by administrators via the [Settings](../getting_started/configuration.md#admininistration-in-secobserve). ![SPDX license import configuration](../assets/images/screenshot_spdx_license_import.png){ width="80%" style="display: block; margin: 0 auto" } Hour is always in UTC time. + +## ScanCode LicenseDB + +The [ScanCode LicenseDB](https://scancode-licensedb.aboutcode.org) is a free and open database of mostly all the software licenses, including a category per license. Administrators can import the data from the ScanCode LicenseDB with a button in the list of License Groups. License groups will be created or updated for each category, containing the respective SPDX licenses. diff --git a/docs/usage/license_management.md b/docs/usage/license_management.md index 00177a280..41454a622 100644 --- a/docs/usage/license_management.md +++ b/docs/usage/license_management.md @@ -9,7 +9,7 @@ License management is activated by default. If it is not used in an organization If license management is deactivated: * The `Licenses` menu is not visible in the navigation. -* The automatic import of SPDX licenses is deactivated. +* The [automatic import of SPDX licenses](../integrations/license_data.md#spdx-licenses) is deactivated. * Licenses for components are not imported from CycloneDX files and the `License` tab is not visible in the Product view. diff --git a/frontend/src/licenses/license_groups/ImportScanCodeLicenseDB.tsx b/frontend/src/licenses/license_groups/ImportScanCodeLicenseDB.tsx new file mode 100644 index 000000000..a7fcf997f --- /dev/null +++ b/frontend/src/licenses/license_groups/ImportScanCodeLicenseDB.tsx @@ -0,0 +1,60 @@ +import UploadIcon from "@mui/icons-material/Upload"; +import { Backdrop, CircularProgress } from "@mui/material"; +import { useState } from "react"; +import { Button, Confirm, useNotify, useRefresh } from "react-admin"; + +import { httpClient } from "../../commons/ra-data-django-rest-framework"; + +const ImportScanCodeLicenseDB = () => { + const [open, setOpen] = useState(false); + const [loading, setLoading] = useState(false); + const refresh = useRefresh(); + const notify = useNotify(); + const handleClick = () => setOpen(true); + const handleDialogClose = () => setOpen(false); + + const importScanCodeLicenseDB = async () => { + setLoading(true); + const url = window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_groups/import_scancode_licensedb/"; + httpClient(url, { + method: "POST", + }) + .then(() => { + refresh(); + setLoading(false); + notify("ScanCode LicenseDB imported", { type: "success" }); + }) + .catch((error) => { + setLoading(false); + notify(error.message, { type: "warning" }); + }); + + setOpen(false); + }; + + return ( + <> +