From 9edfa99674f352e3bd2ab61523377b3073fb3df5 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Fri, 22 Nov 2024 19:17:03 +0000 Subject: [PATCH 01/30] feat: show branch for licenses in product header (#2252) --- frontend/src/core/products/ProductHeader.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/core/products/ProductHeader.tsx b/frontend/src/core/products/ProductHeader.tsx index 2969907c5..402705d05 100644 --- a/frontend/src/core/products/ProductHeader.tsx +++ b/frontend/src/core/products/ProductHeader.tsx @@ -13,13 +13,20 @@ const ProductHeader = () => { const { data: product } = useGetOne("products", { id: id }); const { classes } = useStyles(); - function get_open_observation_label(product: Product | undefined) { + function get_open_observations_label(product: Product | undefined) { if (!product || product.repository_default_branch == null) { return "Open observations"; } return "Open observations (" + product.repository_default_branch_name + ")"; } + function get_licenses_label(product: Product | undefined) { + if (!product || product.repository_default_branch == null) { + return "Licenses"; + } + return "Licenses (" + product.repository_default_branch_name + ")"; + } + return ( { )} - + {product && product.forbidden_licenses_count + @@ -58,7 +65,7 @@ const ProductHeader = () => { product.ignored_licenses_count > 0 && ( - + )} From 33f8f7bc84690860ca4405f407b09ec09dc5658d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:23:28 +0100 Subject: [PATCH 02/30] chore(deps): update dependency typescript to v5.7.2 (#2254) 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 50360388d..97227bb03 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -54,7 +54,7 @@ "globals": "15.12.0", "prettier": "3.3.3", "rewire": "7.0.0", - "typescript": "5.6.3", + "typescript": "5.7.2", "vite": "5.4.11" } }, @@ -8873,9 +8873,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/frontend/package.json b/frontend/package.json index 00672fe39..7d8f4f899 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -63,7 +63,7 @@ "globals": "15.12.0", "prettier": "3.3.3", "rewire": "7.0.0", - "typescript": "5.6.3", + "typescript": "5.7.2", "vite": "5.4.11" } } From 45f70e0cfff3f3fcaf6d0aabd2ef6ef7607681c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:31:45 +0100 Subject: [PATCH 03/30] chore(deps): update maibornwolff/secobserve_actions_templates digest to 5476f0d (#2253) 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 57b58a048..3a9fadb08 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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 67c013166..95cc04697 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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 4a73470d8..373b5f0b0 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/importer@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/importer@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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 224e82fc9..9de1f74c3 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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 a6ba9db27..a25b3070c 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # 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@d15c2401857055841b487d2f25d4a9eb6c4f4ef2 # main + uses: MaibornWolff/secobserve_actions_templates/actions/vulnerability_scanner@5476f0de11c46875081d9767ec166c1e030e9ef0 # main with: so_configuration: 'so_configuration_endpoints.yml' SO_API_TOKEN: ${{ secrets.SO_API_TOKEN }} From e017d1db5f33c7a31d117e1255b00bd2e112b061 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Fri, 22 Nov 2024 20:44:27 +0000 Subject: [PATCH 04/30] chore: add missing dependency (#2255) --- frontend/package-lock.json | 324 ++++++++++++++++++------------------- frontend/package.json | 1 + 2 files changed, 161 insertions(+), 164 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 97227bb03..007340b4f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,6 +28,7 @@ "react-admin": "5.4.0", "react-chartjs-2": "5.2.0", "react-dom": "18.3.1", + "react-is": "18.3.1", "react-oidc-context": "3.2.0", "runtime-env-cra": "file:lib/runtime-env-cra", "tss-react": "4.9.13" @@ -1704,12 +1705,6 @@ } } }, - "node_modules/@mui/material/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, "node_modules/@mui/private-theming": { "version": "5.16.6", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", @@ -1853,12 +1848,6 @@ } } }, - "node_modules/@mui/utils/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2185,9 +2174,9 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.60.6", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.60.6.tgz", - "integrity": "sha512-FUzSDaiPkuZCmuGqrixfRRXJV9u+nrUh9lAlA5Q3ZFrOw1Js1VeBfxi1NIcJO3ZWJdKceBqKeBJdNcWStCYZnw==", + "version": "5.61.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.61.0.tgz", + "integrity": "sha512-SBzV27XAeCRBOQ8QcC94w2H1Md0+LI0gTWwc3qRJoaGuewKn5FNW4LSqwPFJZVEItfhMfGT7RpZuSFXjTi12pQ==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.60.6" @@ -2219,9 +2208,9 @@ } }, "node_modules/@tiptap/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.9.1.tgz", - "integrity": "sha512-tifnLL/ARzQ6/FGEJjVwj9UT3v+pENdWHdk9x6F3X0mB1y0SeCjV21wpFLYESzwNdBPAj8NMp8Behv7dBnhIfw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.10.2.tgz", + "integrity": "sha512-jYLXbYHTi1stLla/74J8NJizDtcJ/uokhG+1gN4DMWHDujaZOrRZhW98o9gN5BYAp4zv//TVX8H+afLZwKGCKQ==", "license": "MIT", "funding": { "type": "github", @@ -2232,9 +2221,9 @@ } }, "node_modules/@tiptap/extension-blockquote": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.9.1.tgz", - "integrity": "sha512-Y0jZxc/pdkvcsftmEZFyG+73um8xrx6/DMfgUcNg3JAM63CISedNcr+OEI11L0oFk1KFT7/aQ9996GM6Kubdqg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.10.2.tgz", + "integrity": "sha512-whmep+v0VvBI9Kg5TJ4sKIj7Z+MOjBKAndP0qn1bMoqPNNVRxt92iIud72wfXwfBNcrYiGNlssvsAnPwXfbG9w==", "license": "MIT", "funding": { "type": "github", @@ -2245,9 +2234,9 @@ } }, "node_modules/@tiptap/extension-bold": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.9.1.tgz", - "integrity": "sha512-e2P1zGpnnt4+TyxTC5pX/lPxPasZcuHCYXY0iwQ3bf8qRQQEjDfj3X7EI+cXqILtnhOiviEOcYmeu5op2WhQDg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.10.2.tgz", + "integrity": "sha512-1KNTXA8HDkhXblkfeRYDdqAu/Xz2fygyaSrvabrfzg5QVYyVYPNJwjrtfTQNyzWOejBVGE3mOyqnjlLUzPmyYA==", "license": "MIT", "funding": { "type": "github", @@ -2258,9 +2247,9 @@ } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.9.1.tgz", - "integrity": "sha512-DWUF6NG08/bZDWw0jCeotSTvpkyqZTi4meJPomG9Wzs/Ol7mEwlNCsCViD999g0+IjyXFatBk4DfUq1YDDu++Q==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.10.2.tgz", + "integrity": "sha512-KAh2bvYcixJ3RFv2P05kPNLAJ4uW6BDj1AfEMn0YguBWWTgZg8Kot1AzBRgTjBBFCInQS6b49db1ff4M07DGsg==", "license": "MIT", "dependencies": { "tippy.js": "^6.3.7" @@ -2275,9 +2264,9 @@ } }, "node_modules/@tiptap/extension-bullet-list": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.9.1.tgz", - "integrity": "sha512-0hizL/0j9PragJObjAWUVSuGhN1jKjCFnhLQVRxtx4HutcvS/lhoWMvFg6ZF8xqWgIa06n6A7MaknQkqhTdhKA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.10.2.tgz", + "integrity": "sha512-jXtTQXZ3j2cyG2dNyVnGauIbsX8CmDY56MJfDg1p+1UZ3zW2GVbKHfvyuulsjobxEd0DNLxduGqbkDY7x3I+HA==", "license": "MIT", "funding": { "type": "github", @@ -2288,9 +2277,9 @@ } }, "node_modules/@tiptap/extension-code": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.9.1.tgz", - "integrity": "sha512-WQqcVGe7i/E+yO3wz5XQteU1ETNZ00euUEl4ylVVmH2NM4Dh0KDjEhbhHlCM0iCfLUo7jhjC7dmS+hMdPUb+Tg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.10.2.tgz", + "integrity": "sha512-VV14oeOsJ3VqUEjuUl+lzSW/IBLhurmcj9IiN2sq/Voin04dwvtchqP5fNXgmM3+rFM88zNOsbX0e4uSG4R10w==", "license": "MIT", "funding": { "type": "github", @@ -2301,9 +2290,9 @@ } }, "node_modules/@tiptap/extension-code-block": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.9.1.tgz", - "integrity": "sha512-A/50wPWDqEUUUPhrwRKILP5gXMO5UlQ0F6uBRGYB9CEVOREam9yIgvONOnZVJtszHqOayjIVMXbH/JMBeq11/g==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.10.2.tgz", + "integrity": "sha512-Y/wkK9Ni4ALGqiGezov62p6cpPcJauBfn2wF1lgJVr6XJ4na5KTCUEbiyBZNbo3aD52vZKgWt8LpLvJ2/5STSw==", "license": "MIT", "funding": { "type": "github", @@ -2315,9 +2304,9 @@ } }, "node_modules/@tiptap/extension-color": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.9.1.tgz", - "integrity": "sha512-9h4FcCDenOmr8x8/Vfzg9PBYrgXIXTi2x8JiaTbrQX+Ufea1SMx+Ko/Vowp7SGMnBAsB+sXkTVhAhiXDQbtWcQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.10.2.tgz", + "integrity": "sha512-lIUrsk8XBG0h8ft5vU6u0ehPk0pcZK3xjhOLF/qxiGhZNBynX5/Nb7mez05J0/P6GKsD9Hj6UD7wm4ZkGmNT9A==", "license": "MIT", "funding": { "type": "github", @@ -2329,9 +2318,9 @@ } }, "node_modules/@tiptap/extension-document": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.9.1.tgz", - "integrity": "sha512-1a+HCoDPnBttjqExfYLwfABq8MYdiowhy/wp8eCxVb6KGFEENO53KapstISvPzqH7eOi+qRjBB1KtVYb/ZXicg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.10.2.tgz", + "integrity": "sha512-Xodp6rMg6vtKZkyX3I6gVd6OZ9PNz9udhDLdCG6JscVJQPO8viV++39UOH416FCvRT46BdHWNCRu/xjUG1C0rA==", "license": "MIT", "funding": { "type": "github", @@ -2342,9 +2331,9 @@ } }, "node_modules/@tiptap/extension-dropcursor": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.9.1.tgz", - "integrity": "sha512-wJZspSmJRkDBtPkzFz1g7gvZOEOayk8s93UHsgbJxcV4VWHYleZ5XhT74sZunSjefNDm3qC6v2BSgLp3vNHVKQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.10.2.tgz", + "integrity": "sha512-pzkD6Y9r3x4Mb6KqpuPraGNNfxIkQD6dJNtZ9PpU9jVtJDjsGIGdyzCbVJq984UAPBamXiF/5DLwlON7buLd6A==", "license": "MIT", "funding": { "type": "github", @@ -2356,9 +2345,9 @@ } }, "node_modules/@tiptap/extension-floating-menu": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.9.1.tgz", - "integrity": "sha512-MxZ7acNNsoNaKpetxfwi3Z11Bgrh0T2EJlCV77v9N1vWK38+st3H1WJanmLbPNtc2ocvhHJrz+DjDz3CWxQ9rQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.10.2.tgz", + "integrity": "sha512-s/KfW5YQY13BwhSQRlgomYmHuBT0k6FBxn8mgJLHcA9sTqgy/BriOhmNkMrredNzd4UOd5JVpcT6b+eckG4nkQ==", "license": "MIT", "dependencies": { "tippy.js": "^6.3.7" @@ -2373,9 +2362,9 @@ } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.9.1.tgz", - "integrity": "sha512-jsRBmX01vr+5H02GljiHMo0n5H1vzoMLmFarxe0Yq2d2l9G/WV2VWX2XnGliqZAYWd1bI0phs7uLQIN3mxGQTw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.10.2.tgz", + "integrity": "sha512-Uj2hIYC5zRPGI9xBYFwtld8JrZ8YZXEqO7sN5VcOwt12cnSmvzga86jUKpj3WOMP/8KamLWW8m8UKHd7Qg1kMA==", "license": "MIT", "funding": { "type": "github", @@ -2387,9 +2376,9 @@ } }, "node_modules/@tiptap/extension-hard-break": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.9.1.tgz", - "integrity": "sha512-fCuaOD/b7nDjm47PZ58oanq7y4ccS2wjPh42Qm0B0yipu/1fmC8eS1SmaXmk28F89BLtuL6uOCtR1spe+lZtlQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.10.2.tgz", + "integrity": "sha512-jEVKEe8I+Ai/qYjVf6Idg2Gpp1Cxn4O4twJ0MnlEdzoaEHgt/OTU5NO0PBZMpoe/4BkOvkETZmqRbrcGsapeYQ==", "license": "MIT", "funding": { "type": "github", @@ -2400,9 +2389,9 @@ } }, "node_modules/@tiptap/extension-heading": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.9.1.tgz", - "integrity": "sha512-SjZowzLixOFaCrV2cMaWi1mp8REK0zK1b3OcVx7bCZfVSmsOETJyrAIUpCKA8o60NwF7pwhBg0MN8oXlNKMeFw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.10.2.tgz", + "integrity": "sha512-OfvE+epZSyB0TbV5/4GdvRPMT1kd0fbgLUEaldWMZOLw/4eOGWZ8yXAtrWkoRMLZfOclgnDfwXvXJLnWXrDdDw==", "license": "MIT", "funding": { "type": "github", @@ -2413,9 +2402,9 @@ } }, "node_modules/@tiptap/extension-highlight": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.9.1.tgz", - "integrity": "sha512-ro3bARRgxb4v8w6fPVfG1kO2UWtLgKI5ESfsQ9CqiZuRkZdRKhM5ZpXPIky28Pn7CxhDUSXBXS/MhvP0VuhMJQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.10.2.tgz", + "integrity": "sha512-yJpqagUS672RPsGRc6JrNuqf3DbMiP+g4Al3cVpU3ff3yEORbCMsgvwkCOE9thSO9B4SOFQP4HzX2x1DLJtjew==", "license": "MIT", "funding": { "type": "github", @@ -2426,9 +2415,9 @@ } }, "node_modules/@tiptap/extension-history": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.9.1.tgz", - "integrity": "sha512-wp9qR1NM+LpvyLZFmdNaAkDq0d4jDJ7z7Fz7icFQPu31NVxfQYO3IXNmvJDCNu8hFAbImpA5aG8MBuwzRo0H9w==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.10.2.tgz", + "integrity": "sha512-Hr5cvYgOAP7vaRD5vbMjirTATFe/zYqnzePhq1c9TQESOi2o0zKxWpZIcHbFFIXCjHLSnpXOZ4yFwHP4k12rgg==", "license": "MIT", "funding": { "type": "github", @@ -2440,9 +2429,9 @@ } }, "node_modules/@tiptap/extension-horizontal-rule": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.9.1.tgz", - "integrity": "sha512-ydUhABeaBI1CoJp+/BBqPhXINfesp1qMNL/jiDcMsB66fsD4nOyphpAJT7FaRFZFtQVF06+nttBtFZVkITQVqg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.10.2.tgz", + "integrity": "sha512-DqaCUxjXnoVN/yylEjoGIlvKkT1KF8mwFJncJn8oSAukYEaSAK056ETvmyZk+/bzc3aRpfv0Kfn/zmLfHZ3wnA==", "license": "MIT", "funding": { "type": "github", @@ -2454,9 +2443,9 @@ } }, "node_modules/@tiptap/extension-image": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.9.1.tgz", - "integrity": "sha512-aGqJnsuS8oagIhsx7wetm8jw4NEDsOV0OSx4FQ4VPlUqWlnzK0N+erFKKJmXTdAxL8PGzoPSlITFH63MV3eV3Q==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.10.2.tgz", + "integrity": "sha512-xaJOVeR/fWozJMVKjYhskecsbayUUm1tIbjE+SyG7IW3Jp+081/W9z2nyfXG6YNnuVjYq+uLejR2Bt0cnEZvmA==", "license": "MIT", "funding": { "type": "github", @@ -2467,9 +2456,9 @@ } }, "node_modules/@tiptap/extension-italic": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.9.1.tgz", - "integrity": "sha512-VkNA6Vz96+/+7uBlsgM7bDXXx4b62T1fDam/3UKifA72aD/fZckeWrbT7KrtdUbzuIniJSbA0lpTs5FY29+86Q==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.10.2.tgz", + "integrity": "sha512-6p1YkJEWHuMROzNrK+GFJamujBswpydfR3ZMpIjQTLr4hRhSGrde/B5WODRDS+3JiK1xcN16ZQVPFsRJaHMjfQ==", "license": "MIT", "funding": { "type": "github", @@ -2480,9 +2469,9 @@ } }, "node_modules/@tiptap/extension-link": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.9.1.tgz", - "integrity": "sha512-yG+e3e8cCCN9dZjX4ttEe3e2xhh58ryi3REJV4MdiEkOT9QF75Bl5pUbMIS4tQ8HkOr04QBFMHKM12kbSxg1BA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.10.2.tgz", + "integrity": "sha512-bgsWdinDPGEiMD0NgphpKaxm4l9+PbPwdLDGDFyEX069VAyuSN4y63Sn32clpwlLcibVu3JxVFClJ+o6wKtmdg==", "license": "MIT", "dependencies": { "linkifyjs": "^4.1.0" @@ -2497,9 +2486,9 @@ } }, "node_modules/@tiptap/extension-list-item": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.9.1.tgz", - "integrity": "sha512-6O4NtYNR5N2Txi4AC0/4xMRJq9xd4+7ShxCZCDVL0WDVX37IhaqMO7LGQtA6MVlYyNaX4W1swfdJaqrJJ5HIUw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.10.2.tgz", + "integrity": "sha512-NE800m/QCk58MUcfeeCqmDjgOuiwHddaZvCCQIpErZdI2Y0io9RsSYU3HHEFPIfbKsv/ykVTYbwSweTPs1Tmxw==", "license": "MIT", "funding": { "type": "github", @@ -2510,9 +2499,9 @@ } }, "node_modules/@tiptap/extension-ordered-list": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.9.1.tgz", - "integrity": "sha512-6J9jtv1XP8dW7/JNSH/K4yiOABc92tBJtgCsgP8Ep4+fjfjdj4HbjS1oSPWpgItucF2Fp/VF8qg55HXhjxHjTw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.10.2.tgz", + "integrity": "sha512-1WYknf7/feouoBN7jW9Z6fvN9gzS1WRaOrDVkLZQ2ZLgT+Bs8H8/r1pv23q8Un6lg0mApwqnUxNhLOOrVyDkGQ==", "license": "MIT", "funding": { "type": "github", @@ -2523,9 +2512,9 @@ } }, "node_modules/@tiptap/extension-paragraph": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.9.1.tgz", - "integrity": "sha512-JOmT0xd4gd3lIhLwrsjw8lV+ZFROKZdIxLi0Ia05XSu4RLrrvWj0zdKMSB+V87xOWfSB3Epo95zAvnPox5Q16A==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.10.2.tgz", + "integrity": "sha512-EZG9W5rsU4uP585cIOrhbAPOUsgqrFbDrj1tZjTbvv0EWK03Un3FGYoGilkcUIxD9uB/XVHP+v2596Ifyi/dvQ==", "license": "MIT", "funding": { "type": "github", @@ -2536,9 +2525,9 @@ } }, "node_modules/@tiptap/extension-placeholder": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.9.1.tgz", - "integrity": "sha512-Q/w3OOg/C6jGBf4QKEWKF9k+iaCQCgPoaIg2IDTPx8QmaxRfgoVE5Csd+oTOY/brdmSNXOxykZWEci6OJP+MbA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.10.2.tgz", + "integrity": "sha512-QWzih69SetWYiylQzHsK29dMR8z1ParfcEw05hy3yyWqXE1DiKEot6rOGV1xenMVEA/SNGYYhQia15Bvco95TA==", "license": "MIT", "funding": { "type": "github", @@ -2550,9 +2539,9 @@ } }, "node_modules/@tiptap/extension-strike": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.9.1.tgz", - "integrity": "sha512-V5aEXdML+YojlPhastcu7w4biDPwmzy/fWq0T2qjfu5Te/THcqDmGYVBKESBm5x6nBy5OLkanw2O+KHu2quDdg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.10.2.tgz", + "integrity": "sha512-TjrBbO6UbXCt55hV9wRE7h5R/jLTB+z2yn2blz1TfR7wKkX3tJOnb+ptvIHEVFGJOjkZP6Xaj+aAkGVg5dKZYA==", "license": "MIT", "funding": { "type": "github", @@ -2563,9 +2552,9 @@ } }, "node_modules/@tiptap/extension-text": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.9.1.tgz", - "integrity": "sha512-3wo9uCrkLVLQFgbw2eFU37QAa1jq1/7oExa+FF/DVxdtHRS9E2rnUZ8s2hat/IWzvPUHXMwo3Zg2XfhoamQpCA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.10.2.tgz", + "integrity": "sha512-7WaJCmHAnf24gZc+Bl64vZgjAFt0CSEc5Jr+f3GII6XeCkZpTCJX85po2MFUhBRZMJheyctyL+UfsRauo/iP0Q==", "license": "MIT", "funding": { "type": "github", @@ -2576,9 +2565,9 @@ } }, "node_modules/@tiptap/extension-text-align": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.9.1.tgz", - "integrity": "sha512-oUp0XnwJpAImcOVV68vsY2CpkHpRZ3gzWfIRTuy+aYitQim3xDKis/qfWQUWZsANp9/TZ0VyjtkZxNMwOfcu1g==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.10.2.tgz", + "integrity": "sha512-eDvks4fUZuOuAhWD8/HJ070g2OQlEnBpak2+huvzPhGdYP81vhx5OWk/rfF6WzLzxLwnDND2zvk3YL+RBqERZQ==", "license": "MIT", "funding": { "type": "github", @@ -2589,9 +2578,9 @@ } }, "node_modules/@tiptap/extension-text-style": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.9.1.tgz", - "integrity": "sha512-LAxc0SeeiPiAVBwksczeA7BJSZb6WtVpYhy5Esvy9K0mK5kttB4KxtnXWeQzMIJZQbza65yftGKfQlexf/Y7yg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.10.2.tgz", + "integrity": "sha512-dWx5Ean7Rb6rdqO6C/i0qIIABKHFsABZj0mTDr0/ZXsw3V2O4d1cP13evvcc7HMLNAXziRTtWCVU6M06vwM/Pw==", "license": "MIT", "funding": { "type": "github", @@ -2602,9 +2591,9 @@ } }, "node_modules/@tiptap/extension-underline": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.9.1.tgz", - "integrity": "sha512-IrUsIqKPgD7GcAjr4D+RC0WvLHUDBTMkD8uPNEoeD1uH9t9zFyDfMRPnx/z3/6Gf6fTh3HzLcHGibiW2HiMi2A==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.10.2.tgz", + "integrity": "sha512-jDWGqqUYkrLgqRQDyqh+LpbkiqPfaWOoo5bydYL0u80GPEavovxZPoCJ/HDlOfdwm+FIPy55OP/29tELJRptmg==", "license": "MIT", "funding": { "type": "github", @@ -2615,29 +2604,29 @@ } }, "node_modules/@tiptap/pm": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.9.1.tgz", - "integrity": "sha512-mvV86fr7kEuDYEApQ2uMPCKL2uagUE0BsXiyyz3KOkY1zifyVm1fzdkscb24Qy1GmLzWAIIihA+3UHNRgYdOlQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.10.2.tgz", + "integrity": "sha512-jEgC79uvuEl51XxulutUJPSlhkoY0xQc9R/G4MQltAi+JxJ+KE/pOxgqziWNxBpgUzQqloupjod0kLhLUL4Cig==", "license": "MIT", "dependencies": { "prosemirror-changeset": "^2.2.1", "prosemirror-collab": "^1.3.1", - "prosemirror-commands": "^1.6.0", + "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-markdown": "^1.13.0", + "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", - "prosemirror-model": "^1.22.3", + "prosemirror-model": "^1.23.0", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.4.1", "prosemirror-state": "^1.4.3", - "prosemirror-tables": "^1.4.0", + "prosemirror-tables": "^1.6.1", "prosemirror-trailing-node": "^3.0.0", - "prosemirror-transform": "^1.10.0", - "prosemirror-view": "^1.34.3" + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.36.0" }, "funding": { "type": "github", @@ -2645,16 +2634,16 @@ } }, "node_modules/@tiptap/react": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.9.1.tgz", - "integrity": "sha512-LQJ34ZPfXtJF36SZdcn4Fiwsl2WxZ9YRJI87OLnsjJ45O+gV/PfBzz/4ap+LF8LOS0AbbGhTTjBOelPoNm+aYA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.10.2.tgz", + "integrity": "sha512-xBg0uA/ON9LbC8ojwjgFQgZA1xmaEotXZnZcM3tfGjCboqk0toi59v+2CIN9icDfW+UT/hsget3SBQtRw+SBEw==", "license": "MIT", "dependencies": { - "@tiptap/extension-bubble-menu": "^2.9.1", - "@tiptap/extension-floating-menu": "^2.9.1", + "@tiptap/extension-bubble-menu": "^2.10.2", + "@tiptap/extension-floating-menu": "^2.10.2", "@types/use-sync-external-store": "^0.0.6", "fast-deep-equal": "^3", - "use-sync-external-store": "^1.2.2" + "use-sync-external-store": "^1" }, "funding": { "type": "github", @@ -2663,37 +2652,37 @@ "peerDependencies": { "@tiptap/core": "^2.7.0", "@tiptap/pm": "^2.7.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@tiptap/starter-kit": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.9.1.tgz", - "integrity": "sha512-nsw6UF/7wDpPfHRhtGOwkj1ipIEiWZS1VGw+c14K61vM1CNj0uQ4jogbHwHZqN1dlL5Hh+FCqUHDPxG6ECbijg==", - "license": "MIT", - "dependencies": { - "@tiptap/core": "^2.9.1", - "@tiptap/extension-blockquote": "^2.9.1", - "@tiptap/extension-bold": "^2.9.1", - "@tiptap/extension-bullet-list": "^2.9.1", - "@tiptap/extension-code": "^2.9.1", - "@tiptap/extension-code-block": "^2.9.1", - "@tiptap/extension-document": "^2.9.1", - "@tiptap/extension-dropcursor": "^2.9.1", - "@tiptap/extension-gapcursor": "^2.9.1", - "@tiptap/extension-hard-break": "^2.9.1", - "@tiptap/extension-heading": "^2.9.1", - "@tiptap/extension-history": "^2.9.1", - "@tiptap/extension-horizontal-rule": "^2.9.1", - "@tiptap/extension-italic": "^2.9.1", - "@tiptap/extension-list-item": "^2.9.1", - "@tiptap/extension-ordered-list": "^2.9.1", - "@tiptap/extension-paragraph": "^2.9.1", - "@tiptap/extension-strike": "^2.9.1", - "@tiptap/extension-text": "^2.9.1", - "@tiptap/extension-text-style": "^2.9.1", - "@tiptap/pm": "^2.9.1" + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.10.2.tgz", + "integrity": "sha512-YbS9P3zvLhfEWnCPMcvCwK/+3XjMgZX73D1qMu9jVRHtQGI2DMk9u42KWAMLQAMBUESMcIeGxJ9G5IWJO0PsyA==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^2.10.2", + "@tiptap/extension-blockquote": "^2.10.2", + "@tiptap/extension-bold": "^2.10.2", + "@tiptap/extension-bullet-list": "^2.10.2", + "@tiptap/extension-code": "^2.10.2", + "@tiptap/extension-code-block": "^2.10.2", + "@tiptap/extension-document": "^2.10.2", + "@tiptap/extension-dropcursor": "^2.10.2", + "@tiptap/extension-gapcursor": "^2.10.2", + "@tiptap/extension-hard-break": "^2.10.2", + "@tiptap/extension-heading": "^2.10.2", + "@tiptap/extension-history": "^2.10.2", + "@tiptap/extension-horizontal-rule": "^2.10.2", + "@tiptap/extension-italic": "^2.10.2", + "@tiptap/extension-list-item": "^2.10.2", + "@tiptap/extension-ordered-list": "^2.10.2", + "@tiptap/extension-paragraph": "^2.10.2", + "@tiptap/extension-strike": "^2.10.2", + "@tiptap/extension-text": "^2.10.2", + "@tiptap/extension-text-style": "^2.10.2", + "@tiptap/pm": "^2.10.2" }, "funding": { "type": "github", @@ -3901,9 +3890,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001680", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", - "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "version": "1.0.30001683", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", + "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", "dev": true, "funding": [ { @@ -4808,9 +4797,9 @@ "license": "(MPL-2.0 OR Apache-2.0)" }, "node_modules/electron-to-chromium": { - "version": "1.5.63", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", - "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", + "version": "1.5.64", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", + "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==", "dev": true, "license": "ISC" }, @@ -5838,6 +5827,12 @@ "react-is": "^16.7.0" } }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -7255,6 +7250,12 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/prosemirror-changeset": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz", @@ -7574,12 +7575,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ra-core/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, "node_modules/ra-core/node_modules/split-on-first": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", @@ -7824,9 +7819,9 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/react-oidc-context": { @@ -8831,9 +8826,9 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", + "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", "dev": true, "license": "MIT", "dependencies": { @@ -8842,7 +8837,8 @@ "for-each": "^0.3.3", "gopd": "^1.0.1", "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.13", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" diff --git a/frontend/package.json b/frontend/package.json index 7d8f4f899..ce6cfcbce 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "react-admin": "5.4.0", "react-chartjs-2": "5.2.0", "react-dom": "18.3.1", + "react-is": "18.3.1", "react-oidc-context": "3.2.0", "runtime-env-cra": "file:lib/runtime-env-cra", "tss-react": "4.9.13" From da260cd49fbd3b64edb371d347189030db0a396b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 08:52:38 +0100 Subject: [PATCH 05/30] chore(deps): update postgres docker tag to v15.10 (#2256) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose-dev-keycloak.yml | 2 +- docker-compose-dev.yml | 2 +- docker-compose-prod-postgres.yml | 2 +- docker-compose-prod-test.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose-dev-keycloak.yml b/docker-compose-dev-keycloak.yml index f33de6bcf..674bc5984 100644 --- a/docker-compose-dev-keycloak.yml +++ b/docker-compose-dev-keycloak.yml @@ -66,7 +66,7 @@ services: command: /start postgres: - image: postgres:15.9-alpine + image: postgres:15.10-alpine volumes: - dev_postgres_data:/var/lib/postgresql/data environment: diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 488fbcde2..febbba8f7 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -50,7 +50,7 @@ services: command: /start postgres: - image: postgres:15.9-alpine + image: postgres:15.10-alpine volumes: - dev_postgres_data:/var/lib/postgresql/data environment: diff --git a/docker-compose-prod-postgres.yml b/docker-compose-prod-postgres.yml index 406a66f7b..31f0641a1 100644 --- a/docker-compose-prod-postgres.yml +++ b/docker-compose-prod-postgres.yml @@ -96,7 +96,7 @@ services: - database postgres: - image: postgres:15.9-alpine + image: postgres:15.10-alpine container_name: "prod_postgres" environment: POSTGRES_DB: ${SO_POSTGRES_DB:-secobserve} diff --git a/docker-compose-prod-test.yml b/docker-compose-prod-test.yml index 6529228e0..666787302 100644 --- a/docker-compose-prod-test.yml +++ b/docker-compose-prod-test.yml @@ -76,7 +76,7 @@ services: - "3306:3306" postgres: - image: postgres:15.9-alpine + image: postgres:15.10-alpine environment: POSTGRES_DB: ${SO_POSTGRES_DB:-secobserve} POSTGRES_USER: ${SO_POSTGRES_USER:-secobserve} From 3d021399463b30f161bbbea29aefcfe65fe874f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 09:06:53 +0100 Subject: [PATCH 06/30] chore(deps): update dependency @types/node to v22.9.3 (#2257) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- end_to_end_tests/package-lock.json | 8 ++++---- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index 95741b5e8..62cb3bf3a 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -9,7 +9,7 @@ "version": "1.22.4", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.9.1" + "@types/node": "22.9.3" } }, "node_modules/@playwright/test": { @@ -29,9 +29,9 @@ } }, "node_modules/@types/node": { - "version": "22.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", - "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==", + "version": "22.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", + "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index 61032471a..f01a84474 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -9,6 +9,6 @@ "author": "", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.9.1" + "@types/node": "22.9.3" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 007340b4f..cd68e8202 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,7 +40,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.9.1", + "@types/node": "22.9.3", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", @@ -3188,9 +3188,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", - "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==", + "version": "22.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", + "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index ce6cfcbce..b1c9d3a30 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.9.1", + "@types/node": "22.9.3", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", From ad2ef6cef70b806a984cdaa679ba56333f299f39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 09:40:39 +0100 Subject: [PATCH 07/30] fix(deps): update dependency coverage to v7.6.8 (#2258) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- backend/poetry.lock | 128 ++++++++++++++++++++--------------------- backend/pyproject.toml | 2 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index f5748647d..8e5f1f662 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -413,73 +413,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.7" +version = "7.6.8" description = "Code coverage measurement for Python" optional = true python-versions = ">=3.9" files = [ - {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, - {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, - {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, - {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, - {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, - {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, - {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, - {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, - {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, - {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, - {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, - {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, - {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, - {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, - {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, - {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed"}, + {file = "coverage-7.6.8-cp310-cp310-win32.whl", hash = "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e"}, + {file = "coverage-7.6.8-cp310-cp310-win_amd64.whl", hash = "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0"}, + {file = "coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801"}, + {file = "coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443"}, + {file = "coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad"}, + {file = "coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b"}, + {file = "coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146"}, + {file = "coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b"}, + {file = "coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71"}, + {file = "coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea"}, + {file = "coverage-7.6.8-cp39-cp39-win32.whl", hash = "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e"}, + {file = "coverage-7.6.8-cp39-cp39-win_amd64.whl", hash = "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076"}, + {file = "coverage-7.6.8-pp39.pp310-none-any.whl", hash = "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce"}, + {file = "coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc"}, ] [package.extras] @@ -2514,4 +2514,4 @@ unittests = ["coverage", "django-coverage-plugin", "django-extensions"] [metadata] lock-version = "2.0" python-versions = ">= 3.10, < 3.13" -content-hash = "5d536e3e82478f21e54951965cef9fa95a00778d07152ff3746676b73ea4feda" +content-hash = "a635c50582dc36e143d45233e64fe5d7f69d3bae7f460bd4a3274daf2f752de1" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 2dab3daca..da0faa036 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -70,7 +70,7 @@ django-extensions = { version = "3.2.3", optional = true } # https://github.com # Unittest dependencies # ------------------------------------------------------------------------------ -coverage = { version = "7.6.7", optional = true } # https://github.com/nedbat/coveragepy +coverage = { version = "7.6.8", optional = true } # https://github.com/nedbat/coveragepy django-coverage-plugin = { version = "3.1.0", optional = true } # https://github.com/nedbat/django_coverage_plugin # Code quality dependencies From 736d8ce7eb1e44a363701b327f04ccc0d4ff849b Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Sun, 24 Nov 2024 13:40:50 +0000 Subject: [PATCH 08/30] feat: license component overview list (#2259) * feat: license component overview list * chore: prettier and eslint * fix: sortable optional * fix: embedded list for branch names * feat: label for radio buttons --- backend/application/licenses/api/filters.py | 36 ++- .../application/licenses/api/serializers.py | 14 ++ backend/application/licenses/api/views.py | 120 +++++++++- .../licenses/queries/license_component.py | 33 ++- .../custom_fields/EvaluationResultField.tsx | 3 +- .../observations/ObservationEmbeddedList.tsx | 1 + frontend/src/core/products/ProductShow.tsx | 35 ++- .../LicenseComponentEmbeddedList.tsx | 141 ++++++++---- .../LicenseComponentOverview.tsx | 216 ++++++++++++++++++ .../LicenseComponentShow.tsx | 7 + 10 files changed, 540 insertions(+), 66 deletions(-) create mode 100644 frontend/src/licenses/license_components/LicenseComponentOverview.tsx diff --git a/backend/application/licenses/api/filters.py b/backend/application/licenses/api/filters.py index 912021b2a..b1f17d61b 100644 --- a/backend/application/licenses/api/filters.py +++ b/backend/application/licenses/api/filters.py @@ -2,6 +2,7 @@ from django.utils import timezone from django_filters import ( + BooleanFilter, CharFilter, ChoiceFilter, FilterSet, @@ -28,10 +29,33 @@ class LicenseComponentFilter(FilterSet): name_version = CharFilter(field_name="name_version", lookup_expr="icontains") license_spdx_id = CharFilter(field_name="license__spdx_id", lookup_expr="icontains") + license_spdx_id_exact = CharFilter(field_name="license__spdx_id") unknown_license = CharFilter(field_name="unknown_license", lookup_expr="icontains") + unknown_license_exact = CharFilter(field_name="unknown_license") age = ChoiceFilter( field_name="age", method="get_age", choices=Age_Choices.AGE_CHOICES ) + no_license = BooleanFilter(field_name="no_license", method="get_no_license") + branch_name = CharFilter(field_name="branch__name") + + def get_age(self, queryset, field_name, value): # pylint: disable=unused-argument + # field_name is used as a positional argument + + days = Age_Choices.get_days_from_age(value) + + if days is None: + return queryset + + today = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0) + time_threshold = today - timedelta(days=int(days)) + return queryset.filter(last_change__gte=time_threshold) + + def get_no_license( + self, queryset, field_name, value + ): # pylint: disable=unused-argument + if value is True: + return queryset.filter(license=None, unknown_license="") + return queryset ordering = ExtendedOrderingFilter( # tuple-mapping retains order @@ -66,18 +90,6 @@ class Meta: "purl_type", ] - def get_age(self, queryset, field_name, value): # pylint: disable=unused-argument - # field_name is used as a positional argument - - days = Age_Choices.get_days_from_age(value) - - if days is None: - return queryset - - today = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0) - time_threshold = today - timedelta(days=int(days)) - return queryset.filter(last_change__gte=time_threshold) - class LicenseComponentEvidenceFilter(FilterSet): name = CharFilter(field_name="name", lookup_expr="icontains") diff --git a/backend/application/licenses/api/serializers.py b/backend/application/licenses/api/serializers.py index ae5364da7..8c52c02d8 100644 --- a/backend/application/licenses/api/serializers.py +++ b/backend/application/licenses/api/serializers.py @@ -166,6 +166,20 @@ class LicenseComponentBulkDeleteSerializer(Serializer): ) +class LicenseComponentOverviewElementSerializer(Serializer): + branch_name = CharField() + spdx_id = CharField() + license_name = CharField() + unknown_license = CharField() + evaluation_result = CharField() + num_components = IntegerField() + + +class LicenseComponentOverviewSerializer(Serializer): + count = IntegerField() + results = ListField(child=LicenseComponentOverviewElementSerializer()) + + class LicenseGroupSerializer(ModelSerializer): is_manager = SerializerMethodField() is_in_license_policy = SerializerMethodField() diff --git a/backend/application/licenses/api/views.py b/backend/application/licenses/api/views.py index 9c7b69fd0..c6399f912 100644 --- a/backend/application/licenses/api/views.py +++ b/backend/application/licenses/api/views.py @@ -1,14 +1,22 @@ +from dataclasses import dataclass +from typing import Optional + from django_filters.rest_framework import DjangoFilterBackend -from drf_spectacular.utils import extend_schema +from drf_spectacular.utils import OpenApiParameter, extend_schema from rest_framework.decorators import action from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError from rest_framework.filters import SearchFilter from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from rest_framework.status import HTTP_201_CREATED, HTTP_204_NO_CONTENT +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT from rest_framework.viewsets import GenericViewSet, ModelViewSet +from application.access_control.services.authorization import user_has_permission_or_403 +from application.access_control.services.roles_permissions import Permissions +from application.core.models import Branch, Product +from application.core.queries.branch import get_branch_by_id +from application.core.queries.product import get_product_by_id from application.licenses.api.filters import ( LicenseComponentEvidenceFilter, LicenseComponentFilter, @@ -33,6 +41,7 @@ LicenseComponentEvidenceSerializer, LicenseComponentIdSerializer, LicenseComponentListSerializer, + LicenseComponentOverviewSerializer, LicenseComponentSerializer, LicenseGroupAuthorizationGroupMemberSerializer, LicenseGroupCopySerializer, @@ -59,7 +68,10 @@ License_Policy_Member, ) from application.licenses.queries.license import get_license -from application.licenses.queries.license_component import get_license_components +from application.licenses.queries.license_component import ( + get_license_component_licenses, + get_license_components, +) from application.licenses.queries.license_component_evidence import ( get_license_component_evidences, ) @@ -96,6 +108,22 @@ ) +@dataclass +class LicenseComponentOverviewElement: + branch_name: Optional[str] + spdx_id: Optional[str] + license_name: Optional[str] + unknown_license: Optional[str] + evaluation_result: str + num_components: int + + +@dataclass +class LicenseComponentOverview: + count: int + results: list[LicenseComponentOverviewElement] + + class LicenseComponentViewSet(GenericViewSet, ListModelMixin, RetrieveModelMixin): serializer_class = LicenseComponentSerializer filterset_class = LicenseComponentFilter @@ -112,6 +140,92 @@ def get_queryset(self): get_license_components().select_related("branch").select_related("license") ) + @extend_schema( + methods=["GET"], + responses={200: LicenseComponentOverviewSerializer}, + parameters=[ + OpenApiParameter(name="product", type=int, required=True), + OpenApiParameter(name="branch", type=int), + ], + ) + @action(detail=False, methods=["get"]) + def license_overview(self, request): + product_id = request.query_params.get("product") + if not product_id: + raise ValidationError("No product id provided") + product = self.__get_product(product_id) + branch = self.__get_branch(product, request.query_params.get("branch")) + spdx_id = request.query_params.get("spdx_id") + unknown_license = request.query_params.get("unknown_license") + evaluation_result = request.query_params.get("evaluation_result") + purl_type = request.query_params.get("purl_type") + + license_overview_elements = get_license_component_licenses(product, branch) + if spdx_id: + license_overview_elements = license_overview_elements.filter( + license__spdx_id__icontains=spdx_id + ) + if unknown_license: + license_overview_elements = license_overview_elements.filter( + unknown_license__icontains=unknown_license + ) + if evaluation_result: + license_overview_elements = license_overview_elements.filter( + evaluation_result=evaluation_result + ) + if purl_type: + license_overview_elements = license_overview_elements.filter( + purl_type=purl_type + ) + + results = [] + for element in license_overview_elements: + license_component_overview_element = LicenseComponentOverviewElement( + branch_name=element["branch__name"], + spdx_id=element["license__spdx_id"], + license_name=element["license__name"], + unknown_license=element["unknown_license"], + evaluation_result=element["evaluation_result"], + num_components=element["id__count"], + ) + results.append(license_component_overview_element) + + license_overview = LicenseComponentOverview( + count=len(results), + results=results, + ) + + response_serializer = LicenseComponentOverviewSerializer(license_overview) + + return Response( + status=HTTP_200_OK, + data=response_serializer.data, + ) + + def __get_product(self, pk: int) -> Product: + if not pk: + raise ValidationError("No product id provided") + + product = get_product_by_id(pk) + if not product: + raise NotFound() + + user_has_permission_or_403(product, Permissions.Product_View) + + return product + + def __get_branch(self, product: Product, pk: int) -> Optional[Branch]: + if not pk: + return None + + branch = get_branch_by_id(product, pk) + if not branch: + raise NotFound() + + user_has_permission_or_403(branch, Permissions.Branch_View) + + return branch + class LicenseComponentIdViewSet(GenericViewSet, ListModelMixin, RetrieveModelMixin): serializer_class = LicenseComponentIdSerializer diff --git a/backend/application/licenses/queries/license_component.py b/backend/application/licenses/queries/license_component.py index c2598b394..780df0fb7 100644 --- a/backend/application/licenses/queries/license_component.py +++ b/backend/application/licenses/queries/license_component.py @@ -1,8 +1,15 @@ -from django.db.models import Exists, OuterRef, Q +from typing import Optional + +from django.db.models import Count, Exists, OuterRef, Q from django.db.models.query import QuerySet from application.commons.services.global_request import get_current_user -from application.core.models import Product_Authorization_Group_Member, Product_Member +from application.core.models import ( + Branch, + Product, + Product_Authorization_Group_Member, + Product_Member, +) from application.licenses.models import License_Component @@ -57,3 +64,25 @@ def get_license_components() -> QuerySet[License_Component]: ) return components + + +def get_license_component_licenses( + product: Product, branch: Optional[Branch] +) -> QuerySet: + license_components = get_license_components().filter( + product=product, + ) + if branch: + license_components = license_components.filter(branch=branch) + + return ( + license_components.values( + "branch__name", + "license__spdx_id", + "license__name", + "unknown_license", + "evaluation_result", + ) + .annotate(Count("id")) + .order_by("numerical_evaluation_result", "license__spdx_id", "unknown_license") + ) diff --git a/frontend/src/commons/custom_fields/EvaluationResultField.tsx b/frontend/src/commons/custom_fields/EvaluationResultField.tsx index 118aa2d2c..ef2b3cd6b 100644 --- a/frontend/src/commons/custom_fields/EvaluationResultField.tsx +++ b/frontend/src/commons/custom_fields/EvaluationResultField.tsx @@ -5,6 +5,7 @@ import { get_evaluation_result_color } from "../functions"; interface EvaluationResultProps { source: string; label: string; + sortable?: boolean; } export const EvaluationResultField = (props: EvaluationResultProps) => { @@ -12,7 +13,7 @@ export const EvaluationResultField = (props: EvaluationResultProps) => { return record ? ( if (current_product_id == null || Number(current_product_id) !== product.id) { localStorage.removeItem("RaStore.observations.embedded"); localStorage.removeItem("RaStore.license_components.embedded"); + localStorage.removeItem("RaStore.license_components.overview"); localStorage.setItem("observationembeddedlist.product", product.id); navigate(get_observations_url(product.repository_default_branch)); } diff --git a/frontend/src/core/products/ProductShow.tsx b/frontend/src/core/products/ProductShow.tsx index c90311d73..bd6920ce2 100644 --- a/frontend/src/core/products/ProductShow.tsx +++ b/frontend/src/core/products/ProductShow.tsx @@ -13,7 +13,9 @@ import { Fragment, useState } from "react"; import { EditButton, PrevNextButtons, + RadioButtonGroupInput, Show, + SimpleForm, Tab, TabbedShowLayout, TabbedShowLayoutTabs, @@ -44,6 +46,7 @@ import ApiConfigurationEmbeddedList from "../../import_observations/api_configur import ImportMenu from "../../import_observations/import/ImportMenu"; import VulnerabilityCheckEmbeddedList from "../../import_observations/vulnerability_checks/VulnerabilityCheckEmbeddedList"; import LicenseComponentEmbeddedList from "../../licenses/license_components/LicenseComponentEmbeddedList"; +import LicenseComponentOverview from "../../licenses/license_components/LicenseComponentOverview"; import MetricsHeader from "../../metrics/MetricsHeader"; import MetricsSeveritiesCurrent from "../../metrics/MetricsSeveritiesCurrent"; import MetricsSeveritiesTimeline from "../../metrics/MetricsSeveritiesTimeLine"; @@ -95,6 +98,7 @@ const ShowActions = (props: ShowActionsProps) => { }; const ProductShow = () => { + const [licenseViewState, setLicenseViewState] = useState("detail"); // eslint-disable-line @typescript-eslint/no-unused-vars const [settingsTabsShow, setSettingsTabsShow] = useState(false); const [tabs_changed, setTabsChanged] = useState(false); function showSettingsTabs() { @@ -119,6 +123,20 @@ const ProductShow = () => { } const settingsLabel = settingsTabsShow ? "Settings" : "Settings >>>"; + const licenseView = (): string => { + const license_view_storage = localStorage.getItem("license_view"); + if (license_view_storage === null) { + return "detail"; + } + setLicenseViewState(license_view_storage); + return license_view_storage; + }; + + const setLicenseView = (value: string) => { + localStorage.setItem("license_view", value); + setLicenseViewState(value); + }; + let filter = {}; let storeKey = "products.list"; @@ -231,7 +249,22 @@ const ProductShow = () => { )} {feature_license_management() && product.has_licenses && ( } onClick={hideSettingsTabs}> - + + setLicenseView(e.target.value)} + /> + {licenseView() === "detail" && ( + + )} + {licenseView() === "overview" && } + )} { - return "../../../../license_components/" + id + "/show"; -}; - -function listFilters(product: any) { - const filters = []; - if (product && product.has_branches) { - filters.push( - - - - ); - } - filters.push(); - filters.push(); - filters.push( - - ); - filters.push(); - filters.push(); - filters.push(); - - return filters; -} - type LicenseComponentEmbeddedListProps = { product: any; + expand?: boolean; + purl_type?: string; }; const BulkActionButtons = (product: any) => ( @@ -72,15 +39,83 @@ const BulkActionButtons = (product: any) => ( ); -const LicenseComponentEmbeddedList = ({ product }: LicenseComponentEmbeddedListProps) => { +const LicenseComponentEmbeddedList = ({ product, expand, purl_type }: LicenseComponentEmbeddedListProps) => { + const showLicenseComponent = (id: any) => { + return "../../../../license_components/" + id + "/show"; + }; + + function listFilters() { + const filters = []; + if (product && product.has_branches) { + filters.push( + + + + ); + } + filters.push(); + filters.push(); + filters.push( + + ); + filters.push(); + filters.push( + + ); + filters.push(); + + return filters; + } + + let filter: any = { product: Number(product.id) }; + let storeKey: any = "license_components.embedded"; + let filterDefaultValues: any = {}; + + const record = useRecordContext(); + if (expand) { + if (record && record.branch_name) { + filter = { ...filter, branch_name: record.branch_name }; + } + if (record && !record.spdx_id && !record.unknown_license) { + filter = { ...filter, no_license: true }; + } + if (record && record.spdx_id) { + filter = { ...filter, license_spdx_id_exact: record.spdx_id }; + } + if (record && record.unknown_license) { + filter = { ...filter, unknown_license_exact: record.unknown_license }; + } + if (record && record.evaluation_result) { + filter = { ...filter, evaluation_result: record.evaluation_result }; + } + if (purl_type) { + filter = { ...filter, purl_type: purl_type }; + } + storeKey = false; + } else { + filterDefaultValues = { branch: product.repository_default_branch }; + } + const listContext = useListController({ - filter: { product: Number(product.id) }, + filter: filter, perPage: 25, resource: "license_components", sort: { field: "evaluation_result", order: "ASC" }, - filterDefaultValues: { branch: product.repository_default_branch }, + filterDefaultValues: filterDefaultValues, disableSyncWithLocation: true, - storeKey: "license_components.embedded", + storeKey: storeKey, }); if (listContext.isLoading) { @@ -91,7 +126,7 @@ const LicenseComponentEmbeddedList = ({ product }: LicenseComponentEmbeddedListP
- + {!expand && } - {product && product.has_branches && } - - - + {!expand && product && product.has_branches && ( + + )} + {!expand && } + {!expand && } + {!expand && ( + + )} (record ? humanReadableDate(record.last_change) : "")} /> - + ( + {((expand && total && total > 25) || !expand) && } + )} + />
diff --git a/frontend/src/licenses/license_components/LicenseComponentOverview.tsx b/frontend/src/licenses/license_components/LicenseComponentOverview.tsx new file mode 100644 index 000000000..9759e6f67 --- /dev/null +++ b/frontend/src/licenses/license_components/LicenseComponentOverview.tsx @@ -0,0 +1,216 @@ +import { Paper } from "@mui/material"; +import { useEffect, useState } from "react"; +import { + AutocompleteInput, + Datagrid, + FilterForm, + ListContextProvider, + NumberField, + ReferenceInput, + ResourceContextProvider, + TextField, + TextInput, + useList, + useNotify, +} from "react-admin"; + +import { EvaluationResultField } from "../../commons/custom_fields/EvaluationResultField"; +import { AutocompleteInputMedium } from "../../commons/layout/themes"; +import { httpClient } from "../../commons/ra-data-django-rest-framework"; +import { getSettingListSize } from "../../commons/user_settings/functions"; +import { PURL_TYPE_CHOICES } from "../../core/types"; +import { EVALUATION_RESULT_CHOICES } from "../types"; +import LicenseComponentEmbeddedList from "./LicenseComponentEmbeddedList"; + +type LicenseComponentOverviewProps = { + product: any; +}; + +const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => { + const [data, setData] = useState(); + const [count, setCount] = useState(0); + const [loading, setLoading] = useState(false); + const [filterBranch, setFilterBranch] = useState(undefined); + const [filterSPDXId, setFilterSPDXId] = useState(undefined); + const [filterUnknownLicense, setFilterUnknownLicense] = useState(undefined); + const [filterEvaluationResult, setFilterEvaluationResult] = useState(undefined); + const [filterPURLType, setFilterPURLType] = useState(undefined); + const notify = useNotify(); + + function listFilters(product: any) { + const filters = []; + if (product && product.has_branches) { + filters.push( + + setFilterBranch(e)} + /> + + ); + } + filters.push( + setFilterSPDXId(e.target.value)} alwaysOn /> + ); + filters.push( + setFilterUnknownLicense(e.target.value)} + alwaysOn + /> + ); + filters.push( + setFilterEvaluationResult(e)} + alwaysOn + /> + ); + filters.push( + setFilterPURLType(e)} + alwaysOn + /> + ); + return filters; + } + + useEffect(() => { + if (filterBranch === undefined) { + const storedFilters = localStorage.getItem("RaStore.license_components.overview"); + if (storedFilters) { + const filters = JSON.parse(storedFilters); + setFilterBranch(filters.branch); + setFilterSPDXId(filters.spdx_id); + setFilterUnknownLicense(filters.unknown_license); + setFilterEvaluationResult(filters.evaluation_result); + setFilterPURLType(filters.purl_type); + } else { + setFilterBranch(product.repository_default_branch); + } + } else { + localStorage.removeItem("RaStore.license_components.datagrid.expanded"); + get_data(); + } + }, [filterBranch, filterSPDXId, filterUnknownLicense, filterEvaluationResult, filterPURLType]); // eslint-disable-line react-hooks/exhaustive-deps + + function storeFilters() { + const filterStorage = { + branch: filterBranch, + spdx_id: filterSPDXId, + unknown_license: filterUnknownLicense, + evaluation_result: filterEvaluationResult, + purl_type: filterPURLType, + }; + localStorage.setItem("RaStore.license_components.overview", JSON.stringify(filterStorage)); + } + + function get_data() { + setLoading(true); + + let url = + window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_components/license_overview/?product=" + product.id; + if (filterBranch) { + url += "&branch=" + filterBranch; + } + if (filterSPDXId) { + url += "&spdx_id=" + encodeURIComponent(filterSPDXId); + } + if (filterUnknownLicense) { + url += "&unknown_license=" + encodeURIComponent(filterUnknownLicense); + } + if (filterEvaluationResult) { + url += "&evaluation_result=" + encodeURIComponent(filterEvaluationResult); + } + if (filterPURLType) { + url += "&purl_type=" + encodeURIComponent(filterPURLType); + } + + httpClient(url, { + method: "GET", + }) + .then((result: any) => { + setCount(result.json.count); + setData(result.json.results); + }) + .catch((error: any) => { + if (error !== undefined) { + notify(error.message, { + type: "warning", + }); + } else { + notify("Error while loading metrics status", { + type: "warning", + }); + } + }); + + storeFilters(); + setLoading(false); + } + + const listContext = useList({ + data, + isLoading: loading, + filter: { + branch: filterBranch, + spdx_id: filterSPDXId, + unknown_license: filterUnknownLicense, + evaluation_result: filterEvaluationResult, + purl_type: filterPURLType, + }, + }); + + return ( +
+ + + + + + + } + expandSingle + > + {product && product.has_branches && ( + + )} + + + + + + + + +
+ ); +}; + +export default LicenseComponentOverview; diff --git a/frontend/src/licenses/license_components/LicenseComponentShow.tsx b/frontend/src/licenses/license_components/LicenseComponentShow.tsx index 6b8d9dffd..e076e916b 100644 --- a/frontend/src/licenses/license_components/LicenseComponentShow.tsx +++ b/frontend/src/licenses/license_components/LicenseComponentShow.tsx @@ -73,6 +73,13 @@ export const LicenseComponentComponent = () => { )} + {!component.license && !component.unknown_license && ( + + + No license + + + )} From 007e72436214498628d75d840b5a04ffb6d3a9dc Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Mon, 25 Nov 2024 07:18:47 +0000 Subject: [PATCH 09/30] chore: improvements for login (#2260) * chore: improvements for login * chore: black --- backend/application/commons/api/views.py | 9 ++++++- .../auth_provider/authProvider.ts | 24 +++++++++++-------- frontend/src/access_control/login/Login.tsx | 16 +++++++++---- frontend/src/commons/functions.tsx | 4 ++-- frontend/src/dashboard/Dashboard.tsx | 10 ++++++-- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/backend/application/commons/api/views.py b/backend/application/commons/api/views.py index b0b09814f..b53b05c68 100644 --- a/backend/application/commons/api/views.py +++ b/backend/application/commons/api/views.py @@ -60,8 +60,10 @@ def get(self, request): features = [] settings = Settings.load() + if settings.feature_disable_user_login: features.append("feature_disable_user_login") + if request.user.is_authenticated: if settings.feature_vex: features.append("feature_vex") @@ -72,8 +74,13 @@ def get(self, request): content = { "features": features, - "risk_acceptance_expiry_days": settings.risk_acceptance_expiry_days, } + + if request.user.is_authenticated: + content["risk_acceptance_expiry_days"] = ( + settings.risk_acceptance_expiry_days + ) + return Response(content) diff --git a/frontend/src/access_control/auth_provider/authProvider.ts b/frontend/src/access_control/auth_provider/authProvider.ts index 3c26572b4..4d350c838 100644 --- a/frontend/src/access_control/auth_provider/authProvider.ts +++ b/frontend/src/access_control/auth_provider/authProvider.ts @@ -89,14 +89,14 @@ const authProvider: AuthProvider = { let fullName = ""; const avatar = undefined; - const user = localStorage.getItem("user"); + let user = localStorage.getItem("user"); + if (!user) { + await setUserInfo(); + } + user = localStorage.getItem("user"); if (user) { const user_json = JSON.parse(user); fullName = user_json.full_name; - } else { - const userinfo = await getUserInfo(); - const { id: id, full_name: fullName, null: avatar } = userinfo; - return Promise.resolve({ id, fullName, avatar }); } set_settings_in_local_storage(); @@ -105,12 +105,16 @@ const authProvider: AuthProvider = { }, }; -const getUserInfo = async () => { +export const setUserInfo = async () => { + const userinfo = await getUserInfo(); + setListProperties(userinfo.setting_list_properties); + delete userinfo.setting_list_properties; + localStorage.setItem("user", JSON.stringify(userinfo)); + localStorage.setItem("theme", userinfo.setting_theme); +}; + +const getUserInfo = () => { return httpClient(window.__RUNTIME_CONFIG__.API_BASE_URL + "/users/me/").then((response) => { - setListProperties(response.json.setting_list_properties); - delete response.json.setting_list_properties; - localStorage.setItem("user", JSON.stringify(response.json)); - localStorage.setItem("theme", response.json.setting_theme); return response.json; }); }; diff --git a/frontend/src/access_control/login/Login.tsx b/frontend/src/access_control/login/Login.tsx index aa5fe38fa..f2b1572b3 100644 --- a/frontend/src/access_control/login/Login.tsx +++ b/frontend/src/access_control/login/Login.tsx @@ -10,7 +10,7 @@ import { Navigate, useLocation } from "react-router-dom"; import { getTheme } from "../../commons/user_settings/functions"; import { OIDCSignInButton } from "../auth_provider/OIDCSignInButton"; -import { jwt_signed_in } from "../auth_provider/authProvider"; +import { jwt_signed_in, oidc_signed_in } from "../auth_provider/authProvider"; const Login = () => { const [loading, setLoading] = useState(false); @@ -21,11 +21,18 @@ const Login = () => { const login = useLogin(); const location = useLocation(); - const isAuthenticated = jwt_signed_in() || auth.isAuthenticated; + const isAuthenticated = jwt_signed_in() || oidc_signed_in(); useEffect(() => { if (window.__RUNTIME_CONFIG__.OIDC_ENABLE == "true") { - get_disable_login_feature(); + const settingsStorage = localStorage.getItem("settings"); + if (settingsStorage) { + const settings = JSON.parse(settingsStorage); + const features = settings.features || []; + setFeatureDisableUserLogin(features.indexOf("feature_disable_user_login") !== -1); + } else { + get_disable_login_feature(); + } } }, []); @@ -44,9 +51,10 @@ const Login = () => { return response.json(); }) .then((data) => { + localStorage.setItem("settings", JSON.stringify(data)); const features = data.features || []; const feature_disable_user_login_position = features.indexOf("feature_disable_user_login"); - return setFeatureDisableUserLogin(feature_disable_user_login_position !== -1); + setFeatureDisableUserLogin(feature_disable_user_login_position !== -1); }); } diff --git a/frontend/src/commons/functions.tsx b/frontend/src/commons/functions.tsx index f0c36fac8..a438738a6 100644 --- a/frontend/src/commons/functions.tsx +++ b/frontend/src/commons/functions.tsx @@ -165,8 +165,8 @@ export const humanReadableDate = (date: string | undefined) => { return rtf.format(Math.trunc(diffInDays), "day").replace(" ago", ""); }; -export async function set_settings_in_local_storage() { - await httpClient(window.__RUNTIME_CONFIG__.API_BASE_URL + "/status/settings/").then((response) => { +export function set_settings_in_local_storage() { + httpClient(window.__RUNTIME_CONFIG__.API_BASE_URL + "/status/settings/").then((response) => { localStorage.setItem("settings", JSON.stringify(response.json)); }); } diff --git a/frontend/src/dashboard/Dashboard.tsx b/frontend/src/dashboard/Dashboard.tsx index d9bd06ff0..d826882d5 100644 --- a/frontend/src/dashboard/Dashboard.tsx +++ b/frontend/src/dashboard/Dashboard.tsx @@ -2,6 +2,7 @@ import { Stack } from "@mui/material"; import { Fragment, useEffect, useState } from "react"; import { useTheme } from "react-admin"; +import { setUserInfo } from "../access_control/auth_provider/authProvider"; import { getSettingTheme, getTheme } from "../commons/user_settings/functions"; import ObservationDashboardList from "../core/observations/ObservationDashboardList"; import MetricsHeader from "../metrics/MetricsHeader"; @@ -13,11 +14,16 @@ const Dashboard = () => { const [setting_theme, setSettingTheme] = useState(""); const [, setTheme] = useTheme(); - if (setting_theme != getSettingTheme()) { + const getUserInfo = async () => { + const user = localStorage.getItem("user"); + if (!user) { + await setUserInfo(); + } setSettingTheme(getSettingTheme()); - } + }; useEffect(() => { + getUserInfo(); setTheme(getTheme()); }, [setting_theme, setTheme]); From 70b9b0c3baf1b87e8b03ddd171a1c81b93c29186 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Mon, 25 Nov 2024 09:13:53 +0000 Subject: [PATCH 10/30] chore: remove left border on dark menu (#2262) --- frontend/src/commons/layout/themes.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/frontend/src/commons/layout/themes.ts b/frontend/src/commons/layout/themes.ts index afe1f47b9..e9e4c2722 100644 --- a/frontend/src/commons/layout/themes.ts +++ b/frontend/src/commons/layout/themes.ts @@ -73,16 +73,6 @@ export const darkTheme = { }, components: { ...defaultTheme.components, - RaMenuItemLink: { - styleOverrides: { - root: { - borderLeft: "3px solid #000", - "&.RaMenuItemLink-active": { - borderLeft: "3px solid #90caf9", - }, - }, - }, - }, MuiAppBar: { styleOverrides: { colorSecondary: { From 38e4fb0567772b1b93a03ba9c0e6e831a4a54ad2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:30:04 +0100 Subject: [PATCH 11/30] chore(deps): update dependency mkdocs-material to v9.5.46 (#2263) 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 52be620e3..b2aa69a32 100644 --- a/mkdocs_requirements.txt +++ b/mkdocs_requirements.txt @@ -1 +1 @@ -mkdocs-material==9.5.45 # https://github.com/squidfunk/mkdocs-material +mkdocs-material==9.5.46 # https://github.com/squidfunk/mkdocs-material From f52931b51b7bd0d2e15fbfcbb46d4addaedcf0ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:35:17 +0100 Subject: [PATCH 12/30] chore(deps): lock file maintenance (#2261) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 234 +++++++++++++++++++------------------ 1 file changed, 119 insertions(+), 115 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cd68e8202..cfe9047c8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1912,9 +1912,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", - "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", "cpu": [ "arm" ], @@ -1926,9 +1926,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", - "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", "cpu": [ "arm64" ], @@ -1940,9 +1940,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", - "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", "cpu": [ "arm64" ], @@ -1954,9 +1954,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", - "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", "cpu": [ "x64" ], @@ -1968,9 +1968,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", - "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", "cpu": [ "arm64" ], @@ -1982,9 +1982,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", - "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", "cpu": [ "x64" ], @@ -1996,9 +1996,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", - "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", "cpu": [ "arm" ], @@ -2010,9 +2010,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", - "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", "cpu": [ "arm" ], @@ -2024,9 +2024,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", - "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", "cpu": [ "arm64" ], @@ -2038,9 +2038,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", - "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", "cpu": [ "arm64" ], @@ -2052,9 +2052,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", - "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", "cpu": [ "ppc64" ], @@ -2066,9 +2066,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", - "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", "cpu": [ "riscv64" ], @@ -2080,9 +2080,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", - "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", "cpu": [ "s390x" ], @@ -2094,9 +2094,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", - "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", "cpu": [ "x64" ], @@ -2108,9 +2108,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", - "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", "cpu": [ "x64" ], @@ -2122,9 +2122,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", - "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", "cpu": [ "arm64" ], @@ -2136,9 +2136,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", - "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", "cpu": [ "ia32" ], @@ -2150,9 +2150,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", - "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", "cpu": [ "x64" ], @@ -2174,9 +2174,9 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.61.0.tgz", - "integrity": "sha512-SBzV27XAeCRBOQ8QcC94w2H1Md0+LI0gTWwc3qRJoaGuewKn5FNW4LSqwPFJZVEItfhMfGT7RpZuSFXjTi12pQ==", + "version": "5.61.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.61.3.tgz", + "integrity": "sha512-c3Oz9KaCBapGkRewu7AJLhxE9BVqpMcHsd3KtFxSd7FSCu2qGwqfIN37zbSGoyk6Ix9LGZBNHQDPI6GpWABnmA==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.60.6" @@ -3093,9 +3093,9 @@ } }, "node_modules/@types/d3-time": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", - "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, "node_modules/@types/d3-time-format": { @@ -3890,9 +3890,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001683", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", - "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", + "version": "1.0.30001684", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", + "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", "dev": true, "funding": [ { @@ -5404,9 +5404,9 @@ } }, "node_modules/file-selector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.0.tgz", - "integrity": "sha512-ZuXAqGePcSPz4JuerOY06Dzzq0hrmQ6VGoXVzGyFI1npeOfBgqGIKKpznfYWRkSLJlXutkqVC5WvGZtkFVhu9Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.1.tgz", + "integrity": "sha512-pJVY80PuSiHbnYEZ0gZYQf15x0z/lkeIF1yn95yRC/Usb43343ewXtMClQ9GLPvPm4/SscX4zvQz9QhCAyLqlg==", "license": "MIT", "dependencies": { "tslib": "^2.7.0" @@ -6073,13 +6073,16 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", + "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7036,9 +7039,9 @@ } }, "node_modules/package-manager-detector": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.4.tgz", - "integrity": "sha512-H/OUu9/zUfP89z1APcBf2X8Us0tt8dUK4lUmKqz12QNXif3DxAs1/YqjGtcutZi1zQqeNQRWr9C+EbQnnvSSFA==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.5.tgz", + "integrity": "sha512-3dS7y28uua+UDbRCLBqltMBrbI+A5U2mI9YuxHRxIWYmLj3DwntEBmERYzIAQ4DMeuCUOBSak7dBHHoXKpOTYQ==", "license": "MIT" }, "node_modules/parent-module": { @@ -7441,9 +7444,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.36.0.tgz", - "integrity": "sha512-U0GQd5yFvV5qUtT41X1zCQfbw14vkbbKwLlQXhdylEmgpYVHkefXYcC4HHwWOfZa3x6Y8wxDLUBv7dxN5XQ3nA==", + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.37.0.tgz", + "integrity": "sha512-z2nkKI1sJzyi7T47Ji/ewBPuIma1RNvQCCYVdV+MqWBV7o4Sa1n94UJCJJ1aQRF/xRkFfyqLGlGFWitIcCOtbg==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.20.0", @@ -7896,19 +7899,19 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz", + "integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "gopd": "^1.0.1", + "which-builtin-type": "^1.1.4" }, "engines": { "node": ">= 0.4" @@ -8221,9 +8224,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", - "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", "dev": true, "license": "MIT", "dependencies": { @@ -8237,24 +8240,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.3", - "@rollup/rollup-android-arm64": "4.27.3", - "@rollup/rollup-darwin-arm64": "4.27.3", - "@rollup/rollup-darwin-x64": "4.27.3", - "@rollup/rollup-freebsd-arm64": "4.27.3", - "@rollup/rollup-freebsd-x64": "4.27.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", - "@rollup/rollup-linux-arm-musleabihf": "4.27.3", - "@rollup/rollup-linux-arm64-gnu": "4.27.3", - "@rollup/rollup-linux-arm64-musl": "4.27.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", - "@rollup/rollup-linux-riscv64-gnu": "4.27.3", - "@rollup/rollup-linux-s390x-gnu": "4.27.3", - "@rollup/rollup-linux-x64-gnu": "4.27.3", - "@rollup/rollup-linux-x64-musl": "4.27.3", - "@rollup/rollup-win32-arm64-msvc": "4.27.3", - "@rollup/rollup-win32-ia32-msvc": "4.27.3", - "@rollup/rollup-win32-x64-msvc": "4.27.3", + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", "fsevents": "~2.3.2" } }, @@ -8712,9 +8715,9 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", - "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.1.tgz", + "integrity": "sha512-5RU2/lxTA3YUZxju61HO2U6EoZLvBLtmV2mbTvqyu4a/7s7RmJPT+1YekhMVsQhznRWk/czIwDUg+V8Q9ZuG4w==", "dev": true, "license": "MIT", "engines": { @@ -8848,18 +8851,18 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -9145,17 +9148,18 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz", + "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==", "dev": true, "license": "MIT", "dependencies": { + "call-bind": "^1.0.7", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.1.4", "is-weakref": "^1.0.2", From 9260ece8fab00172d65a00d842fd606034e6bbe8 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Mon, 25 Nov 2024 19:56:35 +0000 Subject: [PATCH 13/30] feat: apply license policy in product show (#2264) * feat: apply license policy in product show * chore: mypy --- .../core/api/serializers_product.py | 6 ++ backend/application/licenses/api/views.py | 51 +++++++--- .../licenses/services/license_policy.py | 64 ++++++++---- .../api/test_authorization_products.py | 10 +- frontend/src/core/products/ProductShow.tsx | 37 +------ .../LicenseComponentOverview.tsx | 3 +- .../ProductShowLicenseComponents.tsx | 99 +++++++++++++++++++ .../license_policies/LicensePolicyApply.tsx | 68 ++++++++----- 8 files changed, 239 insertions(+), 99 deletions(-) create mode 100644 frontend/src/licenses/license_components/ProductShowLicenseComponents.tsx diff --git a/backend/application/core/api/serializers_product.py b/backend/application/core/api/serializers_product.py index f0a1fb810..9c98dbe14 100644 --- a/backend/application/core/api/serializers_product.py +++ b/backend/application/core/api/serializers_product.py @@ -226,6 +226,7 @@ class ProductSerializer( product_group_new_observations_in_review = SerializerMethodField() has_branches = SerializerMethodField() has_licenses = SerializerMethodField() + product_group_license_policy = SerializerMethodField() class Meta: model = Product @@ -318,6 +319,11 @@ def get_has_branches(self, obj: Product) -> bool: def get_has_licenses(self, obj: Product) -> bool: return License_Component.objects.filter(product=obj).exists() + def get_product_group_license_policy(self, obj: Product) -> Optional[int]: + if not obj.product_group or not obj.product_group.license_policy: + return None + return obj.product_group.license_policy.id + def validate(self, attrs: dict): # pylint: disable=too-many-branches # There are quite a lot of branches, but at least they are not nested too much if attrs.get("issue_tracker_type") == Issue_Tracker.ISSUE_TRACKER_GITHUB: diff --git a/backend/application/licenses/api/views.py b/backend/application/licenses/api/views.py index c6399f912..cd44c2878 100644 --- a/backend/application/licenses/api/views.py +++ b/backend/application/licenses/api/views.py @@ -104,6 +104,7 @@ ) from application.licenses.services.license_policy import ( apply_license_policy, + apply_license_policy_product, copy_license_policy, ) @@ -153,8 +154,8 @@ def license_overview(self, request): product_id = request.query_params.get("product") if not product_id: raise ValidationError("No product id provided") - product = self.__get_product(product_id) - branch = self.__get_branch(product, request.query_params.get("branch")) + product = _get_product(product_id, Permissions.Product_View) + branch = self._get_branch(product, request.query_params.get("branch")) spdx_id = request.query_params.get("spdx_id") unknown_license = request.query_params.get("unknown_license") evaluation_result = request.query_params.get("evaluation_result") @@ -202,19 +203,7 @@ def license_overview(self, request): data=response_serializer.data, ) - def __get_product(self, pk: int) -> Product: - if not pk: - raise ValidationError("No product id provided") - - product = get_product_by_id(pk) - if not product: - raise NotFound() - - user_has_permission_or_403(product, Permissions.Product_View) - - return product - - def __get_branch(self, product: Product, pk: int) -> Optional[Branch]: + def _get_branch(self, product: Product, pk: int) -> Optional[Branch]: if not pk: return None @@ -501,6 +490,25 @@ def apply(self, request, pk): status=HTTP_204_NO_CONTENT, ) + @extend_schema( + methods=["POST"], + request=None, + responses={HTTP_204_NO_CONTENT: None}, + parameters=[ + OpenApiParameter(name="product", type=int, required=True), + ], + ) + @action(detail=False, methods=["post"]) + def apply_product(self, request): + product = _get_product( + request.query_params.get("product"), Permissions.Product_Edit + ) + apply_license_policy_product(product) + + return Response( + status=HTTP_204_NO_CONTENT, + ) + class LicensePolicyItemViewSet(ModelViewSet): serializer_class = LicensePolicyItemSerializer @@ -549,3 +557,16 @@ def get_queryset(self): .select_related("license_policy") .select_related("authorization_group") ) + + +def _get_product(product_id: int, permission: int) -> Product: + if not product_id: + raise ValidationError("No product id provided") + + product = get_product_by_id(product_id) + if not product: + raise NotFound() + + user_has_permission_or_403(product, permission) + + return product diff --git a/backend/application/licenses/services/license_policy.py b/backend/application/licenses/services/license_policy.py index c4dca88ff..50d90a783 100644 --- a/backend/application/licenses/services/license_policy.py +++ b/backend/application/licenses/services/license_policy.py @@ -1,3 +1,6 @@ +from typing import Optional + +from django.db.models import Q from django.utils import timezone from application.core.models import Product @@ -11,11 +14,8 @@ def get_license_evaluation_results(product: Product) -> dict: - if product.license_policy: - license_policy = product.license_policy - elif product.product_group and product.product_group.license_policy: - license_policy = product.product_group.license_policy - else: + license_policy = _get_license_policy(product) + if not license_policy: return {} license_evaluation_results = {} @@ -71,29 +71,45 @@ def apply_license_policy_to_component( def apply_license_policy(license_policy: License_Policy) -> None: - products = Product.objects.filter(license_policy=license_policy) + products = Product.objects.filter( + Q(license_policy=license_policy) + | ( + Q(product_group__license_policy=license_policy) + & Q(license_policy__isnull=True) + ) + ) for product in products: - license_evaluation_results = get_license_evaluation_results(product) - components = License_Component.objects.filter(product=product) - for component in components: - license_before = component.license - unknown_license_before = component.unknown_license - evaluation_result_before = component.evaluation_result + apply_license_policy_product(product) + + +def apply_license_policy_product(product: Product) -> None: + license_evaluation_results = get_license_evaluation_results(product) + components = License_Component.objects.filter(product=product) + for component in components: + license_before = component.license + unknown_license_before = component.unknown_license + evaluation_result_before = component.evaluation_result + license_policy = _get_license_policy(product) + if license_policy: apply_license_policy_to_component( component, license_evaluation_results, get_ignore_component_type_list(license_policy.ignore_component_types), ) + else: + component.evaluation_result = ( + License_Policy_Evaluation_Result.RESULT_UNKNOWN + ) - if ( - license_before != component.license - or unknown_license_before != component.unknown_license - or evaluation_result_before != component.evaluation_result - ): - component.last_change = timezone.now() + if ( + license_before != component.license + or unknown_license_before != component.unknown_license + or evaluation_result_before != component.evaluation_result + ): + component.last_change = timezone.now() - component.save() + component.save() def copy_license_policy( @@ -133,3 +149,13 @@ def get_ignore_component_type_list(ignore_component_types: str) -> list: ) ignore_component_types_list = [x.strip() for x in ignore_component_types_list] return ignore_component_types_list + + +def _get_license_policy(product: Product) -> Optional[License_Policy]: + if product.license_policy: + return product.license_policy + + if product.product_group and product.product_group.license_policy: + return product.product_group.license_policy + + return None diff --git a/backend/unittests/access_control/api/test_authorization_products.py b/backend/unittests/access_control/api/test_authorization_products.py index 669ca3ca4..89547d7dd 100644 --- a/backend/unittests/access_control/api/test_authorization_products.py +++ b/backend/unittests/access_control/api/test_authorization_products.py @@ -16,18 +16,18 @@ def test_authorization_products_product_authorization_group_member(self): self._test_authorization_products() def _test_authorization_products(self): - expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}, {'id': 2, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_external', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'name': 'db_product_external', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': False, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': None, 'repository_default_branch': 3, 'license_policy': None}]}" + expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'product_group_license_policy': None, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}, {'id': 2, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_external', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'product_group_license_policy': None, 'name': 'db_product_external', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': False, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': None, 'repository_default_branch': 3, 'license_policy': None}]}" self._test_api( APITest("db_admin", "get", "/api/products/", None, 200, expected_data) ) - expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}]}" + expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'product_group_license_policy': None, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}]}" self._test_api( APITest( "db_internal_write", "get", "/api/products/", None, 200, expected_data ) ) - expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}" + expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'product_group_license_policy': None, 'name': 'db_product_internal', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}" self._test_api( APITest( "db_internal_write", "get", "/api/products/1/", None, 200, expected_data @@ -63,7 +63,7 @@ def _test_authorization_products(self): expected_data, ) ) - expected_data = "{'id': 5, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': '', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': False, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': False, 'has_licenses': False, 'name': 'string', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': None, 'repository_default_branch': None, 'license_policy': None}" + expected_data = "{'id': 5, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': '', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': False, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': False, 'has_licenses': False, 'product_group_license_policy': None, 'name': 'string', 'description': '', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': None, 'repository_default_branch': None, 'license_policy': None}" self._test_api( APITest( "db_internal_write", @@ -91,7 +91,7 @@ def _test_authorization_products(self): expected_data, ) ) - expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'name': 'db_product_internal', 'description': 'string', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}" + expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unknown_observation_count': 0, 'forbidden_licenses_count': 0, 'review_required_licenses_count': 0, 'unknown_licenses_count': 0, 'allowed_licenses_count': 0, 'ignored_licenses_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'product_group_assessments_need_approval': False, 'repository_default_branch_name': 'db_branch_internal_dev', 'observation_reviews': 0, 'observation_log_approvals': 0, 'has_services': True, 'product_group_product_rules_need_approval': False, 'product_rule_approvals': 0, 'risk_acceptance_expiry_date_calculated': datetime.date(2024, 7, 1), 'product_group_new_observations_in_review': False, 'has_branches': True, 'has_licenses': True, 'product_group_license_policy': None, 'name': 'db_product_internal', 'description': 'string', 'purl': '', 'cpe23': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unknown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_slack_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'issue_tracker_minimum_severity': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'assessments_need_approval': False, 'new_observations_in_review': False, 'product_rules_need_approval': False, 'risk_acceptance_expiry_active': None, 'risk_acceptance_expiry_days': None, 'has_cloud_resource': False, 'has_component': False, 'has_docker_image': False, 'has_endpoint': False, 'has_kubernetes_resource': False, 'has_source': False, 'has_potential_duplicates': False, 'product_group': 3, 'repository_default_branch': 1, 'license_policy': None}" self._test_api( APITest( "db_internal_write", diff --git a/frontend/src/core/products/ProductShow.tsx b/frontend/src/core/products/ProductShow.tsx index bd6920ce2..ca1eb0ae7 100644 --- a/frontend/src/core/products/ProductShow.tsx +++ b/frontend/src/core/products/ProductShow.tsx @@ -13,9 +13,7 @@ import { Fragment, useState } from "react"; import { EditButton, PrevNextButtons, - RadioButtonGroupInput, Show, - SimpleForm, Tab, TabbedShowLayout, TabbedShowLayoutTabs, @@ -45,8 +43,7 @@ import ApiConfigurationCreate from "../../import_observations/api_configurations import ApiConfigurationEmbeddedList from "../../import_observations/api_configurations/ApiConfigurationEmbeddedList"; import ImportMenu from "../../import_observations/import/ImportMenu"; import VulnerabilityCheckEmbeddedList from "../../import_observations/vulnerability_checks/VulnerabilityCheckEmbeddedList"; -import LicenseComponentEmbeddedList from "../../licenses/license_components/LicenseComponentEmbeddedList"; -import LicenseComponentOverview from "../../licenses/license_components/LicenseComponentOverview"; +import ProductShowLicenseComponents from "../../licenses/license_components/ProductShowLicenseComponents"; import MetricsHeader from "../../metrics/MetricsHeader"; import MetricsSeveritiesCurrent from "../../metrics/MetricsSeveritiesCurrent"; import MetricsSeveritiesTimeline from "../../metrics/MetricsSeveritiesTimeLine"; @@ -98,7 +95,6 @@ const ShowActions = (props: ShowActionsProps) => { }; const ProductShow = () => { - const [licenseViewState, setLicenseViewState] = useState("detail"); // eslint-disable-line @typescript-eslint/no-unused-vars const [settingsTabsShow, setSettingsTabsShow] = useState(false); const [tabs_changed, setTabsChanged] = useState(false); function showSettingsTabs() { @@ -123,20 +119,6 @@ const ProductShow = () => { } const settingsLabel = settingsTabsShow ? "Settings" : "Settings >>>"; - const licenseView = (): string => { - const license_view_storage = localStorage.getItem("license_view"); - if (license_view_storage === null) { - return "detail"; - } - setLicenseViewState(license_view_storage); - return license_view_storage; - }; - - const setLicenseView = (value: string) => { - localStorage.setItem("license_view", value); - setLicenseViewState(value); - }; - let filter = {}; let storeKey = "products.list"; @@ -249,22 +231,7 @@ const ProductShow = () => { )} {feature_license_management() && product.has_licenses && ( } onClick={hideSettingsTabs}> - - setLicenseView(e.target.value)} - /> - {licenseView() === "detail" && ( - - )} - {licenseView() === "overview" && } - + )} bulkActionButtons={false} rowClick={false} expand={ - + { + const [licenseViewState, setLicenseViewState] = useState("detail"); + + const licenseView = (): string => { + let license_view_storage = localStorage.getItem("license_view"); + if (license_view_storage === null) { + license_view_storage = "detail"; + } + if (license_view_storage !== licenseViewState) { + setLicenseViewState(license_view_storage); + } + return license_view_storage; + }; + + const setLicenseView = (value: string) => { + localStorage.setItem("license_view", value); + setLicenseViewState(value); + }; + + return ( + + + setLicenseView(e.target.value)} + helperText={false} + sx={{ width: "fit-content", margin: 0 }} + /> + {product && product.license_policy && ( + + + + + + )} + {product && + !product.license_policy && + product.product_group && + product.product_group_license_policy && ( + + + + + + )} + {product && product.permissions.includes(PERMISSION_PRODUCT_EDIT) && ( + + )} + {product && !product.permissions.includes(PERMISSION_PRODUCT_EDIT) && ( + + )} + + {licenseView() === "detail" && } + {licenseView() === "overview" && } + + ); +}; + +export default ProductShowLicenseComponents; diff --git a/frontend/src/licenses/license_policies/LicensePolicyApply.tsx b/frontend/src/licenses/license_policies/LicensePolicyApply.tsx index 85596a7df..df1f75f9e 100644 --- a/frontend/src/licenses/license_policies/LicensePolicyApply.tsx +++ b/frontend/src/licenses/license_policies/LicensePolicyApply.tsx @@ -6,10 +6,11 @@ import { Confirm, useNotify, useRefresh } from "react-admin"; import { httpClient } from "../../commons/ra-data-django-rest-framework"; type LicensePolicyApplyProps = { - license_policy: any; + license_policy?: any; + product?: any; }; -const LicensePolicyApply = ({ license_policy }: LicensePolicyApplyProps) => { +const LicensePolicyApply = ({ license_policy, product }: LicensePolicyApplyProps) => { const [open, setOpen] = useState(false); const refresh = useRefresh(); const [loading, setLoading] = useState(false); @@ -17,29 +18,50 @@ const LicensePolicyApply = ({ license_policy }: LicensePolicyApplyProps) => { const handleClick = () => setOpen(true); const handleDialogClose = () => setOpen(false); + const buttonText = () => { + if (product) { + return "Apply license policy"; + } + return "Apply"; + }; + + const content = () => { + if (product) { + return "Are you sure you want to apply the license policy?"; + } + return "Are you sure you want to apply the license policy " + license_policy.name + " to all products?"; + }; + const handleConfirm = async () => { setLoading(true); - const url = window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_policies/" + license_policy.id + "/apply/"; + let url = ""; + if (product) { + url = window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_policies/apply_product/?product=" + product.id; + } else { + url = window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_policies/" + license_policy.id + "/apply/"; + } - httpClient(url, { - method: "POST", - }) - .then(() => { - refresh(); - setOpen(false); - setLoading(false); - notify("License policy applied", { - type: "success", - }); + if (url !== "") { + httpClient(url, { + method: "POST", }) - .catch((error) => { - refresh(); - setOpen(false); - setLoading(false); - notify(error.message, { - type: "warning", + .then(() => { + refresh(); + setOpen(false); + setLoading(false); + notify("License policy applied", { + type: "success", + }); + }) + .catch((error) => { + refresh(); + setOpen(false); + setLoading(false); + notify(error.message, { + type: "warning", + }); }); - }); + } }; return ( @@ -50,14 +72,12 @@ const LicensePolicyApply = ({ license_policy }: LicensePolicyApplyProps) => { onClick={handleClick} startIcon={} > - Apply + {buttonText()} From affb6d17280b03f64dd12e89a23bad111acb3fc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 21:04:32 +0100 Subject: [PATCH 14/30] chore(deps): update typescript-eslint monorepo to v8.16.0 (#2225) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 88 +++++++++++++++++++------------------- frontend/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cfe9047c8..35c4ba4b6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -45,8 +45,8 @@ "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@types/recharts": "1.8.29", - "@typescript-eslint/eslint-plugin": "8.15.0", - "@typescript-eslint/parser": "8.15.0", + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", "@vitejs/plugin-react": "4.3.3", "eslint": "9.15.0", "eslint-plugin-react": "7.37.2", @@ -3262,17 +3262,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", - "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz", + "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/type-utils": "8.15.0", - "@typescript-eslint/utils": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/type-utils": "8.16.0", + "@typescript-eslint/utils": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3296,16 +3296,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", - "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", + "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4" }, "engines": { @@ -3325,14 +3325,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", - "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", + "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0" + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3343,14 +3343,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", - "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz", + "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/utils": "8.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3371,9 +3371,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", - "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", + "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", "dev": true, "license": "MIT", "engines": { @@ -3385,14 +3385,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", - "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", + "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3440,16 +3440,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", - "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", + "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0" + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3468,13 +3468,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", - "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", + "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/types": "8.16.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { diff --git a/frontend/package.json b/frontend/package.json index b1c9d3a30..fcba161f4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@types/recharts": "1.8.29", - "@typescript-eslint/eslint-plugin": "8.15.0", - "@typescript-eslint/parser": "8.15.0", + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", "@vitejs/plugin-react": "4.3.3", "eslint": "9.15.0", "eslint-plugin-react": "7.37.2", From 283ab14fc971bd334a120d34a694769a255f9e91 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Mon, 25 Nov 2024 21:36:23 +0000 Subject: [PATCH 15/30] feat: show product groups for license policies (#2265) * feat: show product groups for license policies * chore: fix unittests --- backend/application/core/api/filters.py | 2 +- .../application/licenses/api/serializers.py | 4 + .../test_authorization_license_policies.py | 16 ++-- ...ense_policy_authorization_group_members.py | 10 +-- ...test_authorization_license_policy_items.py | 16 ++-- ...st_authorization_license_policy_members.py | 10 +-- .../ProductGroupEmbeddedList.tsx | 73 +++++++++++++++++++ .../license_policies/LicensePolicyShow.tsx | 9 +++ 8 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 frontend/src/core/product_groups/ProductGroupEmbeddedList.tsx diff --git a/backend/application/core/api/filters.py b/backend/application/core/api/filters.py index 38ea0ff7a..e2a58062a 100644 --- a/backend/application/core/api/filters.py +++ b/backend/application/core/api/filters.py @@ -36,7 +36,7 @@ class ProductGroupFilter(FilterSet): class Meta: model = Product - fields = ["name"] + fields = ["name", "license_policy"] class ProductFilter(FilterSet): diff --git a/backend/application/licenses/api/serializers.py b/backend/application/licenses/api/serializers.py index 8c52c02d8..4932bf984 100644 --- a/backend/application/licenses/api/serializers.py +++ b/backend/application/licenses/api/serializers.py @@ -314,6 +314,7 @@ class LicenseGroupCopySerializer(Serializer): class LicensePolicySerializer(ModelSerializer): is_manager = SerializerMethodField() has_products = SerializerMethodField() + has_product_groups = SerializerMethodField() has_items = SerializerMethodField() has_users = SerializerMethodField() has_authorization_groups = SerializerMethodField() @@ -351,6 +352,9 @@ def get_is_manager(self, obj: License_Policy) -> bool: def get_has_products(self, obj: License_Policy) -> bool: return get_products().filter(license_policy=obj).exists() + def get_has_product_groups(self, obj: License_Policy) -> bool: + return get_products(is_product_group=True).filter(license_policy=obj).exists() + def get_has_items(self, obj: License_Policy) -> bool: return obj.license_policy_items.exists() diff --git a/backend/unittests/access_control/api/test_authorization_license_policies.py b/backend/unittests/access_control/api/test_authorization_license_policies.py index 0c5dfc3f0..d27aced07 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policies.py +++ b/backend/unittests/access_control/api/test_authorization_license_policies.py @@ -9,14 +9,14 @@ class TestAuthorizationLicensePolicies(TestAuthorizationBase): def test_authorization_license_policies(self): License_Policy.objects.filter(pk__lt=1000).delete() - expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1001, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1002, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1004, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" + expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1002, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1004, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" self._test_api( APITest( "db_admin", "get", "/api/license_policies/", None, 200, expected_data ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" self._test_api( APITest( "db_internal_write", @@ -29,7 +29,7 @@ def test_authorization_license_policies(self): ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}]}" self._test_api( APITest( "db_product_group_user", @@ -42,7 +42,7 @@ def test_authorization_license_policies(self): ) ) - expected_data = "{'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}" + expected_data = "{'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}" self._test_api( APITest( "db_internal_write", @@ -79,7 +79,7 @@ def test_authorization_license_policies(self): ) post_data = {"name": "new_license_policy"} - expected_data = "{'id': 1005, 'is_manager': True, 'has_products': False, 'has_items': False, 'has_users': True, 'has_authorization_groups': False, 'name': 'new_license_policy', 'description': '', 'is_public': False, 'ignore_component_types': ''}" + expected_data = "{'id': 1005, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': False, 'has_users': True, 'has_authorization_groups': False, 'name': 'new_license_policy', 'description': '', 'is_public': False, 'ignore_component_types': ''}" self._test_api( APITest( "db_internal_write", @@ -108,7 +108,7 @@ def test_authorization_license_policies(self): ) ) - expected_data = "{'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" + expected_data = "{'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" self._test_api( APITest( "db_internal_write", @@ -136,7 +136,7 @@ def test_authorization_license_policies(self): ) ) - expected_data = "{'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" + expected_data = "{'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" self._test_api( APITest( "db_product_group_user", @@ -177,7 +177,7 @@ def test_authorization_license_policies(self): ) post_data = {"name": "copied_license_policy"} - expected_data = "{'id': 1006, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'copied_license_policy', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" + expected_data = "{'id': 1006, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'copied_license_policy', 'description': 'changed', 'is_public': False, 'ignore_component_types': ''}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_license_policy_authorization_group_members.py b/backend/unittests/access_control/api/test_authorization_license_policy_authorization_group_members.py index 8c71a91fa..002fb4b5c 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policy_authorization_group_members.py +++ b/backend/unittests/access_control/api/test_authorization_license_policy_authorization_group_members.py @@ -9,7 +9,7 @@ class TestAuthorizationLicensePolicyAuthorizationGroupMembers(TestAuthorizationB def test_authorization_license_policy_authorization_group_members(self): License_Policy.objects.filter(pk__lt=1000).delete() - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}, {'id': 1001, 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 2}, {'id': 1002, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 3, 'name': 'non_oidc_group', 'oidc_group': ''}, 'is_manager': True, 'license_policy': 1003, 'authorization_group': 3}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}, {'id': 1001, 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 2}, {'id': 1002, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 3, 'name': 'non_oidc_group', 'oidc_group': ''}, 'is_manager': True, 'license_policy': 1003, 'authorization_group': 3}]}" self._test_api( APITest( "db_admin", @@ -21,7 +21,7 @@ def test_authorization_license_policy_authorization_group_members(self): ) ) - expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}, {'id': 1001, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 2}]}" + expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}, {'id': 1001, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 2}]}" self._test_api( APITest( "db_product_group_user", @@ -34,7 +34,7 @@ def test_authorization_license_policy_authorization_group_members(self): ) ) - expected_data = "{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}" + expected_data = "{'id': 1000, 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 2, 'name': 'oidc_group_2', 'oidc_group': 'oidc_2'}, 'is_manager': False, 'license_policy': 1003, 'authorization_group': 2}" self._test_api( APITest( "db_product_group_user", @@ -65,7 +65,7 @@ def test_authorization_license_policy_authorization_group_members(self): "authorization_group": 1, "is_manager": False, } - expected_data = "{'id': 1003, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 1, 'name': 'oidc_group_1', 'oidc_group': 'oidc_1'}, 'is_manager': False, 'license_policy': 1004, 'authorization_group': 1}" + expected_data = "{'id': 1003, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 1, 'name': 'oidc_group_1', 'oidc_group': 'oidc_1'}, 'is_manager': False, 'license_policy': 1004, 'authorization_group': 1}" self._test_api( APITest( "db_product_group_user", @@ -133,7 +133,7 @@ def test_authorization_license_policy_authorization_group_members(self): ) ) - expected_data = "{'id': 1003, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 1, 'name': 'oidc_group_1', 'oidc_group': 'oidc_1'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 1}" + expected_data = "{'id': 1003, 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'authorization_group_data': {'id': 1, 'name': 'oidc_group_1', 'oidc_group': 'oidc_1'}, 'is_manager': True, 'license_policy': 1004, 'authorization_group': 1}" self._test_api( APITest( "db_product_group_user", diff --git a/backend/unittests/access_control/api/test_authorization_license_policy_items.py b/backend/unittests/access_control/api/test_authorization_license_policy_items.py index 692076721..879f6f486 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policy_items.py +++ b/backend/unittests/access_control/api/test_authorization_license_policy_items.py @@ -9,7 +9,7 @@ class TestAuthorizationLicensePolicyItems(TestAuthorizationBase): def test_authorization_license_policy_items(self): License_Policy.objects.filter(pk__lt=1000).delete() - expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1001, 'license_spdx_id': '0BSD', 'license_group_name': '', 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Forbidden', 'license_policy': 1001, 'license_group': None, 'license': 1}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1001, 'license_spdx_id': '0BSD', 'license_group_name': '', 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Forbidden', 'license_policy': 1001, 'license_group': None, 'license': 1}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_admin", @@ -21,7 +21,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_internal_write", @@ -34,7 +34,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_product_group_user", @@ -47,7 +47,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}" + expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -89,7 +89,7 @@ def test_authorization_license_policy_items(self): "unknown_license": "", "evaluation_result": "Allowed", } - expected_data = "{'id': 1005, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1002, 'license_group': 2, 'license': None}" + expected_data = "{'id': 1005, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1002, 'license_group': 2, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -129,7 +129,7 @@ def test_authorization_license_policy_items(self): "unknown_license": "", "evaluation_result": "Allowed", } - expected_data = "{'id': 1006, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1004, 'license_group': 2, 'license': None}" + expected_data = "{'id': 1006, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1004, 'license_group': 2, 'license': None}" self._test_api( APITest( "db_product_group_user", @@ -181,7 +181,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1002, 'license_group': None, 'license': None}" + expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1002, 'license_group': None, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -212,7 +212,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1004, 'license_group': None, 'license': None}" + expected_data = "{'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1004, 'license_group': None, 'license': None}" self._test_api( APITest( "db_product_group_user", diff --git a/backend/unittests/access_control/api/test_authorization_license_policy_members.py b/backend/unittests/access_control/api/test_authorization_license_policy_members.py index b29181bc3..05ffce7a0 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policy_members.py +++ b/backend/unittests/access_control/api/test_authorization_license_policy_members.py @@ -9,7 +9,7 @@ class TestAuthorizationLicensePolicyMembers(TestAuthorizationBase): def test_authorization_license_policy_members(self): License_Policy.objects.filter(pk__lt=1000).delete() - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1001, 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 3, 'username': 'db_internal_read', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_read', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:25:06+01:00', 'has_password': False}, 'is_manager': False, 'license_policy': 1001, 'user': 3}, {'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}, {'id': 1003, 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 4, 'username': 'db_external', 'first_name': '', 'last_name': '', 'full_name': 'db_external', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': True, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-12T19:48:08.514000+01:00', 'has_password': False}, 'is_manager': False, 'license_policy': 1001, 'user': 4}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1001, 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 3, 'username': 'db_internal_read', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_read', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:25:06+01:00', 'has_password': False}, 'is_manager': False, 'license_policy': 1001, 'user': 3}, {'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}, {'id': 1003, 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 4, 'username': 'db_external', 'first_name': '', 'last_name': '', 'full_name': 'db_external', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': True, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-12T19:48:08.514000+01:00', 'has_password': False}, 'is_manager': False, 'license_policy': 1001, 'user': 4}]}" self._test_api( APITest( "db_admin", @@ -21,7 +21,7 @@ def test_authorization_license_policy_members(self): ) ) - expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}]}" + expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}]}" self._test_api( APITest( "db_internal_write", @@ -34,7 +34,7 @@ def test_authorization_license_policy_members(self): ) ) - expected_data = "{'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}" + expected_data = "{'id': 1002, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 2, 'username': 'db_internal_write', 'first_name': '', 'last_name': '', 'full_name': 'db_internal_write', 'email': '', 'is_active': True, 'is_superuser': False, 'is_external': False, 'setting_theme': 'light', 'setting_list_size': 'medium', 'permissions': [, ], 'setting_list_properties': '', 'oidc_groups_hash': '', 'is_oidc_user': False, 'date_joined': '2022-12-07T20:24:53+01:00', 'has_password': False}, 'is_manager': True, 'license_policy': 1002, 'user': 2}" self._test_api( APITest( "db_internal_write", @@ -73,7 +73,7 @@ def test_authorization_license_policy_members(self): ) post_data = {"license_policy": 1002, "user": 6, "is_manager": False} - expected_data = "{'id': 1004, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 6, 'username': 'db_product_group_user', 'full_name': 'db_product_group_user'}, 'is_manager': False, 'license_policy': 1002, 'user': 6}" + expected_data = "{'id': 1004, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 6, 'username': 'db_product_group_user', 'full_name': 'db_product_group_user'}, 'is_manager': False, 'license_policy': 1002, 'user': 6}" self._test_api( APITest( "db_internal_write", @@ -115,7 +115,7 @@ def test_authorization_license_policy_members(self): ) ) - expected_data = "{'id': 1004, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 6, 'username': 'db_product_group_user', 'full_name': 'db_product_group_user'}, 'is_manager': True, 'license_policy': 1002, 'user': 6}" + expected_data = "{'id': 1004, 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'user_data': {'id': 6, 'username': 'db_product_group_user', 'full_name': 'db_product_group_user'}, 'is_manager': True, 'license_policy': 1002, 'user': 6}" self._test_api( APITest( "db_internal_write", diff --git a/frontend/src/core/product_groups/ProductGroupEmbeddedList.tsx b/frontend/src/core/product_groups/ProductGroupEmbeddedList.tsx new file mode 100644 index 000000000..a00a75460 --- /dev/null +++ b/frontend/src/core/product_groups/ProductGroupEmbeddedList.tsx @@ -0,0 +1,73 @@ +import { + Datagrid, + FilterForm, + ListContextProvider, + ResourceContextProvider, + TextField, + TextInput, + useListController, +} from "react-admin"; + +import { CustomPagination } from "../../commons/custom_fields/CustomPagination"; +import LicensesCountField from "../../commons/custom_fields/LicensesCountField"; +import ObservationsCountField from "../../commons/custom_fields/ObservationsCountField"; +import { feature_license_management } from "../../commons/functions"; +import { getSettingListSize } from "../../commons/user_settings/functions"; + +interface ProductGroupEmbeddedListProps { + license_policy: any; +} + +const showProductGroup = (id: any) => { + return "../../../../product_groups/" + id + "/show"; +}; + +function listFilters() { + return []; +} + +const ProductGroupEmbeddedList = ({ license_policy }: ProductGroupEmbeddedListProps) => { + let filter = {}; + if (license_policy) { + filter = { ...filter, license_policy: Number(license_policy.id) }; + } + const listContext = useListController({ + filter: filter, + perPage: 25, + resource: "product_groups", + sort: { field: "name", order: "ASC" }, + filterDefaultValues: {}, + disableSyncWithLocation: false, + storeKey: "productgroups.embedded", + }); + + if (listContext.isLoading) { + return
Loading...
; + } + localStorage.removeItem("productgroupembeddedlist.license_policy"); + if (license_policy) localStorage.setItem("productgroupembeddedlist.license_policy", license_policy.id); + + return ( + + +
+ + + + + + {feature_license_management() && } + + +
+
+
+ ); +}; + +export default ProductGroupEmbeddedList; diff --git a/frontend/src/licenses/license_policies/LicensePolicyShow.tsx b/frontend/src/licenses/license_policies/LicensePolicyShow.tsx index 4fcad70fb..2fd7bb434 100644 --- a/frontend/src/licenses/license_policies/LicensePolicyShow.tsx +++ b/frontend/src/licenses/license_policies/LicensePolicyShow.tsx @@ -15,6 +15,7 @@ import { import MarkdownField from "../../commons/custom_fields/MarkdownField"; import { is_external, is_superuser } from "../../commons/functions"; import { useStyles } from "../../commons/layout/themes"; +import ProductGroupEmbeddedList from "../../core/product_groups/ProductGroupEmbeddedList"; import ProductEmbeddedList from "../../core/products/ProductEmbeddedList"; import LicensePolicyAuthorizationGroupMemberEmbeddedList from "../license_policy_authorization_group_members/LicensePolicyAuthorizationGroupMemberEmbeddedList"; import LicensePolicyItemEmbeddedList from "../license_policy_items/LicensePolicyItemEmbeddedList"; @@ -93,6 +94,14 @@ const LicensePolicyComponent = () => {
+ {license_policy.has_product_groups && ( + + + Product Groups using this license policy + + + + )} {license_policy.has_products && ( From 25998880952e1026be2d2c14c7e74ab406827245 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:11:25 +0100 Subject: [PATCH 16/30] chore(deps): update dependency @types/node to v22.10.0 (#2266) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- end_to_end_tests/package-lock.json | 16 ++++++++-------- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index 62cb3bf3a..428380c74 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -9,7 +9,7 @@ "version": "1.22.4", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.9.3" + "@types/node": "22.10.0" } }, "node_modules/@playwright/test": { @@ -29,13 +29,13 @@ } }, "node_modules/@types/node": { - "version": "22.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", - "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/fsevents": { @@ -86,9 +86,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" } diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index f01a84474..d0382d8a1 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -9,6 +9,6 @@ "author": "", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.9.3" + "@types/node": "22.10.0" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 35c4ba4b6..884ec0057 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,7 +40,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.9.3", + "@types/node": "22.10.0", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", @@ -3188,13 +3188,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", - "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/parse-json": { @@ -8914,9 +8914,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index fcba161f4..8ba8df0e6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.9.3", + "@types/node": "22.10.0", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", From 85ab5ef744dc15e42996a5d31fa670e804cc9e1a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:16:43 +0100 Subject: [PATCH 17/30] fix(deps): update dependency axios to v1.7.8 (#2267) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Stefan Fleckenstein --- 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 884ec0057..f5a9fe371 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,7 +16,7 @@ "@fortawesome/free-solid-svg-icons": "6.7.1", "@fortawesome/react-fontawesome": "0.2.2", "@textea/json-viewer": "3.5.0", - "axios": "1.7.7", + "axios": "1.7.8", "chart.js": "4.4.6", "markdown-to-jsx": "7.7.0", "mermaid": "11.4.0", @@ -3772,9 +3772,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", + "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", diff --git a/frontend/package.json b/frontend/package.json index 8ba8df0e6..8fb3592fb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,7 @@ "@fortawesome/free-solid-svg-icons": "6.7.1", "@fortawesome/react-fontawesome": "0.2.2", "@textea/json-viewer": "3.5.0", - "axios": "1.7.7", + "axios": "1.7.8", "chart.js": "4.4.6", "markdown-to-jsx": "7.7.0", "mermaid": "11.4.0", From bf02f1873febbf0234464ac221664b4df8180873 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:22:16 +0100 Subject: [PATCH 18/30] chore(deps): update dependency prettier to v3.4.0 (#2268) 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 f5a9fe371..97deaf0ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -53,7 +53,7 @@ "eslint-plugin-react-hooks": "rc", "eslint-plugin-security": "3.0.1", "globals": "15.12.0", - "prettier": "3.3.3", + "prettier": "3.4.0", "rewire": "7.0.0", "typescript": "5.7.2", "vite": "5.4.11" @@ -7227,9 +7227,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.0.tgz", + "integrity": "sha512-/OXNZcLyWkfo13ofOW5M7SLh+k5pnIs07owXK2teFpnfaOEcycnSy7HQxldaVX1ZP/7Q8oO1eDuQJNwbomQq5Q==", "dev": true, "license": "MIT", "bin": { diff --git a/frontend/package.json b/frontend/package.json index 8fb3592fb..104356b68 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -62,7 +62,7 @@ "eslint-plugin-react-hooks": "rc", "eslint-plugin-security": "3.0.1", "globals": "15.12.0", - "prettier": "3.3.3", + "prettier": "3.4.0", "rewire": "7.0.0", "typescript": "5.7.2", "vite": "5.4.11" From 090fa32c7d738f52a1555b388c40ed76adc62034 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Tue, 26 Nov 2024 11:36:35 +0000 Subject: [PATCH 19/30] chore: auth* tests for license policy apply product (#2269) --- .../access_control/api/test_authentication.py | 1 + .../test_authorization_license_policies.py | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/backend/unittests/access_control/api/test_authentication.py b/backend/unittests/access_control/api/test_authentication.py index 5d1f5d443..478d64e91 100644 --- a/backend/unittests/access_control/api/test_authentication.py +++ b/backend/unittests/access_control/api/test_authentication.py @@ -351,6 +351,7 @@ def test_authentication(self, mock_user): ) self._check_authentication(["post"], "/api/license_policies/1/copy/") self._check_authentication(["post"], "/api/license_policies/1/apply/") + self._check_authentication(["post"], "/api/license_policies/apply_product/") self._check_authentication(["get", "post"], "/api/license_policy_items/") self._check_authentication( diff --git a/backend/unittests/access_control/api/test_authorization_license_policies.py b/backend/unittests/access_control/api/test_authorization_license_policies.py index d27aced07..e2161d243 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policies.py +++ b/backend/unittests/access_control/api/test_authorization_license_policies.py @@ -1,3 +1,4 @@ +from application.core.models import Product from application.licenses.models import License_Policy from unittests.access_control.api.test_authorization import ( APITest, @@ -258,6 +259,59 @@ def test_authorization_license_policies(self): ) ) + product_1 = Product.objects.get(pk=1) + license_policy_1000 = License_Policy.objects.get(pk=1000) + product_1.license_policy = license_policy_1000 + product_1.save() + + self._test_api( + APITest( + "db_admin", + "post", + "/api/license_policies/apply_product/?product=1", + None, + 204, + None, + no_second_user=False, + ) + ) + + self._test_api( + APITest( + "db_internal_write", + "post", + "/api/license_policies/apply_product/?product=1", + None, + 204, + None, + no_second_user=False, + ) + ) + + self._test_api( + APITest( + "db_internal_read", + "post", + "/api/license_policies/apply_product/?product=1", + None, + 403, + None, + no_second_user=False, + ) + ) + + self._test_api( + APITest( + "db_external", + "post", + "/api/license_policies/apply_product/?product=1", + None, + 403, + None, + no_second_user=False, + ) + ) + self._test_api( APITest( "db_internal_write", From 1bf6d0aac03d258e34f0dcc3a1a65bd5a5541c8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:08:05 +0100 Subject: [PATCH 20/30] chore(deps): update dependency prettier to v3.4.1 (#2274) 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 97deaf0ca..8e127f802 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -53,7 +53,7 @@ "eslint-plugin-react-hooks": "rc", "eslint-plugin-security": "3.0.1", "globals": "15.12.0", - "prettier": "3.4.0", + "prettier": "3.4.1", "rewire": "7.0.0", "typescript": "5.7.2", "vite": "5.4.11" @@ -7227,9 +7227,9 @@ } }, "node_modules/prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.0.tgz", - "integrity": "sha512-/OXNZcLyWkfo13ofOW5M7SLh+k5pnIs07owXK2teFpnfaOEcycnSy7HQxldaVX1ZP/7Q8oO1eDuQJNwbomQq5Q==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, "license": "MIT", "bin": { diff --git a/frontend/package.json b/frontend/package.json index 104356b68..71c006d95 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -62,7 +62,7 @@ "eslint-plugin-react-hooks": "rc", "eslint-plugin-security": "3.0.1", "globals": "15.12.0", - "prettier": "3.4.0", + "prettier": "3.4.1", "rewire": "7.0.0", "typescript": "5.7.2", "vite": "5.4.11" From be675a16c9cc0ea52fed8c1867951da68d8dabea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:38:01 +0100 Subject: [PATCH 21/30] chore(deps): update dependency @vitejs/plugin-react to v4.3.4 (#2270) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8e127f802..66f81fec9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "@types/recharts": "1.8.29", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", - "@vitejs/plugin-react": "4.3.3", + "@vitejs/plugin-react": "4.3.4", "eslint": "9.15.0", "eslint-plugin-react": "7.37.2", "eslint-plugin-react-hooks": "rc", @@ -3506,15 +3506,15 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", - "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, @@ -3522,7 +3522,7 @@ "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/acorn": { diff --git a/frontend/package.json b/frontend/package.json index 71c006d95..d63a3116a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -56,7 +56,7 @@ "@types/recharts": "1.8.29", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", - "@vitejs/plugin-react": "4.3.3", + "@vitejs/plugin-react": "4.3.4", "eslint": "9.15.0", "eslint-plugin-react": "7.37.2", "eslint-plugin-react-hooks": "rc", From f83ad108e974e3ba5c4b4ab73f8aae782df2f8a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:42:19 +0100 Subject: [PATCH 22/30] chore(deps): update docker/build-push-action action to v6.10.0 (#2271) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build_push_dev.yml | 4 ++-- .github/workflows/build_push_release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_push_dev.yml b/.github/workflows/build_push_dev.yml index 3a9fadb08..1d0c0d3ad 100644 --- a/.github/workflows/build_push_dev.yml +++ b/.github/workflows/build_push_dev.yml @@ -28,7 +28,7 @@ jobs: run: echo "CREATED=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_ENV - name: Build and push backend - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: context: . file: ./docker/backend/prod/django/Dockerfile @@ -40,7 +40,7 @@ jobs: VERSION=dev - name: Build and push frontend - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: context: . file: ./docker/frontend/prod/Dockerfile diff --git a/.github/workflows/build_push_release.yml b/.github/workflows/build_push_release.yml index 95cc04697..2c3a24b74 100644 --- a/.github/workflows/build_push_release.yml +++ b/.github/workflows/build_push_release.yml @@ -36,7 +36,7 @@ jobs: run: echo "CREATED=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_ENV - name: Build and push backend - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: context: . file: ./docker/backend/prod/django/Dockerfile @@ -50,7 +50,7 @@ jobs: VERSION=${{ github.event.inputs.release }} - name: Build and push frontend - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: context: . file: ./docker/frontend/prod/Dockerfile From b3787a8b7ee92e783dc9d5c1edc463024a087d8d Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 27 Nov 2024 07:25:11 +0000 Subject: [PATCH 23/30] feat: evaluate license expressions (#2275) --- backend/application/licenses/api/filters.py | 42 +- .../application/licenses/api/serializers.py | 13 +- backend/application/licenses/api/views.py | 7 + ...e_component_license_expression_and_more.py | 23 + backend/application/licenses/models.py | 2 + .../licenses/queries/license_component.py | 8 +- .../licenses/services/license_component.py | 28 +- .../licenses/services/license_policy.py | 89 + backend/poetry.lock | 43 +- backend/pyproject.toml | 1 + .../test_authorization_license_components.py | 6 +- ...test_authorization_license_policy_items.py | 16 +- .../import_observations_fixtures.json | 2 +- .../cyclone_dx/files/changed/licenses_1.json | 12 +- .../parsers/cyclone_dx/files/licenses_1.json | 3179 ++++++++++++++++- .../services/test_import_observations.py | 112 + .../licenses/api/test_serializers.py | 5 +- docs/getting_started/data_model.md | 6 +- docs/usage/license_management.md | 9 +- .../LicenseComponentEmbeddedList.tsx | 5 + .../LicenseComponentOverview.tsx | 25 +- .../LicenseComponentShow.tsx | 7 +- .../LicensePolicyItemAdd.tsx | 12 + .../LicensePolicyItemEdit.tsx | 9 + .../LicensePolicyItemEmbeddedList.tsx | 2 + 25 files changed, 3615 insertions(+), 48 deletions(-) create mode 100644 backend/application/licenses/migrations/0009_license_component_license_expression_and_more.py diff --git a/backend/application/licenses/api/filters.py b/backend/application/licenses/api/filters.py index b1f17d61b..92e64a8b2 100644 --- a/backend/application/licenses/api/filters.py +++ b/backend/application/licenses/api/filters.py @@ -30,6 +30,10 @@ class LicenseComponentFilter(FilterSet): name_version = CharFilter(field_name="name_version", lookup_expr="icontains") license_spdx_id = CharFilter(field_name="license__spdx_id", lookup_expr="icontains") license_spdx_id_exact = CharFilter(field_name="license__spdx_id") + license_expression = CharFilter( + field_name="license_expression", lookup_expr="icontains" + ) + license_expression_exact = CharFilter(field_name="license_expression") unknown_license = CharFilter(field_name="unknown_license", lookup_expr="icontains") unknown_license_exact = CharFilter(field_name="unknown_license") age = ChoiceFilter( @@ -61,11 +65,13 @@ def get_no_license( # tuple-mapping retains order fields=( ("license__spdx_id", "license_data.spdx_id"), + ("license_expression", "license_expression"), ("unknown_license", "unknown_license"), ( ( "numerical_evaluation_result", "license__spdx_id", + "license_expression", "unknown_license", "name_version", ), @@ -84,6 +90,7 @@ class Meta: "product", "branch", "license_spdx_id", + "license_expression", "unknown_license", "evaluation_result", "name_version", @@ -249,6 +256,9 @@ class LicensePolicyItemFilter(FilterSet): field_name="license_group__name", lookup_expr="icontains" ) license_spdx_id = CharFilter(field_name="license__spdx_id", lookup_expr="icontains") + license_expression = CharFilter( + field_name="license_expression", lookup_expr="icontains" + ) unknown_license = CharFilter(field_name="unknown_license", lookup_expr="icontains") ordering = ExtendedOrderingFilter( @@ -256,15 +266,39 @@ class LicensePolicyItemFilter(FilterSet): fields=( ("license_policy__name", "license_policy_data.name"), ( - ("license_group__name", "license__spdx_id", "unknown_license"), + ( + "license_group__name", + "license__spdx_id", + "license_expression", + "unknown_license", + ), "license_group_name", ), ( - ("license__spdx_id", "license_group__name", "unknown_license"), + ( + "license__spdx_id", + "license_group__name", + "license_expression", + "unknown_license", + ), "license_spdx_id", ), ( - ("unknown_license", "license_group__name", "license__spdx_id"), + ( + "license_expression", + "license_group__name", + "license__spdx_id", + "unknown_license", + ), + "license_expression", + ), + ( + ( + "unknown_license", + "license_group__name", + "license__spdx_id", + "license_expression", + ), "unknown_license", ), ( @@ -272,6 +306,7 @@ class LicensePolicyItemFilter(FilterSet): "numerical_evaluation_result", "license_group__name", "license__spdx_id", + "license_expression", "unknown_license", ), "evaluation_result", @@ -285,6 +320,7 @@ class Meta: "license_policy", "license_group_name", "license_spdx_id", + "license_expression", "unknown_license", "evaluation_result", "license_group_name", diff --git a/backend/application/licenses/api/serializers.py b/backend/application/licenses/api/serializers.py index 4932bf984..201e483fb 100644 --- a/backend/application/licenses/api/serializers.py +++ b/backend/application/licenses/api/serializers.py @@ -139,6 +139,8 @@ def get_license_policy_id(self, obj: License_Component) -> int: def get_title(self, obj: License_Component) -> str: if obj.license: return f"{obj.license.spdx_id} ({obj.license.name})" + if obj.license_expression: + return obj.license_expression if obj.unknown_license: return obj.unknown_license return "No license" @@ -170,6 +172,7 @@ class LicenseComponentOverviewElementSerializer(Serializer): branch_name = CharField() spdx_id = CharField() license_name = CharField() + license_expression = CharField() unknown_license = CharField() evaluation_result = CharField() num_components = IntegerField() @@ -397,15 +400,18 @@ def validate(self, attrs: dict): self.instance: License_Policy_Item data_license_group = attrs.get("license_group") data_license = attrs.get("license") + data_license_expression = attrs.get("license_expression", "") data_unknown_license = attrs.get("unknown_license", "") if self.instance: self.instance.license_group = data_license_group self.instance.license = data_license + self.instance.license_expression = data_license_expression self.instance.unknown_license = data_unknown_license num_fields = ( bool(self.instance.license_group) + bool(self.instance.license) + + bool(self.instance.license_expression) + bool(self.instance.unknown_license) ) try: @@ -413,6 +419,7 @@ def validate(self, attrs: dict): license_policy=self.instance.license_policy, license_group=self.instance.license_group, license=self.instance.license, + license_expression=self.instance.license_expression, unknown_license=self.instance.unknown_license, ) if item.pk != self.instance.pk: @@ -423,6 +430,7 @@ def validate(self, attrs: dict): num_fields = ( bool(data_license_group) + bool(data_license) + + bool(data_license_expression) + bool(data_unknown_license) ) try: @@ -430,6 +438,7 @@ def validate(self, attrs: dict): license_policy=attrs.get("license_policy"), license_group=data_license_group, license=data_license, + license_expression=data_license_expression, unknown_license=data_unknown_license, ) raise ValidationError("License policy item already exists") @@ -438,11 +447,11 @@ def validate(self, attrs: dict): if num_fields == 0: raise ValidationError( - "One of license group, license or unknown license must be set" + "One of license group, license, license expression or unknown license must be set" ) if num_fields > 1: raise ValidationError( - "Only one of license group, license or unknown license must be set" + "Only one of license group, license, license expression or unknown license must be set" ) return attrs diff --git a/backend/application/licenses/api/views.py b/backend/application/licenses/api/views.py index cd44c2878..384a2062d 100644 --- a/backend/application/licenses/api/views.py +++ b/backend/application/licenses/api/views.py @@ -114,6 +114,7 @@ class LicenseComponentOverviewElement: branch_name: Optional[str] spdx_id: Optional[str] license_name: Optional[str] + license_expression: Optional[str] unknown_license: Optional[str] evaluation_result: str num_components: int @@ -157,6 +158,7 @@ def license_overview(self, request): product = _get_product(product_id, Permissions.Product_View) branch = self._get_branch(product, request.query_params.get("branch")) spdx_id = request.query_params.get("spdx_id") + license_expression = request.query_params.get("license_expression") unknown_license = request.query_params.get("unknown_license") evaluation_result = request.query_params.get("evaluation_result") purl_type = request.query_params.get("purl_type") @@ -166,6 +168,10 @@ def license_overview(self, request): license_overview_elements = license_overview_elements.filter( license__spdx_id__icontains=spdx_id ) + if license_expression: + license_overview_elements = license_overview_elements.filter( + license_expression__icontains=license_expression + ) if unknown_license: license_overview_elements = license_overview_elements.filter( unknown_license__icontains=unknown_license @@ -185,6 +191,7 @@ def license_overview(self, request): branch_name=element["branch__name"], spdx_id=element["license__spdx_id"], license_name=element["license__name"], + license_expression=element["license_expression"], unknown_license=element["unknown_license"], evaluation_result=element["evaluation_result"], num_components=element["id__count"], diff --git a/backend/application/licenses/migrations/0009_license_component_license_expression_and_more.py b/backend/application/licenses/migrations/0009_license_component_license_expression_and_more.py new file mode 100644 index 000000000..da9123e16 --- /dev/null +++ b/backend/application/licenses/migrations/0009_license_component_license_expression_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.3 on 2024-11-26 19:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("licenses", "0008_alter_license_policy_item_license_group"), + ] + + operations = [ + migrations.AddField( + model_name="license_component", + name="license_expression", + field=models.CharField(blank=True, max_length=255), + ), + migrations.AddField( + model_name="license_policy_item", + name="license_expression", + field=models.CharField(blank=True, max_length=255), + ), + ] diff --git a/backend/application/licenses/models.py b/backend/application/licenses/models.py index ea1cb152f..d6a0c95ac 100644 --- a/backend/application/licenses/models.py +++ b/backend/application/licenses/models.py @@ -121,6 +121,7 @@ class License_Component(Model): blank=True, null=True, ) + license_expression = CharField(max_length=255, blank=True) unknown_license = CharField(max_length=255, blank=True) evaluation_result = CharField( max_length=16, @@ -206,6 +207,7 @@ class License_Policy_Item(Model): blank=True, null=True, ) + license_expression = CharField(max_length=255, blank=True) unknown_license = CharField(max_length=255, blank=True) evaluation_result = CharField( max_length=16, choices=License_Policy_Evaluation_Result.RESULT_CHOICES diff --git a/backend/application/licenses/queries/license_component.py b/backend/application/licenses/queries/license_component.py index 780df0fb7..ce8482704 100644 --- a/backend/application/licenses/queries/license_component.py +++ b/backend/application/licenses/queries/license_component.py @@ -80,9 +80,15 @@ def get_license_component_licenses( "branch__name", "license__spdx_id", "license__name", + "license_expression", "unknown_license", "evaluation_result", ) .annotate(Count("id")) - .order_by("numerical_evaluation_result", "license__spdx_id", "unknown_license") + .order_by( + "numerical_evaluation_result", + "license__spdx_id", + "license_expression", + "unknown_license", + ) ) diff --git a/backend/application/licenses/services/license_component.py b/backend/application/licenses/services/license_component.py index 1e49feeb8..0aaf2b3b9 100644 --- a/backend/application/licenses/services/license_component.py +++ b/backend/application/licenses/services/license_component.py @@ -3,6 +3,7 @@ from django.db.models.query import QuerySet from django.utils import timezone +from license_expression import get_spdx_licensing from packageurl import PackageURL from rest_framework.exceptions import ValidationError @@ -83,6 +84,7 @@ def process_license_components( existing_component.cpe = unsaved_component.cpe existing_component.dependencies = unsaved_component.dependencies existing_component.license = unsaved_component.license + existing_component.license_expression = unsaved_component.license_expression existing_component.unknown_license = unsaved_component.unknown_license apply_license_policy_to_component( existing_component, @@ -170,11 +172,7 @@ def _prepare_component(component: License_Component) -> None: if component.purl_type is None: component.purl_type = "" - if component.unsaved_license: - component.license = get_license_by_spdx_id(component.unsaved_license) - component.unknown_license = "" - if not component.license: - component.unknown_license = component.unsaved_license + _prepare_license(component) component.identity_hash = get_identity_hash(component) @@ -198,6 +196,26 @@ def _prepare_name_version(component: License_Component) -> None: component.version = "" +def _prepare_license(component: License_Component) -> None: + component.license_expression = "" + component.unknown_license = "" + + if component.unsaved_license: + component.license = get_license_by_spdx_id(component.unsaved_license) + if not component.license: + licensing = get_spdx_licensing() + try: + expression_info = licensing.validate( + component.unsaved_license, strict=True + ) + if not expression_info.errors: + component.license_expression = expression_info.normalized_expression + else: + component.unknown_license = component.unsaved_license + except Exception: + component.unknown_license = component.unsaved_license + + def license_components_bulk_delete(product: Product, component_ids: list[int]) -> None: components = _check_components(product, component_ids) components.delete() diff --git a/backend/application/licenses/services/license_policy.py b/backend/application/licenses/services/license_policy.py index 50d90a783..7e2068649 100644 --- a/backend/application/licenses/services/license_policy.py +++ b/backend/application/licenses/services/license_policy.py @@ -2,6 +2,7 @@ from django.db.models import Q from django.utils import timezone +from license_expression import LicenseSymbol, get_spdx_licensing from application.core.models import Product from application.licenses.models import ( @@ -10,6 +11,7 @@ License_Policy_Item, License_Policy_Member, ) +from application.licenses.queries.license import get_license_by_spdx_id from application.licenses.types import License_Policy_Evaluation_Result @@ -39,6 +41,14 @@ def get_license_evaluation_results(product: Product) -> dict: item.evaluation_result ) + items_license_expressions = License_Policy_Item.objects.filter( + license_policy=license_policy + ).exclude(license_expression="") + for item in items_license_expressions: + license_evaluation_results[f"expression_{item.license_expression}"] = ( + item.evaluation_result + ) + items_unknown_licenses = License_Policy_Item.objects.filter( license_policy=license_policy ).exclude(unknown_license="") @@ -60,6 +70,12 @@ def apply_license_policy_to_component( evaluation_result = License_Policy_Evaluation_Result.RESULT_IGNORED elif component.license: evaluation_result = evaluation_results.get(f"spdx_{component.license.spdx_id}") + elif component.license_expression: + evaluation_result = _evaluate_license_expression(component, evaluation_results) + if not evaluation_result: + evaluation_result = evaluation_results.get( + f"expression_{component.license_expression}" + ) elif component.unknown_license: evaluation_result = evaluation_results.get( f"unknown_{component.unknown_license}" @@ -159,3 +175,76 @@ def _get_license_policy(product: Product) -> Optional[License_Policy]: return product.product_group.license_policy return None + + +def _evaluate_license_expression( + component: License_Component, evaluation_results: dict +) -> Optional[str]: + evaluation_result = None + + try: + licensing = get_spdx_licensing() + parsed_expression = licensing.parse( + component.license_expression, validate=True, strict=True + ) + + operator = parsed_expression.operator.strip().upper() + if operator not in ["AND", "OR"]: + return evaluation_result + + licenses = [] + for arg in parsed_expression.args: + if isinstance(arg, LicenseSymbol): + my_license = get_license_by_spdx_id(arg.key) + if not my_license: + return evaluation_result + licenses.append(my_license) + else: + return evaluation_result + + evaluation_result_set = set() + for my_license in licenses: + evaluation_result_set.add( + evaluation_results.get(f"spdx_{my_license.spdx_id}") + ) + + if operator == "AND": + evaluation_result = _evaluate_and_expression(evaluation_result_set) + + if operator == "OR": + evaluation_result = _evaluate_or_expression(evaluation_result_set) + + except Exception: + pass + + return evaluation_result + + +def _evaluate_and_expression(evaluation_result_set: set) -> str: + evaluation_result_set.discard(License_Policy_Evaluation_Result.RESULT_IGNORED) + if not evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_UNKNOWN + + if License_Policy_Evaluation_Result.RESULT_FORBIDDEN in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_FORBIDDEN + if License_Policy_Evaluation_Result.RESULT_UNKNOWN in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_UNKNOWN + if License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED + + return License_Policy_Evaluation_Result.RESULT_ALLOWED + + +def _evaluate_or_expression(evaluation_result_set: set) -> str: + evaluation_result_set.discard(License_Policy_Evaluation_Result.RESULT_IGNORED) + if not evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_UNKNOWN + + if License_Policy_Evaluation_Result.RESULT_ALLOWED in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_ALLOWED + if License_Policy_Evaluation_Result.RESULT_UNKNOWN in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_UNKNOWN + if License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED in evaluation_result_set: + return License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED + + return License_Policy_Evaluation_Result.RESULT_FORBIDDEN diff --git a/backend/poetry.lock b/backend/poetry.lock index 8e5f1f662..31140e560 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -171,6 +171,17 @@ d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "boolean-py" +version = "4.0" +description = "Define boolean algebras, create and parse boolean expressions and create custom boolean DSL." +optional = false +python-versions = "*" +files = [ + {file = "boolean.py-4.0-py3-none-any.whl", hash = "sha256:2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd"}, + {file = "boolean.py-4.0.tar.gz", hash = "sha256:17b9a181630e43dde1851d42bef546d616d5d9b4480357514597e78b203d06e4"}, +] + [[package]] name = "certifi" version = "2024.8.30" @@ -1021,13 +1032,13 @@ redis = ["redis (>=3.0.0)"] [[package]] name = "identify" -version = "2.6.2" +version = "2.6.3" description = "File identification library for Python" optional = true python-versions = ">=3.9" files = [ - {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, - {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, + {file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"}, + {file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"}, ] [package.extras] @@ -1248,6 +1259,24 @@ files = [ [package.dependencies] referencing = ">=0.31.0" +[[package]] +name = "license-expression" +version = "30.4.0" +description = "license-expression is a comprehensive utility library to parse, compare, simplify and normalize license expressions (such as SPDX license expressions) using boolean logic." +optional = false +python-versions = ">=3.9" +files = [ + {file = "license_expression-30.4.0-py3-none-any.whl", hash = "sha256:7c8f240c6e20d759cb8455e49cb44a923d9e25c436bf48d7e5b8eea660782c04"}, + {file = "license_expression-30.4.0.tar.gz", hash = "sha256:6464397f8ed4353cc778999caec43b099f8d8d5b335f282e26a9eb9435522f05"}, +] + +[package.dependencies] +"boolean.py" = ">=4.0" + +[package.extras] +docs = ["Sphinx (>=5.0.2)", "doc8 (>=0.11.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-reredirects (>=0.1.2)", "sphinx-rtd-dark-mode (>=1.3.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-apidoc (>=0.4.0)"] +testing = ["black", "isort", "pytest (>=6,!=7.0.0)", "pytest-xdist (>=2)", "twine"] + [[package]] name = "markupsafe" version = "3.0.2" @@ -2446,13 +2475,13 @@ crypto-eth-addresses = ["eth-hash[pycryptodome] (>=0.7.0)"] [[package]] name = "virtualenv" -version = "20.27.1" +version = "20.28.0" description = "Virtual Python Environment builder" optional = true python-versions = ">=3.8" files = [ - {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, - {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, + {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, + {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, ] [package.dependencies] @@ -2514,4 +2543,4 @@ unittests = ["coverage", "django-coverage-plugin", "django-extensions"] [metadata] lock-version = "2.0" python-versions = ">= 3.10, < 3.13" -content-hash = "a635c50582dc36e143d45233e64fe5d7f69d3bae7f460bd4a3274daf2f752de1" +content-hash = "53a983749039fc198d75344e7582213bd37fb63eba195c634ac7afdbb45a53cb" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index da0faa036..9e103bf6a 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -59,6 +59,7 @@ cvss = "3.3" # https://github.com/RedHatProductSecurity/cvss jsonpickle = "4.0.0" # https://github.com/jsonpickle/jsonpickle py-ocsf-models = "0.2.0" # https://github.com/prowler-cloud/py-ocsf-models semver = "3.0.2" # https://github.com/python-semver/python-semver +license-expression = "30.4.0" # https://github.com/aboutcode-org/license-expression # Development dependencies # ------------------------------------------------------------------------------ diff --git a/backend/unittests/access_control/api/test_authorization_license_components.py b/backend/unittests/access_control/api/test_authorization_license_components.py index 47d223ee5..cc2cd823e 100644 --- a/backend/unittests/access_control/api/test_authorization_license_components.py +++ b/backend/unittests/access_control/api/test_authorization_license_components.py @@ -16,14 +16,14 @@ def test_authorization_license_components_product_authorization_group_member(sel self._test_authorization_license_components() def _test_authorization_license_components(self): - expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}, {'id': 2, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'external license', 'identity_hash': 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007', 'upload_filename': '', 'name': 'external_component', 'version': '2.0.0', 'name_version': 'external_component:2.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'unknown_license': 'external license', 'evaluation_result': 'Review required', 'numerical_evaluation_result': 2, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 2, 'branch': None, 'license': None}]}" + expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}, {'id': 2, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'external license', 'identity_hash': 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007', 'upload_filename': '', 'name': 'external_component', 'version': '2.0.0', 'name_version': 'external_component:2.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'external license', 'evaluation_result': 'Review required', 'numerical_evaluation_result': 2, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 2, 'branch': None, 'license': None}]}" self._test_api( APITest( "db_admin", "get", "/api/license_components/", None, 200, expected_data ) ) - expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}]}" + expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}]}" self._test_api( APITest( "db_internal_write", @@ -34,7 +34,7 @@ def _test_authorization_license_components(self): expected_data, ) ) - expected_data = "{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'license_policy_name': '', 'license_policy_id': 0, 'evidences': [{'id': 1, 'name': 'internal_license_evidence_name'}], 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'dependencies': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}" + expected_data = "{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'license_policy_name': '', 'license_policy_id': 0, 'evidences': [{'id': 1, 'name': 'internal_license_evidence_name'}], 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'dependencies': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_license_policy_items.py b/backend/unittests/access_control/api/test_authorization_license_policy_items.py index 879f6f486..bd6544e2d 100644 --- a/backend/unittests/access_control/api/test_authorization_license_policy_items.py +++ b/backend/unittests/access_control/api/test_authorization_license_policy_items.py @@ -9,7 +9,7 @@ class TestAuthorizationLicensePolicyItems(TestAuthorizationBase): def test_authorization_license_policy_items(self): License_Policy.objects.filter(pk__lt=1000).delete() - expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1001, 'license_spdx_id': '0BSD', 'license_group_name': '', 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Forbidden', 'license_policy': 1001, 'license_group': None, 'license': 1}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 5, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1001, 'license_spdx_id': '0BSD', 'license_group_name': '', 'license_policy_data': {'id': 1001, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_read_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Forbidden', 'license_policy': 1001, 'license_group': None, 'license': 1}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_admin", @@ -21,7 +21,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_internal_write", @@ -34,7 +34,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" + expected_data = "{'count': 3, 'next': None, 'previous': None, 'results': [{'id': 1000, 'license_spdx_id': '', 'license_group_name': 'Permissive Model (Blue Oak Council)', 'license_policy_data': {'id': 1000, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': False, 'name': 'public', 'description': '', 'is_public': True, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1000, 'license_group': 1, 'license': None}, {'id': 1003, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1003, 'is_manager': False, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_not_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Three unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1003, 'license_group': None, 'license': None}, {'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1004, 'license_group': None, 'license': None}]}" self._test_api( APITest( "db_product_group_user", @@ -47,7 +47,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}" + expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Unknown', 'license_policy': 1002, 'license_group': None, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -89,7 +89,7 @@ def test_authorization_license_policy_items(self): "unknown_license": "", "evaluation_result": "Allowed", } - expected_data = "{'id': 1005, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1002, 'license_group': 2, 'license': None}" + expected_data = "{'id': 1005, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1002, 'license_group': 2, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -129,7 +129,7 @@ def test_authorization_license_policy_items(self): "unknown_license": "", "evaluation_result": "Allowed", } - expected_data = "{'id': 1006, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1004, 'license_group': 2, 'license': None}" + expected_data = "{'id': 1006, 'license_spdx_id': '', 'license_group_name': 'Permissive Gold (Blue Oak Council)', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': '', 'evaluation_result': 'Allowed', 'license_policy': 1004, 'license_group': 2, 'license': None}" self._test_api( APITest( "db_product_group_user", @@ -181,7 +181,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1002, 'license_group': None, 'license': None}" + expected_data = "{'id': 1002, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1002, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': True, 'has_authorization_groups': False, 'name': 'internal_write_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Two unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1002, 'license_group': None, 'license': None}" self._test_api( APITest( "db_internal_write", @@ -212,7 +212,7 @@ def test_authorization_license_policy_items(self): ) ) - expected_data = "{'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1004, 'license_group': None, 'license': None}" + expected_data = "{'id': 1004, 'license_spdx_id': '', 'license_group_name': '', 'license_policy_data': {'id': 1004, 'is_manager': True, 'has_products': False, 'has_product_groups': False, 'has_items': True, 'has_users': False, 'has_authorization_groups': True, 'name': 'authorization_group_manager', 'description': '', 'is_public': False, 'ignore_component_types': ''}, 'license_expression': '', 'unknown_license': 'Four unknown licenses', 'evaluation_result': 'Review required', 'license_policy': 1004, 'license_group': None, 'license': None}" self._test_api( APITest( "db_product_group_user", diff --git a/backend/unittests/fixtures/import_observations_fixtures.json b/backend/unittests/fixtures/import_observations_fixtures.json index 003aa61c4..c106c77ea 100644 --- a/backend/unittests/fixtures/import_observations_fixtures.json +++ b/backend/unittests/fixtures/import_observations_fixtures.json @@ -62,7 +62,7 @@ "pk": 1, "fields": { "product": 1, - "user": 5, + "user": 1, "role": 5 } }, diff --git a/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json b/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json index 0ce6caf37..858441b53 100644 --- a/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json +++ b/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json @@ -394,7 +394,7 @@ ], "licenses": [ { - "expression": "Apache-2.0 OR BSD-3-Clause" + "expression": "LGPL-3.0-or-later OR GPL-3.0-or-later" } ], "purl": "pkg:pypi/cryptography@43.0.1", @@ -438,10 +438,7 @@ ], "licenses": [ { - "license": { - "id": "LGPL-3.0-or-later", - "url": "https://opensource.org/licenses/LGPL-3.0-or-later" - } + "expression": "LGPL-3.0-or-later AND BSD-3-Clause" } ], "purl": "pkg:pypi/cvss@3.2", @@ -481,10 +478,7 @@ ], "licenses": [ { - "license": { - "id": "Apache-2.0", - "url": "https://opensource.org/licenses/Apache-2.0" - } + "expression": "Apache-2.0 AND (BSD-3-Clause OR MIT)" } ], "purl": "pkg:pypi/defusedcsv@2.0.0", diff --git a/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json b/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json index 5b6931071..1356dfdef 100644 --- a/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json +++ b/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json @@ -1 +1,3178 @@ -{"bomFormat":"CycloneDX","specVersion":"1.5","serialNumber":"urn:uuid:12f6dd75-f31f-48a8-8b59-c7c9f87d68c9","version":1,"metadata":{"timestamp":"2024-10-22T12:15:48Z","tools":{"components":[{"group":"@cyclonedx","name":"cdxgen","version":"10.10.6","purl":"pkg:npm/%40cyclonedx/cdxgen@10.10.6","type":"application","bom-ref":"pkg:npm/@cyclonedx/cdxgen@10.10.6","author":"OWASP Foundation","publisher":"OWASP Foundation"}]},"authors":[{"name":"OWASP Foundation"}],"lifecycles":[{"phase":"build"}],"component":{"name":"SecObserve","version":"1.22.4","description":"SecObserve is an open source vulnerability management system for software development and cloud environments.","type":"application","bom-ref":"pkg:pypi/secobserve@1.22.4","purl":"pkg:pypi/secobserve@1.22.4"},"properties":[{"name":"cdx:bom:componentTypes","value":"pypi"}]},"components":[{"author":"Hynek Schlawack ","group":"","name":"argon2-cffi-bindings","version":"21.2.0","description":"Low-level CFFI bindings for Argon2","hashes":[{"alg":"SHA-256","content":"ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/argon2-cffi-bindings@21.2.0","externalReferences":[{"type":"vcs","url":"https://github.com/hynek/argon2-cffi-bindings"}],"type":"library","bom-ref":"pkg:pypi/argon2-cffi-bindings@21.2.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Hynek Schlawack ","group":"","name":"argon2-cffi","version":"23.1.0","description":"Argon2 for Python","hashes":[{"alg":"SHA-256","content":"c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/argon2-cffi@23.1.0","type":"library","bom-ref":"pkg:pypi/argon2-cffi@23.1.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Django Software Foundation ","group":"","name":"asgiref","version":"3.8.1","description":"ASGI specs, helper code, and adapters","hashes":[{"alg":"SHA-256","content":"3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}},{"license":{"id":"BSD-3-Clause","url":"https://opensource.org/licenses/BSD-3-Clause"}}],"purl":"pkg:pypi/asgiref@3.8.1","externalReferences":[{"type":"vcs","url":"https://github.com/django/asgiref/"}],"type":"library","bom-ref":"pkg:pypi/asgiref@3.8.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Hynek Schlawack ","group":"","name":"attrs","version":"24.2.0","description":"Classes Without Boilerplate","hashes":[{"alg":"SHA-256","content":"81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/attrs@24.2.0","type":"library","bom-ref":"pkg:pypi/attrs@24.2.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Eric Larson , Frost Ming , William Woodruff ","group":"","name":"CacheControl","version":"0.14.0","description":"httplib2 caching for requests","hashes":[{"alg":"SHA-256","content":"f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/cachecontrol@0.14.0","type":"library","bom-ref":"pkg:pypi/cachecontrol@0.14.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"instrumentation","confidence":1,"value":"/tmp/cdxgen-venv-43yYKx"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]},{"author":"Kenneth Reitz ","group":"","name":"certifi","version":"2024.8.30","description":"Python package for providing Mozilla's CA Bundle.","hashes":[{"alg":"SHA-256","content":"922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}],"licenses":[{"license":{"id":"MPL-2.0","url":"https://opensource.org/licenses/MPL-2.0"}}],"purl":"pkg:pypi/certifi@2024.8.30","externalReferences":[{"type":"vcs","url":"https://github.com/certifi/python-certifi"}],"type":"library","bom-ref":"pkg:pypi/certifi@2024.8.30","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Armin Rigo, Maciej Fijalkowski ","group":"","name":"cffi","version":"1.17.1","description":"Foreign Function Interface for Python calling C code.","hashes":[{"alg":"SHA-256","content":"df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/cffi@1.17.1","externalReferences":[{"type":"website","url":"http://cffi.readthedocs.org"}],"type":"library","bom-ref":"pkg:pypi/cffi@1.17.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Ahmed TAHRI ","group":"","name":"charset-normalizer","version":"3.4.0","description":"The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.","hashes":[{"alg":"SHA-256","content":"4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/charset-normalizer@3.4.0","externalReferences":[{"type":"vcs","url":"https://github.com/Ousret/charset_normalizer"}],"type":"library","bom-ref":"pkg:pypi/charset-normalizer@3.4.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"The cryptography developers >","group":"","name":"cryptography","version":"43.0.1","description":"cryptography is a package which provides cryptographic recipes and primitives to Python developers.","hashes":[{"alg":"SHA-256","content":"8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}],"licenses":[{"expression":"Apache-2.0 OR BSD-3-Clause"}],"purl":"pkg:pypi/cryptography@43.0.1","type":"library","bom-ref":"pkg:pypi/cryptography@43.0.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}},"properties":[{"name":"cdx:pypi:latest_version","value":"43.0.3"},{"name":"cdx:pypi:resolved_from","value":"cryptography"}]},{"author":"Stanislav Kontar, Red Hat Product Security ","group":"","name":"cvss","version":"3.2","description":"CVSS2/3/4 library with interactive calculator for Python 2 and Python 3","hashes":[{"alg":"SHA-256","content":"e2c2fbc8943c6df83d23c7ad74bb9c5e584c666a9455b013b598e292e5018469"}],"licenses":[{"license":{"id":"LGPL-3.0-or-later","url":"https://opensource.org/licenses/LGPL-3.0-or-later"}}],"purl":"pkg:pypi/cvss@3.2","externalReferences":[{"type":"vcs","url":"https://github.com/RedHatProductSecurity/cvss"}],"type":"library","bom-ref":"pkg:pypi/cvss@3.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Raphael Michel ","group":"","name":"defusedcsv","version":"2.0.0","description":"Drop-in replacement for Python's CSV library that tries to mitigate CSV injection attacks","hashes":[{"alg":"SHA-256","content":"a7bc3b1ac1ce4f8c6c1e8740466b1b5789b51ca18d918b0099313dc0cdf2cef4"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/defusedcsv@2.0.0","externalReferences":[{"type":"vcs","url":"https://github.com/raphaelm/defusedcsv"}],"type":"library","bom-ref":"pkg:pypi/defusedcsv@2.0.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Christian Heimes ","group":"","name":"defusedxml","version":"0.7.1","description":"XML bomb protection for Python stdlib modules","hashes":[{"alg":"SHA-256","content":"a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}],"licenses":[{"license":{"id":"PSF-2.0","url":"https://opensource.org/licenses/PSF-2.0"}}],"purl":"pkg:pypi/defusedxml@0.7.1","externalReferences":[{"type":"vcs","url":"https://github.com/tiran/defusedxml"}],"type":"library","bom-ref":"pkg:pypi/defusedxml@0.7.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Otto Yiu ","group":"","name":"django-cors-headers","version":"4.5.0","description":"django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS).","hashes":[{"alg":"SHA-256","content":"28c1ded847aa70208798de3e42422a782f427b8b720e8d7319d34b654b5978e6"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/django-cors-headers@4.5.0","type":"framework","bom-ref":"pkg:pypi/django-cors-headers@4.5.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"James Socol ","group":"","name":"django-csp","version":"3.8","description":"Django Content Security Policy support.","hashes":[{"alg":"SHA-256","content":"19b2978b03fcd73517d7d67acbc04fbbcaec0facc3e83baa502965892d1e0719"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/django-csp@3.8","type":"framework","bom-ref":"pkg:pypi/django-csp@3.8","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Scott Sharkey ","group":"","name":"django-encrypted-model-fields","version":"0.6.5","description":"A set of fields that wrap standard Django fields with encryption provided by the python cryptography library.","hashes":[{"alg":"SHA-256","content":"b21bbdd8ae2e1a0ea37a5049b3ba46e6e63bf287ad241219a058fac1070796cc"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/django-encrypted-model-fields@0.6.5","externalReferences":[{"type":"vcs","url":"https://gitlab.com/lansharkconsulting/django/django-encrypted-model-fields"}],"type":"framework","bom-ref":"pkg:pypi/django-encrypted-model-fields@0.6.5","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Daniele Faraglia ","group":"","name":"django-environ","version":"0.11.2","description":"A package that allows you to utilize 12factor inspired environment variables to configure your Django application.","hashes":[{"alg":"SHA-256","content":"0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/django-environ@0.11.2","externalReferences":[{"type":"website","url":"https://django-environ.readthedocs.org"}],"type":"framework","bom-ref":"pkg:pypi/django-environ@0.11.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Alex Gaynor ","group":"","name":"django-filter","version":"24.3","description":"Django-filter is a reusable Django application for allowing users to filter querysets dynamically.","hashes":[{"alg":"SHA-256","content":"c4852822928ce17fb699bcfccd644b3574f1a2d80aeb2b4ff4f16b02dd49dc64"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/django-filter@24.3","type":"framework","bom-ref":"pkg:pypi/django-filter@24.3","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Simon Charette ","group":"","name":"django-picklefield","version":"3.2","description":"Pickled object field for Django","hashes":[{"alg":"SHA-256","content":"e9a73539d110f69825d9320db18bcb82e5189ff48dbed41821c026a20497764c"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/django-picklefield@3.2","externalReferences":[{"type":"vcs","url":"http://github.com/gintas/django-picklefield"}],"type":"framework","bom-ref":"pkg:pypi/django-picklefield@3.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Django Software Foundation ","group":"","name":"Django","version":"5.1.2","description":"A high-level Python web framework that encourages rapid development and clean, pragmatic design.","hashes":[{"alg":"SHA-256","content":"f11aa87ad8d5617171e3f77e1d5d16f004b79a2cf5d2e1d2b97a6a1f8e9ba5ed"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}},{"license":{"id":"BSD-3-Clause","url":"https://opensource.org/licenses/BSD-3-Clause"}}],"purl":"pkg:pypi/django@5.1.2","type":"framework","bom-ref":"pkg:pypi/django@5.1.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Tom Christie ","group":"","name":"djangorestframework","version":"3.15.2","description":"Web APIs for Django, made easy.","hashes":[{"alg":"SHA-256","content":"2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/djangorestframework@3.15.2","externalReferences":[{"type":"website","url":"https://www.django-rest-framework.org/"}],"type":"framework","bom-ref":"pkg:pypi/djangorestframework@3.15.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Bob Halley ","group":"","name":"dnspython","version":"2.7.0","description":"DNS toolkit","hashes":[{"alg":"SHA-256","content":"b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}],"licenses":[{"license":{"id":"ISC","url":"https://opensource.org/licenses/ISC"}}],"purl":"pkg:pypi/dnspython@2.7.0","type":"library","bom-ref":"pkg:pypi/dnspython@2.7.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"T. Franzel ","group":"","name":"drf-spectacular-sidecar","version":"2024.7.1","description":"Serve self-contained distribution builds of Swagger UI and Redoc with Django","hashes":[{"alg":"SHA-256","content":"5dc8b38ad153e90b328152674c7959bf114bf86360a617a5a4516e135cb832bc"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/drf-spectacular-sidecar@2024.7.1","externalReferences":[{"type":"vcs","url":"https://github.com/tfranzel/drf-spectacular-sidecar"}],"type":"library","bom-ref":"pkg:pypi/drf-spectacular-sidecar@2024.7.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"T. Franzel ","group":"","name":"drf-spectacular","version":"0.27.2","description":"Sane and flexible OpenAPI 3 schema generation for Django REST framework","hashes":[{"alg":"SHA-256","content":"b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/drf-spectacular@0.27.2","externalReferences":[{"type":"vcs","url":"https://github.com/tfranzel/drf-spectacular"}],"type":"framework","bom-ref":"pkg:pypi/drf-spectacular@0.27.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Joshua Tauberer ","group":"","name":"email-validator","version":"2.1.1","description":"A robust email address syntax and deliverability validation library.","hashes":[{"alg":"SHA-256","content":"97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}],"licenses":[{"expression":"The Unlicense (Unlicense)"}],"purl":"pkg:pypi/email-validator@2.1.1","externalReferences":[{"type":"vcs","url":"https://github.com/JoshData/python-email-validator"}],"type":"library","bom-ref":"pkg:pypi/email-validator@2.1.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}},"properties":[{"name":"cdx:pypi:latest_version","value":"2.2.0"},{"name":"cdx:pypi:resolved_from","value":"email-validator"}]},{"author":"See ATUHORS.txt ","group":"","name":"et-xmlfile","version":"1.1.0","description":"An implementation of lxml.xmlfile for the standard library","hashes":[{"alg":"SHA-256","content":"a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/et-xmlfile@1.1.0","externalReferences":[{"type":"website","url":"https://foss.heptapod.net/openpyxl/et_xmlfile"}],"type":"library","bom-ref":"pkg:pypi/et-xmlfile@1.1.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Benoit Chesneau ","group":"","name":"gunicorn","version":"23.0.0","description":"WSGI HTTP Server for UNIX","hashes":[{"alg":"SHA-256","content":"ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/gunicorn@23.0.0","type":"library","bom-ref":"pkg:pypi/gunicorn@23.0.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Charles Leifer ","group":"","name":"huey","version":"2.5.2","description":"huey, a little task queue","hashes":[{"alg":"SHA-256","content":"df33db474c05414ed40ee2110e9df692369871734da22d74ffb035a4bd74047f"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/huey@2.5.2","externalReferences":[{"type":"vcs","url":"http://github.com/coleifer/huey/"}],"type":"library","bom-ref":"pkg:pypi/huey@2.5.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Kim Davies ","group":"","name":"idna","version":"3.10","description":"Internationalized Domain Names in Applications (IDNA)","hashes":[{"alg":"SHA-256","content":"946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/idna@3.10","type":"library","bom-ref":"pkg:pypi/idna@3.10","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"\"Jason R. Coombs\" ","group":"","name":"importlib-metadata","version":"8.5.0","description":"Read metadata from Python packages","hashes":[{"alg":"SHA-256","content":"45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/importlib-metadata@8.5.0","type":"library","bom-ref":"pkg:pypi/importlib-metadata@8.5.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"instrumentation","confidence":1,"value":"/tmp/cdxgen-venv-43yYKx"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]},{"author":"Paul Dyson ","group":"","name":"inflect","version":"7.4.0","description":"Correctly generate plurals, singular nouns, ordinals, indefinite articles","hashes":[{"alg":"SHA-256","content":"85af0997ee2bda942b1c1eed8c8a827abda91aa3e22d1efaa0eea817f9350ce7"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/inflect@7.4.0","type":"library","bom-ref":"pkg:pypi/inflect@7.4.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Janne Vanhala ","group":"","name":"inflection","version":"0.5.1","description":"A port of Ruby on Rails inflector to Python","hashes":[{"alg":"SHA-256","content":"f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/inflection@0.5.1","externalReferences":[{"type":"vcs","url":"https://github.com/jpvanhal/inflection"}],"type":"library","bom-ref":"pkg:pypi/inflection@0.5.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Ben Speakmon ","group":"","name":"jira","version":"3.8.0","description":"Python library for interacting with JIRA via REST APIs.","hashes":[{"alg":"SHA-256","content":"12190dc84dad00b8a6c0341f7e8a254b0f38785afdec022bd5941e1184a5a3fb"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}},{"license":{"id":"BSD-2-Clause","url":"https://opensource.org/licenses/BSD-2-Clause"}}],"purl":"pkg:pypi/jira@3.8.0","externalReferences":[{"type":"vcs","url":"https://github.com/pycontribs/jira"}],"type":"library","bom-ref":"pkg:pypi/jira@3.8.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"David Aguilar ","group":"","name":"jsonpickle","version":"3.3.0","description":"Python library for serializing arbitrary object graphs into JSON","hashes":[{"alg":"SHA-256","content":"287c12143f35571ab00e224fa323aa4b090d5a7f086f5f494d7ee9c7eb1a380a"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/jsonpickle@3.3.0","externalReferences":[{"type":"vcs","url":"https://github.com/jsonpickle/jsonpickle"}],"type":"library","bom-ref":"pkg:pypi/jsonpickle@3.3.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Julian Berman ","group":"","name":"jsonschema-specifications","version":"2024.10.1","description":"The JSON Schema meta-schemas and vocabularies, exposed as a Registry","hashes":[{"alg":"SHA-256","content":"a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/jsonschema-specifications@2024.10.1","type":"library","bom-ref":"pkg:pypi/jsonschema-specifications@2024.10.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Julian Berman ","group":"","name":"jsonschema","version":"4.23.0","description":"An implementation of JSON Schema validation for Python","hashes":[{"alg":"SHA-256","content":"fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/jsonschema@4.23.0","type":"library","bom-ref":"pkg:pypi/jsonschema@4.23.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Erik Rose ","group":"","name":"more-itertools","version":"10.5.0","description":"More routines for operating on iterables, beyond itertools","hashes":[{"alg":"SHA-256","content":"037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/more-itertools@10.5.0","type":"library","bom-ref":"pkg:pypi/more-itertools@10.5.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Inada Naoki ","group":"","name":"msgpack","version":"1.1.0","description":"MessagePack serializer","hashes":[{"alg":"SHA-256","content":"7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/msgpack@1.1.0","type":"library","bom-ref":"pkg:pypi/msgpack@1.1.0","evidence":{"identity":{"field":"purl","confidence":0.8,"methods":[{"technique":"manifest-analysis","confidence":0.8,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]},{"author":"The OAuthlib Community ","group":"","name":"oauthlib","version":"3.2.2","description":"A generic, spec-compliant, thorough implementation of the OAuth request-signing logic","hashes":[{"alg":"SHA-256","content":"8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}],"licenses":[{"expression":"OSI Approved"}],"purl":"pkg:pypi/oauthlib@3.2.2","externalReferences":[{"type":"vcs","url":"https://github.com/oauthlib/oauthlib"}],"type":"library","bom-ref":"pkg:pypi/oauthlib@3.2.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"See AUTHORS ","group":"","name":"openpyxl","version":"3.1.5","description":"A Python library to read/write Excel 2010 xlsx/xlsm files","hashes":[{"alg":"SHA-256","content":"5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/openpyxl@3.1.5","externalReferences":[{"type":"website","url":"https://openpyxl.readthedocs.io"}],"type":"library","bom-ref":"pkg:pypi/openpyxl@3.1.5","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"the purl authors","group":"","name":"packageurl-python","version":"0.16.0","description":"A purl aka. Package URL parser and builder","hashes":[{"alg":"SHA-256","content":"5c3872638b177b0f1cf01c3673017b7b27ebee485693ae12a8bed70fa7fa7c35"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/packageurl-python@0.16.0","externalReferences":[{"type":"vcs","url":"https://github.com/package-url/packageurl-python"}],"type":"library","bom-ref":"pkg:pypi/packageurl-python@0.16.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Donald Stufft ","group":"","name":"packaging","version":"24.1","description":"Core utilities for Python packages","hashes":[{"alg":"SHA-256","content":"5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}},{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/packaging@24.1","type":"library","bom-ref":"pkg:pypi/packaging@24.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"\"Jeffrey A. Clark\" ","group":"","name":"pillow","version":"10.4.0","description":"Python Imaging Library (Fork)","hashes":[{"alg":"SHA-256","content":"4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}],"licenses":[{"expression":"CMU License (MIT-CMU)"}],"purl":"pkg:pypi/pillow@10.4.0","type":"library","bom-ref":"pkg:pypi/pillow@10.4.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}},"properties":[{"name":"cdx:pypi:latest_version","value":"11.0.0"},{"name":"cdx:pypi:resolved_from","value":"pillow"}]},{"author":"Daniele Varrazzo ","group":"","name":"psycopg-binary","version":"3.2.3","description":"PostgreSQL database adapter for Python -- C optimisation distribution","hashes":[{"alg":"SHA-256","content":"965455eac8547f32b3181d5ec9ad8b9be500c10fe06193543efaaebe3e4ce70c"}],"licenses":[{"license":{"id":"LGPL-3.0-only","url":"https://opensource.org/licenses/LGPL-3.0-only"}}],"purl":"pkg:pypi/psycopg-binary@3.2.3","externalReferences":[{"type":"website","url":"https://psycopg.org/psycopg3/"}],"type":"library","bom-ref":"pkg:pypi/psycopg-binary@3.2.3","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Daniele Varrazzo ","group":"","name":"psycopg","version":"3.2.3","description":"PostgreSQL database adapter for Python","hashes":[{"alg":"SHA-256","content":"644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}],"licenses":[{"license":{"id":"LGPL-3.0-only","url":"https://opensource.org/licenses/LGPL-3.0-only"}}],"purl":"pkg:pypi/psycopg@3.2.3","externalReferences":[{"type":"website","url":"https://psycopg.org/psycopg3/"}],"type":"library","bom-ref":"pkg:pypi/psycopg@3.2.3","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Prowler Team ","group":"","name":"py-ocsf-models","version":"0.1.1","description":"This is a Python implementation of the OCSF models. The models are used to represent the data of the OCSF Schema defined in https://schema.ocsf.io/.","hashes":[{"alg":"SHA-256","content":"c6ea465fda85470b938a48da65b1f19664f6d83820ebe849ef5551094e6768de"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/py-ocsf-models@0.1.1","type":"library","bom-ref":"pkg:pypi/py-ocsf-models@0.1.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}},"properties":[{"name":"cdx:pypi:latest_version","value":"0.2.0"},{"name":"cdx:pypi:resolved_from","value":"py-ocsf-models"}]},{"author":"Eli Bendersky ","group":"","name":"pycparser","version":"2.22","description":"C parser in Python","hashes":[{"alg":"SHA-256","content":"c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}},{"license":{"id":"BSD-3-Clause","url":"https://opensource.org/licenses/BSD-3-Clause"}}],"purl":"pkg:pypi/pycparser@2.22","externalReferences":[{"type":"vcs","url":"https://github.com/eliben/pycparser"}],"type":"library","bom-ref":"pkg:pypi/pycparser@2.22","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Samuel Colvin , Eric Jolibois , Hasan Ramezani , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Terrence Dorsey , David Montague , Serge Matveenko , Marcelo Trylesinski , Sydney Runkle , David Hewitt , Alex Hall ","group":"","name":"pydantic","version":"1.10.15","description":"Data validation using Python type hints","hashes":[{"alg":"SHA-256","content":"22ed12ee588b1df028a2aa5d66f07bf8f8b4c8579c2e96d5a9c1f96b77f3bb55"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/pydantic@1.10.15","type":"library","bom-ref":"pkg:pypi/pydantic@1.10.15","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}},"properties":[{"name":"cdx:pypi:latest_version","value":"2.9.2"},{"name":"cdx:pypi:resolved_from","value":"pydantic"}]},{"author":"Jose Padilla ","group":"","name":"PyJWT","version":"2.9.0","description":"JSON Web Token implementation in Python","hashes":[{"alg":"SHA-256","content":"3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/pyjwt@2.9.0","externalReferences":[{"type":"vcs","url":"https://github.com/jpadilla/pyjwt"}],"type":"library","bom-ref":"pkg:pypi/pyjwt@2.9.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Inada Naoki , Yutaka Matsubara ","group":"","name":"PyMySQL","version":"1.1.1","description":"Pure Python MySQL Driver","hashes":[{"alg":"SHA-256","content":"4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/pymysql@1.1.1","type":"library","bom-ref":"pkg:pypi/pymysql@1.1.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Thomas Kluyver ","group":"","name":"pyproject-hooks","version":"1.2.0","description":"Wrappers to call pyproject.toml-based build backend hooks.","hashes":[{"alg":"SHA-256","content":"9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/pyproject-hooks@1.2.0","type":"library","bom-ref":"pkg:pypi/pyproject-hooks@1.2.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"instrumentation","confidence":1,"value":"/tmp/cdxgen-venv-43yYKx"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]},{"author":"Kirill Simonov ","group":"","name":"PyYAML","version":"6.0.2","description":"YAML parser and emitter for Python","hashes":[{"alg":"SHA-256","content":"0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/pyyaml@6.0.2","externalReferences":[{"type":"website","url":"https://pyyaml.org/"}],"type":"library","bom-ref":"pkg:pypi/pyyaml@6.0.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Max Bachmann ","group":"","name":"RapidFuzz","version":"3.10.0","description":"rapid fuzzy string matching","hashes":[{"alg":"SHA-256","content":"884453860de029380dded8f3c1918af2d8eb5adf8010261645c7e5c88c2b5428"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/rapidfuzz@3.10.0","type":"library","bom-ref":"pkg:pypi/rapidfuzz@3.10.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"instrumentation","confidence":1,"value":"/tmp/cdxgen-venv-43yYKx"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]},{"author":"Julian Berman ","group":"","name":"referencing","version":"0.35.1","description":"JSON Referencing + Python","hashes":[{"alg":"SHA-256","content":"eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/referencing@0.35.1","type":"library","bom-ref":"pkg:pypi/referencing@0.35.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Kenneth Reitz ","group":"","name":"requests-oauthlib","version":"2.0.0","description":"OAuthlib authentication support for Requests.","hashes":[{"alg":"SHA-256","content":"7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}},{"license":{"id":"ISC","url":"https://opensource.org/licenses/ISC"}}],"purl":"pkg:pypi/requests-oauthlib@2.0.0","externalReferences":[{"type":"vcs","url":"https://github.com/requests/requests-oauthlib"}],"type":"library","bom-ref":"pkg:pypi/requests-oauthlib@2.0.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Ian Cordasco, Cory Benfield ","group":"","name":"requests-toolbelt","version":"1.0.0","description":"A utility belt for advanced users of python-requests","hashes":[{"alg":"SHA-256","content":"cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/requests-toolbelt@1.0.0","externalReferences":[{"type":"website","url":"https://toolbelt.readthedocs.io/"}],"type":"library","bom-ref":"pkg:pypi/requests-toolbelt@1.0.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Kenneth Reitz ","group":"","name":"requests","version":"2.32.3","description":"Python HTTP for Humans.","hashes":[{"alg":"SHA-256","content":"70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/requests@2.32.3","externalReferences":[{"type":"website","url":"https://requests.readthedocs.io"}],"type":"library","bom-ref":"pkg:pypi/requests@2.32.3","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Julian Berman ","group":"","name":"rpds-py","version":"0.20.0","description":"Python bindings to Rust's persistent data structures (rpds)","hashes":[{"alg":"SHA-256","content":"3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/rpds-py@0.20.0","type":"library","bom-ref":"pkg:pypi/rpds-py@0.20.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Andi Albrecht ","group":"","name":"sqlparse","version":"0.5.1","description":"A non-validating SQL parser.","hashes":[{"alg":"SHA-256","content":"773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}],"licenses":[{"license":{"id":"0BSD","url":"https://opensource.org/licenses/0BSD"}}],"purl":"pkg:pypi/sqlparse@0.5.1","type":"library","bom-ref":"pkg:pypi/sqlparse@0.5.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Alex Grönholm ","group":"","name":"typeguard","version":"4.3.0","description":"Run-time type checker for Python","hashes":[{"alg":"SHA-256","content":"4d24c5b39a117f8a895b9da7a9b3114f04eb63bade45a4492de49b175b6f7dfa"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/typeguard@4.3.0","type":"library","bom-ref":"pkg:pypi/typeguard@4.3.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"\"Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee\" ","group":"","name":"typing-extensions","version":"4.12.2","description":"Backported and Experimental Type Hints for Python 3.8+","hashes":[{"alg":"SHA-256","content":"04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}],"licenses":[{"license":{"id":"PSF-2.0","url":"https://opensource.org/licenses/PSF-2.0"}}],"purl":"pkg:pypi/typing-extensions@4.12.2","type":"library","bom-ref":"pkg:pypi/typing-extensions@4.12.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Python Software Foundation ","group":"","name":"tzdata","version":"2024.2","description":"Provider of IANA time zone data","hashes":[{"alg":"SHA-256","content":"a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}],"licenses":[{"license":{"id":"Apache-2.0","url":"https://opensource.org/licenses/Apache-2.0"}}],"purl":"pkg:pypi/tzdata@2024.2","externalReferences":[{"type":"vcs","url":"https://github.com/python/tzdata"}],"type":"library","bom-ref":"pkg:pypi/tzdata@2024.2","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Ian Stapleton Cordasco ","group":"","name":"uritemplate","version":"4.1.1","description":"Implementation of RFC 6570 URI Templates","hashes":[{"alg":"SHA-256","content":"830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}],"licenses":[{"expression":"OSI Approved OR BSD 3-Clause License or Apache License, Version 2.0"}],"purl":"pkg:pypi/uritemplate@4.1.1","externalReferences":[{"type":"website","url":"https://uritemplate.readthedocs.org"}],"type":"library","bom-ref":"pkg:pypi/uritemplate@4.1.1","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Andrey Petrov ","group":"","name":"urllib3","version":"2.2.3","description":"HTTP library with thread-safe connection pooling, file post, and more.","hashes":[{"alg":"SHA-256","content":"ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/urllib3@2.2.3","type":"library","bom-ref":"pkg:pypi/urllib3@2.2.3","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"Konsta Vesterinen ","group":"","name":"validators","version":"0.34.0","description":"Python Data Validation for Humans™","hashes":[{"alg":"SHA-256","content":"c804b476e3e6d3786fa07a30073a4ef694e617805eb1946ceee3fe5a9b8b1321"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/validators@0.34.0","type":"library","bom-ref":"pkg:pypi/validators@0.34.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"David Evans","group":"","name":"whitenoise","version":"6.7.0","description":"Radically simplified static file serving for WSGI applications","hashes":[{"alg":"SHA-256","content":"a1ae85e01fdc9815d12fa33f17765bc132ed2c54fa76daf9e39e879dd93566f6"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/whitenoise@6.7.0","type":"library","bom-ref":"pkg:pypi/whitenoise@6.7.0","evidence":{"identity":{"field":"purl","confidence":1,"methods":[{"technique":"manifest-analysis","confidence":1,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry.lock"}]}}},{"author":"\"Jason R. Coombs\" ","group":"","name":"zipp","version":"3.20.2","description":"Backport of pathlib-compatible object wrapper for zip files","hashes":[{"alg":"SHA-256","content":"a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}],"licenses":[{"license":{"id":"MIT","url":"https://opensource.org/licenses/MIT"}}],"purl":"pkg:pypi/zipp@3.20.2","type":"library","bom-ref":"pkg:pypi/zipp@3.20.2","evidence":{"identity":{"field":"purl","confidence":0.8,"methods":[{"technique":"manifest-analysis","confidence":0.8,"value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]}},"properties":[{"name":"SrcFile","value":"/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt"}]}],"dependencies":[{"ref":"pkg:pypi/secobserve@1.22.4","dependsOn":["pkg:pypi/argon2-cffi@23.1.0","pkg:pypi/cvss@3.2","pkg:pypi/defusedcsv@2.0.0","pkg:pypi/django-cors-headers@4.5.0","pkg:pypi/django-csp@3.8","pkg:pypi/django-encrypted-model-fields@0.6.5","pkg:pypi/django-environ@0.11.2","pkg:pypi/django-filter@24.3","pkg:pypi/django-picklefield@3.2","pkg:pypi/django@5.1.2","pkg:pypi/djangorestframework@3.15.2","pkg:pypi/drf-spectacular-sidecar@2024.7.1","pkg:pypi/drf-spectacular@0.27.2","pkg:pypi/gunicorn@23.0.0","pkg:pypi/huey@2.5.2","pkg:pypi/inflect@7.4.0","pkg:pypi/jira@3.8.0","pkg:pypi/jsonpickle@3.3.0","pkg:pypi/openpyxl@3.1.5","pkg:pypi/packageurl-python@0.16.0","pkg:pypi/psycopg@3.2.3","pkg:pypi/py-ocsf-models@0.1.1","pkg:pypi/pymysql@1.1.1","pkg:pypi/requests@2.32.3","pkg:pypi/validators@0.34.0","pkg:pypi/whitenoise@6.7.0"]},{"ref":"pkg:pypi/argon2-cffi@23.1.0","dependsOn":["pkg:pypi/argon2-cffi-bindings@21.2.0"]},{"ref":"pkg:pypi/argon2-cffi-bindings@21.2.0","dependsOn":["pkg:pypi/cffi@1.17.1"]},{"ref":"pkg:pypi/asgiref@3.8.1","dependsOn":["pkg:pypi/typing-extensions@4.12.2"]},{"ref":"pkg:pypi/attrs@24.2.0","dependsOn":[]},{"ref":"pkg:pypi/certifi@2024.8.30","dependsOn":[]},{"ref":"pkg:pypi/cffi@1.17.1","dependsOn":["pkg:pypi/pycparser@2.22"]},{"ref":"pkg:pypi/charset-normalizer@3.4.0","dependsOn":[]},{"ref":"pkg:pypi/cryptography@43.0.1","dependsOn":["pkg:pypi/cffi@1.17.1"]},{"ref":"pkg:pypi/cvss@3.2","dependsOn":[]},{"ref":"pkg:pypi/defusedcsv@2.0.0","dependsOn":[]},{"ref":"pkg:pypi/defusedxml@0.7.1","dependsOn":[]},{"ref":"pkg:pypi/django@5.1.2","dependsOn":["pkg:pypi/asgiref@3.8.1","pkg:pypi/sqlparse@0.5.1","pkg:pypi/tzdata@2024.2"]},{"ref":"pkg:pypi/django-cors-headers@4.5.0","dependsOn":["pkg:pypi/asgiref@3.8.1","pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/django-csp@3.8","dependsOn":["pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/django-encrypted-model-fields@0.6.5","dependsOn":["pkg:pypi/cryptography@43.0.1","pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/django-environ@0.11.2","dependsOn":[]},{"ref":"pkg:pypi/django-filter@24.3","dependsOn":["pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/django-picklefield@3.2","dependsOn":["pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/djangorestframework@3.15.2","dependsOn":["pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/dnspython@2.7.0","dependsOn":[]},{"ref":"pkg:pypi/drf-spectacular@0.27.2","dependsOn":["pkg:pypi/django@5.1.2","pkg:pypi/djangorestframework@3.15.2","pkg:pypi/inflection@0.5.1","pkg:pypi/jsonschema@4.23.0","pkg:pypi/pyyaml@6.0.2","pkg:pypi/uritemplate@4.1.1"]},{"ref":"pkg:pypi/drf-spectacular-sidecar@2024.7.1","dependsOn":["pkg:pypi/django@5.1.2"]},{"ref":"pkg:pypi/email-validator@2.1.1","dependsOn":["pkg:pypi/dnspython@2.7.0","pkg:pypi/idna@3.10"]},{"ref":"pkg:pypi/et-xmlfile@1.1.0","dependsOn":[]},{"ref":"pkg:pypi/gunicorn@23.0.0","dependsOn":["pkg:pypi/packaging@24.1"]},{"ref":"pkg:pypi/huey@2.5.2","dependsOn":[]},{"ref":"pkg:pypi/idna@3.10","dependsOn":[]},{"ref":"pkg:pypi/inflect@7.4.0","dependsOn":["pkg:pypi/more-itertools@10.5.0","pkg:pypi/typeguard@4.3.0"]},{"ref":"pkg:pypi/inflection@0.5.1","dependsOn":[]},{"ref":"pkg:pypi/jira@3.8.0","dependsOn":["pkg:pypi/defusedxml@0.7.1","pkg:pypi/packaging@24.1","pkg:pypi/pillow@10.4.0","pkg:pypi/requests-oauthlib@2.0.0","pkg:pypi/requests-toolbelt@1.0.0","pkg:pypi/requests@2.32.3","pkg:pypi/typing-extensions@4.12.2"]},{"ref":"pkg:pypi/jsonpickle@3.3.0","dependsOn":[]},{"ref":"pkg:pypi/jsonschema@4.23.0","dependsOn":["pkg:pypi/attrs@24.2.0","pkg:pypi/jsonschema-specifications@2024.10.1","pkg:pypi/referencing@0.35.1","pkg:pypi/rpds-py@0.20.0"]},{"ref":"pkg:pypi/jsonschema-specifications@2024.10.1","dependsOn":["pkg:pypi/referencing@0.35.1"]},{"ref":"pkg:pypi/more-itertools@10.5.0","dependsOn":[]},{"ref":"pkg:pypi/oauthlib@3.2.2","dependsOn":[]},{"ref":"pkg:pypi/openpyxl@3.1.5","dependsOn":["pkg:pypi/et-xmlfile@1.1.0"]},{"ref":"pkg:pypi/packageurl-python@0.16.0","dependsOn":[]},{"ref":"pkg:pypi/packaging@24.1","dependsOn":[]},{"ref":"pkg:pypi/pillow@10.4.0","dependsOn":[]},{"ref":"pkg:pypi/psycopg@3.2.3","dependsOn":["pkg:pypi/psycopg-binary@3.2.3","pkg:pypi/typing-extensions@4.12.2","pkg:pypi/tzdata@2024.2"]},{"ref":"pkg:pypi/psycopg-binary@3.2.3","dependsOn":[]},{"ref":"pkg:pypi/py-ocsf-models@0.1.1","dependsOn":["pkg:pypi/email-validator@2.1.1","pkg:pypi/pydantic@1.10.15"]},{"ref":"pkg:pypi/pycparser@2.22","dependsOn":[]},{"ref":"pkg:pypi/pydantic@1.10.15","dependsOn":["pkg:pypi/typing-extensions@4.12.2"]},{"ref":"pkg:pypi/pyjwt@2.9.0","dependsOn":[]},{"ref":"pkg:pypi/pymysql@1.1.1","dependsOn":[]},{"ref":"pkg:pypi/pyyaml@6.0.2","dependsOn":[]},{"ref":"pkg:pypi/referencing@0.35.1","dependsOn":["pkg:pypi/attrs@24.2.0","pkg:pypi/rpds-py@0.20.0"]},{"ref":"pkg:pypi/requests@2.32.3","dependsOn":["pkg:pypi/certifi@2024.8.30","pkg:pypi/charset-normalizer@3.4.0","pkg:pypi/idna@3.10","pkg:pypi/urllib3@2.2.3"]},{"ref":"pkg:pypi/requests-oauthlib@2.0.0","dependsOn":["pkg:pypi/oauthlib@3.2.2","pkg:pypi/requests@2.32.3"]},{"ref":"pkg:pypi/requests-toolbelt@1.0.0","dependsOn":["pkg:pypi/requests@2.32.3"]},{"ref":"pkg:pypi/rpds-py@0.20.0","dependsOn":[]},{"ref":"pkg:pypi/sqlparse@0.5.1","dependsOn":[]},{"ref":"pkg:pypi/typeguard@4.3.0","dependsOn":["pkg:pypi/typing-extensions@4.12.2"]},{"ref":"pkg:pypi/typing-extensions@4.12.2","dependsOn":[]},{"ref":"pkg:pypi/tzdata@2024.2","dependsOn":[]},{"ref":"pkg:pypi/uritemplate@4.1.1","dependsOn":[]},{"ref":"pkg:pypi/urllib3@2.2.3","dependsOn":[]},{"ref":"pkg:pypi/validators@0.34.0","dependsOn":[]},{"ref":"pkg:pypi/whitenoise@6.7.0","dependsOn":[]},{"ref":"pkg:pypi/rapidfuzz@3.10.0","dependsOn":[]},{"ref":"pkg:pypi/pyproject-hooks@1.2.0","dependsOn":[]},{"ref":"pkg:pypi/zipp@3.20.2","dependsOn":[]},{"ref":"pkg:pypi/importlib-metadata@8.5.0","dependsOn":["pkg:pypi/zipp@3.20.2"]},{"ref":"pkg:pypi/msgpack@1.1.0","dependsOn":[]},{"ref":"pkg:pypi/cachecontrol@0.14.0","dependsOn":["pkg:pypi/msgpack@1.1.0","pkg:pypi/requests@2.32.3"]}]} \ No newline at end of file +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:12f6dd75-f31f-48a8-8b59-c7c9f87d68c9", + "version": 1, + "metadata": { + "timestamp": "2024-10-22T12:15:48Z", + "tools": { + "components": [ + { + "group": "@cyclonedx", + "name": "cdxgen", + "version": "10.10.6", + "purl": "pkg:npm/%40cyclonedx/cdxgen@10.10.6", + "type": "application", + "bom-ref": "pkg:npm/@cyclonedx/cdxgen@10.10.6", + "author": "OWASP Foundation", + "publisher": "OWASP Foundation" + } + ] + }, + "authors": [ + { + "name": "OWASP Foundation" + } + ], + "lifecycles": [ + { + "phase": "build" + } + ], + "component": { + "name": "SecObserve", + "version": "1.22.4", + "description": "SecObserve is an open source vulnerability management system for software development and cloud environments.", + "type": "application", + "bom-ref": "pkg:pypi/secobserve@1.22.4", + "purl": "pkg:pypi/secobserve@1.22.4" + }, + "properties": [ + { + "name": "cdx:bom:componentTypes", + "value": "pypi" + } + ] + }, + "components": [ + { + "author": "Hynek Schlawack ", + "group": "", + "name": "argon2-cffi-bindings", + "version": "21.2.0", + "description": "Low-level CFFI bindings for Argon2", + "hashes": [ + { + "alg": "SHA-256", + "content": "ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/argon2-cffi-bindings@21.2.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/hynek/argon2-cffi-bindings" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/argon2-cffi-bindings@21.2.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Hynek Schlawack ", + "group": "", + "name": "argon2-cffi", + "version": "23.1.0", + "description": "Argon2 for Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/argon2-cffi@23.1.0", + "type": "library", + "bom-ref": "pkg:pypi/argon2-cffi@23.1.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Django Software Foundation ", + "group": "", + "name": "asgiref", + "version": "3.8.1", + "description": "ASGI specs, helper code, and adapters", + "hashes": [ + { + "alg": "SHA-256", + "content": "3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + }, + { + "license": { + "id": "BSD-3-Clause", + "url": "https://opensource.org/licenses/BSD-3-Clause" + } + } + ], + "purl": "pkg:pypi/asgiref@3.8.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/django/asgiref/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/asgiref@3.8.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Hynek Schlawack ", + "group": "", + "name": "attrs", + "version": "24.2.0", + "description": "Classes Without Boilerplate", + "hashes": [ + { + "alg": "SHA-256", + "content": "81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/attrs@24.2.0", + "type": "library", + "bom-ref": "pkg:pypi/attrs@24.2.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Eric Larson , Frost Ming , William Woodruff ", + "group": "", + "name": "CacheControl", + "version": "0.14.0", + "description": "httplib2 caching for requests", + "hashes": [ + { + "alg": "SHA-256", + "content": "f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/cachecontrol@0.14.0", + "type": "library", + "bom-ref": "pkg:pypi/cachecontrol@0.14.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "instrumentation", + "confidence": 1, + "value": "/tmp/cdxgen-venv-43yYKx" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + }, + { + "author": "Kenneth Reitz ", + "group": "", + "name": "certifi", + "version": "2024.8.30", + "description": "Python package for providing Mozilla's CA Bundle.", + "hashes": [ + { + "alg": "SHA-256", + "content": "922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8" + } + ], + "licenses": [ + { + "license": { + "id": "MPL-2.0", + "url": "https://opensource.org/licenses/MPL-2.0" + } + } + ], + "purl": "pkg:pypi/certifi@2024.8.30", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/certifi/python-certifi" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/certifi@2024.8.30", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Armin Rigo, Maciej Fijalkowski ", + "group": "", + "name": "cffi", + "version": "1.17.1", + "description": "Foreign Function Interface for Python calling C code.", + "hashes": [ + { + "alg": "SHA-256", + "content": "df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/cffi@1.17.1", + "externalReferences": [ + { + "type": "website", + "url": "http://cffi.readthedocs.org" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/cffi@1.17.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Ahmed TAHRI ", + "group": "", + "name": "charset-normalizer", + "version": "3.4.0", + "description": "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.", + "hashes": [ + { + "alg": "SHA-256", + "content": "4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/charset-normalizer@3.4.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/Ousret/charset_normalizer" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/charset-normalizer@3.4.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "The cryptography developers >", + "group": "", + "name": "cryptography", + "version": "43.0.1", + "description": "cryptography is a package which provides cryptographic recipes and primitives to Python developers.", + "hashes": [ + { + "alg": "SHA-256", + "content": "8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d" + } + ], + "licenses": [ + { + "expression": "LGPL-3.0-or-later OR BSD-3-Clause" + } + ], + "purl": "pkg:pypi/cryptography@43.0.1", + "type": "library", + "bom-ref": "pkg:pypi/cryptography@43.0.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + }, + "properties": [ + { + "name": "cdx:pypi:latest_version", + "value": "43.0.3" + }, + { + "name": "cdx:pypi:resolved_from", + "value": "cryptography" + } + ] + }, + { + "author": "Stanislav Kontar, Red Hat Product Security ", + "group": "", + "name": "cvss", + "version": "3.2", + "description": "CVSS2/3/4 library with interactive calculator for Python 2 and Python 3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e2c2fbc8943c6df83d23c7ad74bb9c5e584c666a9455b013b598e292e5018469" + } + ], + "licenses": [ + { + "expression": "GPL-3.0-or-later AND BSD-3-Clause" + } + ], + "purl": "pkg:pypi/cvss@3.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/RedHatProductSecurity/cvss" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/cvss@3.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Raphael Michel ", + "group": "", + "name": "defusedcsv", + "version": "2.0.0", + "description": "Drop-in replacement for Python's CSV library that tries to mitigate CSV injection attacks", + "hashes": [ + { + "alg": "SHA-256", + "content": "a7bc3b1ac1ce4f8c6c1e8740466b1b5789b51ca18d918b0099313dc0cdf2cef4" + } + ], + "licenses": [ + { + "expression": "(Apache-2.0 OR BSD-3-Clause) AND MIT" + } + ], + "purl": "pkg:pypi/defusedcsv@2.0.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/raphaelm/defusedcsv" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/defusedcsv@2.0.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Christian Heimes ", + "group": "", + "name": "defusedxml", + "version": "0.7.1", + "description": "XML bomb protection for Python stdlib modules", + "hashes": [ + { + "alg": "SHA-256", + "content": "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" + } + ], + "licenses": [ + { + "license": { + "id": "PSF-2.0", + "url": "https://opensource.org/licenses/PSF-2.0" + } + } + ], + "purl": "pkg:pypi/defusedxml@0.7.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/tiran/defusedxml" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/defusedxml@0.7.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Otto Yiu ", + "group": "", + "name": "django-cors-headers", + "version": "4.5.0", + "description": "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS).", + "hashes": [ + { + "alg": "SHA-256", + "content": "28c1ded847aa70208798de3e42422a782f427b8b720e8d7319d34b654b5978e6" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/django-cors-headers@4.5.0", + "type": "framework", + "bom-ref": "pkg:pypi/django-cors-headers@4.5.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "James Socol ", + "group": "", + "name": "django-csp", + "version": "3.8", + "description": "Django Content Security Policy support.", + "hashes": [ + { + "alg": "SHA-256", + "content": "19b2978b03fcd73517d7d67acbc04fbbcaec0facc3e83baa502965892d1e0719" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/django-csp@3.8", + "type": "framework", + "bom-ref": "pkg:pypi/django-csp@3.8", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Scott Sharkey ", + "group": "", + "name": "django-encrypted-model-fields", + "version": "0.6.5", + "description": "A set of fields that wrap standard Django fields with encryption provided by the python cryptography library.", + "hashes": [ + { + "alg": "SHA-256", + "content": "b21bbdd8ae2e1a0ea37a5049b3ba46e6e63bf287ad241219a058fac1070796cc" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/django-encrypted-model-fields@0.6.5", + "externalReferences": [ + { + "type": "vcs", + "url": "https://gitlab.com/lansharkconsulting/django/django-encrypted-model-fields" + } + ], + "type": "framework", + "bom-ref": "pkg:pypi/django-encrypted-model-fields@0.6.5", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Daniele Faraglia ", + "group": "", + "name": "django-environ", + "version": "0.11.2", + "description": "A package that allows you to utilize 12factor inspired environment variables to configure your Django application.", + "hashes": [ + { + "alg": "SHA-256", + "content": "0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/django-environ@0.11.2", + "externalReferences": [ + { + "type": "website", + "url": "https://django-environ.readthedocs.org" + } + ], + "type": "framework", + "bom-ref": "pkg:pypi/django-environ@0.11.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Alex Gaynor ", + "group": "", + "name": "django-filter", + "version": "24.3", + "description": "Django-filter is a reusable Django application for allowing users to filter querysets dynamically.", + "hashes": [ + { + "alg": "SHA-256", + "content": "c4852822928ce17fb699bcfccd644b3574f1a2d80aeb2b4ff4f16b02dd49dc64" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/django-filter@24.3", + "type": "framework", + "bom-ref": "pkg:pypi/django-filter@24.3", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Simon Charette ", + "group": "", + "name": "django-picklefield", + "version": "3.2", + "description": "Pickled object field for Django", + "hashes": [ + { + "alg": "SHA-256", + "content": "e9a73539d110f69825d9320db18bcb82e5189ff48dbed41821c026a20497764c" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/django-picklefield@3.2", + "externalReferences": [ + { + "type": "vcs", + "url": "http://github.com/gintas/django-picklefield" + } + ], + "type": "framework", + "bom-ref": "pkg:pypi/django-picklefield@3.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Django Software Foundation ", + "group": "", + "name": "Django", + "version": "5.1.2", + "description": "A high-level Python web framework that encourages rapid development and clean, pragmatic design.", + "hashes": [ + { + "alg": "SHA-256", + "content": "f11aa87ad8d5617171e3f77e1d5d16f004b79a2cf5d2e1d2b97a6a1f8e9ba5ed" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + }, + { + "license": { + "id": "BSD-3-Clause", + "url": "https://opensource.org/licenses/BSD-3-Clause" + } + } + ], + "purl": "pkg:pypi/django@5.1.2", + "type": "framework", + "bom-ref": "pkg:pypi/django@5.1.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Tom Christie ", + "group": "", + "name": "djangorestframework", + "version": "3.15.2", + "description": "Web APIs for Django, made easy.", + "hashes": [ + { + "alg": "SHA-256", + "content": "2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/djangorestframework@3.15.2", + "externalReferences": [ + { + "type": "website", + "url": "https://www.django-rest-framework.org/" + } + ], + "type": "framework", + "bom-ref": "pkg:pypi/djangorestframework@3.15.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Bob Halley ", + "group": "", + "name": "dnspython", + "version": "2.7.0", + "description": "DNS toolkit", + "hashes": [ + { + "alg": "SHA-256", + "content": "b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86" + } + ], + "licenses": [ + { + "license": { + "id": "ISC", + "url": "https://opensource.org/licenses/ISC" + } + } + ], + "purl": "pkg:pypi/dnspython@2.7.0", + "type": "library", + "bom-ref": "pkg:pypi/dnspython@2.7.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "T. Franzel ", + "group": "", + "name": "drf-spectacular-sidecar", + "version": "2024.7.1", + "description": "Serve self-contained distribution builds of Swagger UI and Redoc with Django", + "hashes": [ + { + "alg": "SHA-256", + "content": "5dc8b38ad153e90b328152674c7959bf114bf86360a617a5a4516e135cb832bc" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/drf-spectacular-sidecar@2024.7.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/tfranzel/drf-spectacular-sidecar" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/drf-spectacular-sidecar@2024.7.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "T. Franzel ", + "group": "", + "name": "drf-spectacular", + "version": "0.27.2", + "description": "Sane and flexible OpenAPI 3 schema generation for Django REST framework", + "hashes": [ + { + "alg": "SHA-256", + "content": "b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/drf-spectacular@0.27.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/tfranzel/drf-spectacular" + } + ], + "type": "framework", + "bom-ref": "pkg:pypi/drf-spectacular@0.27.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Joshua Tauberer ", + "group": "", + "name": "email-validator", + "version": "2.1.1", + "description": "A robust email address syntax and deliverability validation library.", + "hashes": [ + { + "alg": "SHA-256", + "content": "97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05" + } + ], + "licenses": [ + { + "expression": "The Unlicense (Unlicense)" + } + ], + "purl": "pkg:pypi/email-validator@2.1.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/JoshData/python-email-validator" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/email-validator@2.1.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + }, + "properties": [ + { + "name": "cdx:pypi:latest_version", + "value": "2.2.0" + }, + { + "name": "cdx:pypi:resolved_from", + "value": "email-validator" + } + ] + }, + { + "author": "See ATUHORS.txt ", + "group": "", + "name": "et-xmlfile", + "version": "1.1.0", + "description": "An implementation of lxml.xmlfile for the standard library", + "hashes": [ + { + "alg": "SHA-256", + "content": "a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/et-xmlfile@1.1.0", + "externalReferences": [ + { + "type": "website", + "url": "https://foss.heptapod.net/openpyxl/et_xmlfile" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/et-xmlfile@1.1.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Benoit Chesneau ", + "group": "", + "name": "gunicorn", + "version": "23.0.0", + "description": "WSGI HTTP Server for UNIX", + "hashes": [ + { + "alg": "SHA-256", + "content": "ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/gunicorn@23.0.0", + "type": "library", + "bom-ref": "pkg:pypi/gunicorn@23.0.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Charles Leifer ", + "group": "", + "name": "huey", + "version": "2.5.2", + "description": "huey, a little task queue", + "hashes": [ + { + "alg": "SHA-256", + "content": "df33db474c05414ed40ee2110e9df692369871734da22d74ffb035a4bd74047f" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/huey@2.5.2", + "externalReferences": [ + { + "type": "vcs", + "url": "http://github.com/coleifer/huey/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/huey@2.5.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Kim Davies ", + "group": "", + "name": "idna", + "version": "3.10", + "description": "Internationalized Domain Names in Applications (IDNA)", + "hashes": [ + { + "alg": "SHA-256", + "content": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/idna@3.10", + "type": "library", + "bom-ref": "pkg:pypi/idna@3.10", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "\"Jason R. Coombs\" ", + "group": "", + "name": "importlib-metadata", + "version": "8.5.0", + "description": "Read metadata from Python packages", + "hashes": [ + { + "alg": "SHA-256", + "content": "45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/importlib-metadata@8.5.0", + "type": "library", + "bom-ref": "pkg:pypi/importlib-metadata@8.5.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "instrumentation", + "confidence": 1, + "value": "/tmp/cdxgen-venv-43yYKx" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + }, + { + "author": "Paul Dyson ", + "group": "", + "name": "inflect", + "version": "7.4.0", + "description": "Correctly generate plurals, singular nouns, ordinals, indefinite articles", + "hashes": [ + { + "alg": "SHA-256", + "content": "85af0997ee2bda942b1c1eed8c8a827abda91aa3e22d1efaa0eea817f9350ce7" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/inflect@7.4.0", + "type": "library", + "bom-ref": "pkg:pypi/inflect@7.4.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Janne Vanhala ", + "group": "", + "name": "inflection", + "version": "0.5.1", + "description": "A port of Ruby on Rails inflector to Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/inflection@0.5.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/jpvanhal/inflection" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/inflection@0.5.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Ben Speakmon ", + "group": "", + "name": "jira", + "version": "3.8.0", + "description": "Python library for interacting with JIRA via REST APIs.", + "hashes": [ + { + "alg": "SHA-256", + "content": "12190dc84dad00b8a6c0341f7e8a254b0f38785afdec022bd5941e1184a5a3fb" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + }, + { + "license": { + "id": "BSD-2-Clause", + "url": "https://opensource.org/licenses/BSD-2-Clause" + } + } + ], + "purl": "pkg:pypi/jira@3.8.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/pycontribs/jira" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/jira@3.8.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "David Aguilar ", + "group": "", + "name": "jsonpickle", + "version": "3.3.0", + "description": "Python library for serializing arbitrary object graphs into JSON", + "hashes": [ + { + "alg": "SHA-256", + "content": "287c12143f35571ab00e224fa323aa4b090d5a7f086f5f494d7ee9c7eb1a380a" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/jsonpickle@3.3.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/jsonpickle/jsonpickle" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/jsonpickle@3.3.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Julian Berman ", + "group": "", + "name": "jsonschema-specifications", + "version": "2024.10.1", + "description": "The JSON Schema meta-schemas and vocabularies, exposed as a Registry", + "hashes": [ + { + "alg": "SHA-256", + "content": "a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/jsonschema-specifications@2024.10.1", + "type": "library", + "bom-ref": "pkg:pypi/jsonschema-specifications@2024.10.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Julian Berman ", + "group": "", + "name": "jsonschema", + "version": "4.23.0", + "description": "An implementation of JSON Schema validation for Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/jsonschema@4.23.0", + "type": "library", + "bom-ref": "pkg:pypi/jsonschema@4.23.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Erik Rose ", + "group": "", + "name": "more-itertools", + "version": "10.5.0", + "description": "More routines for operating on iterables, beyond itertools", + "hashes": [ + { + "alg": "SHA-256", + "content": "037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/more-itertools@10.5.0", + "type": "library", + "bom-ref": "pkg:pypi/more-itertools@10.5.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Inada Naoki ", + "group": "", + "name": "msgpack", + "version": "1.1.0", + "description": "MessagePack serializer", + "hashes": [ + { + "alg": "SHA-256", + "content": "7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/msgpack@1.1.0", + "type": "library", + "bom-ref": "pkg:pypi/msgpack@1.1.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 0.8, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 0.8, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + }, + { + "author": "The OAuthlib Community ", + "group": "", + "name": "oauthlib", + "version": "3.2.2", + "description": "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic", + "hashes": [ + { + "alg": "SHA-256", + "content": "8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca" + } + ], + "licenses": [ + { + "expression": "OSI Approved" + } + ], + "purl": "pkg:pypi/oauthlib@3.2.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/oauthlib/oauthlib" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/oauthlib@3.2.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "See AUTHORS ", + "group": "", + "name": "openpyxl", + "version": "3.1.5", + "description": "A Python library to read/write Excel 2010 xlsx/xlsm files", + "hashes": [ + { + "alg": "SHA-256", + "content": "5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/openpyxl@3.1.5", + "externalReferences": [ + { + "type": "website", + "url": "https://openpyxl.readthedocs.io" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/openpyxl@3.1.5", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "the purl authors", + "group": "", + "name": "packageurl-python", + "version": "0.16.0", + "description": "A purl aka. Package URL parser and builder", + "hashes": [ + { + "alg": "SHA-256", + "content": "5c3872638b177b0f1cf01c3673017b7b27ebee485693ae12a8bed70fa7fa7c35" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/packageurl-python@0.16.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/package-url/packageurl-python" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/packageurl-python@0.16.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Donald Stufft ", + "group": "", + "name": "packaging", + "version": "24.1", + "description": "Core utilities for Python packages", + "hashes": [ + { + "alg": "SHA-256", + "content": "5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + }, + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/packaging@24.1", + "type": "library", + "bom-ref": "pkg:pypi/packaging@24.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "\"Jeffrey A. Clark\" ", + "group": "", + "name": "pillow", + "version": "10.4.0", + "description": "Python Imaging Library (Fork)", + "hashes": [ + { + "alg": "SHA-256", + "content": "4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e" + } + ], + "licenses": [ + { + "expression": "CMU License (MIT-CMU)" + } + ], + "purl": "pkg:pypi/pillow@10.4.0", + "type": "library", + "bom-ref": "pkg:pypi/pillow@10.4.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + }, + "properties": [ + { + "name": "cdx:pypi:latest_version", + "value": "11.0.0" + }, + { + "name": "cdx:pypi:resolved_from", + "value": "pillow" + } + ] + }, + { + "author": "Daniele Varrazzo ", + "group": "", + "name": "psycopg-binary", + "version": "3.2.3", + "description": "PostgreSQL database adapter for Python -- C optimisation distribution", + "hashes": [ + { + "alg": "SHA-256", + "content": "965455eac8547f32b3181d5ec9ad8b9be500c10fe06193543efaaebe3e4ce70c" + } + ], + "licenses": [ + { + "license": { + "id": "LGPL-3.0-only", + "url": "https://opensource.org/licenses/LGPL-3.0-only" + } + } + ], + "purl": "pkg:pypi/psycopg-binary@3.2.3", + "externalReferences": [ + { + "type": "website", + "url": "https://psycopg.org/psycopg3/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/psycopg-binary@3.2.3", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Daniele Varrazzo ", + "group": "", + "name": "psycopg", + "version": "3.2.3", + "description": "PostgreSQL database adapter for Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907" + } + ], + "licenses": [ + { + "license": { + "id": "LGPL-3.0-only", + "url": "https://opensource.org/licenses/LGPL-3.0-only" + } + } + ], + "purl": "pkg:pypi/psycopg@3.2.3", + "externalReferences": [ + { + "type": "website", + "url": "https://psycopg.org/psycopg3/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/psycopg@3.2.3", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Prowler Team ", + "group": "", + "name": "py-ocsf-models", + "version": "0.1.1", + "description": "This is a Python implementation of the OCSF models. The models are used to represent the data of the OCSF Schema defined in https://schema.ocsf.io/.", + "hashes": [ + { + "alg": "SHA-256", + "content": "c6ea465fda85470b938a48da65b1f19664f6d83820ebe849ef5551094e6768de" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/py-ocsf-models@0.1.1", + "type": "library", + "bom-ref": "pkg:pypi/py-ocsf-models@0.1.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + }, + "properties": [ + { + "name": "cdx:pypi:latest_version", + "value": "0.2.0" + }, + { + "name": "cdx:pypi:resolved_from", + "value": "py-ocsf-models" + } + ] + }, + { + "author": "Eli Bendersky ", + "group": "", + "name": "pycparser", + "version": "2.22", + "description": "C parser in Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + }, + { + "license": { + "id": "BSD-3-Clause", + "url": "https://opensource.org/licenses/BSD-3-Clause" + } + } + ], + "purl": "pkg:pypi/pycparser@2.22", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/eliben/pycparser" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/pycparser@2.22", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Samuel Colvin , Eric Jolibois , Hasan Ramezani , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Terrence Dorsey , David Montague , Serge Matveenko , Marcelo Trylesinski , Sydney Runkle , David Hewitt , Alex Hall ", + "group": "", + "name": "pydantic", + "version": "1.10.15", + "description": "Data validation using Python type hints", + "hashes": [ + { + "alg": "SHA-256", + "content": "22ed12ee588b1df028a2aa5d66f07bf8f8b4c8579c2e96d5a9c1f96b77f3bb55" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/pydantic@1.10.15", + "type": "library", + "bom-ref": "pkg:pypi/pydantic@1.10.15", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + }, + "properties": [ + { + "name": "cdx:pypi:latest_version", + "value": "2.9.2" + }, + { + "name": "cdx:pypi:resolved_from", + "value": "pydantic" + } + ] + }, + { + "author": "Jose Padilla ", + "group": "", + "name": "PyJWT", + "version": "2.9.0", + "description": "JSON Web Token implementation in Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/pyjwt@2.9.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/jpadilla/pyjwt" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/pyjwt@2.9.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Inada Naoki , Yutaka Matsubara ", + "group": "", + "name": "PyMySQL", + "version": "1.1.1", + "description": "Pure Python MySQL Driver", + "hashes": [ + { + "alg": "SHA-256", + "content": "4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/pymysql@1.1.1", + "type": "library", + "bom-ref": "pkg:pypi/pymysql@1.1.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Thomas Kluyver ", + "group": "", + "name": "pyproject-hooks", + "version": "1.2.0", + "description": "Wrappers to call pyproject.toml-based build backend hooks.", + "hashes": [ + { + "alg": "SHA-256", + "content": "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/pyproject-hooks@1.2.0", + "type": "library", + "bom-ref": "pkg:pypi/pyproject-hooks@1.2.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "instrumentation", + "confidence": 1, + "value": "/tmp/cdxgen-venv-43yYKx" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + }, + { + "author": "Kirill Simonov ", + "group": "", + "name": "PyYAML", + "version": "6.0.2", + "description": "YAML parser and emitter for Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/pyyaml@6.0.2", + "externalReferences": [ + { + "type": "website", + "url": "https://pyyaml.org/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/pyyaml@6.0.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Max Bachmann ", + "group": "", + "name": "RapidFuzz", + "version": "3.10.0", + "description": "rapid fuzzy string matching", + "hashes": [ + { + "alg": "SHA-256", + "content": "884453860de029380dded8f3c1918af2d8eb5adf8010261645c7e5c88c2b5428" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/rapidfuzz@3.10.0", + "type": "library", + "bom-ref": "pkg:pypi/rapidfuzz@3.10.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "instrumentation", + "confidence": 1, + "value": "/tmp/cdxgen-venv-43yYKx" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + }, + { + "author": "Julian Berman ", + "group": "", + "name": "referencing", + "version": "0.35.1", + "description": "JSON Referencing + Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/referencing@0.35.1", + "type": "library", + "bom-ref": "pkg:pypi/referencing@0.35.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Kenneth Reitz ", + "group": "", + "name": "requests-oauthlib", + "version": "2.0.0", + "description": "OAuthlib authentication support for Requests.", + "hashes": [ + { + "alg": "SHA-256", + "content": "7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + }, + { + "license": { + "id": "ISC", + "url": "https://opensource.org/licenses/ISC" + } + } + ], + "purl": "pkg:pypi/requests-oauthlib@2.0.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/requests/requests-oauthlib" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/requests-oauthlib@2.0.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Ian Cordasco, Cory Benfield ", + "group": "", + "name": "requests-toolbelt", + "version": "1.0.0", + "description": "A utility belt for advanced users of python-requests", + "hashes": [ + { + "alg": "SHA-256", + "content": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/requests-toolbelt@1.0.0", + "externalReferences": [ + { + "type": "website", + "url": "https://toolbelt.readthedocs.io/" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/requests-toolbelt@1.0.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Kenneth Reitz ", + "group": "", + "name": "requests", + "version": "2.32.3", + "description": "Python HTTP for Humans.", + "hashes": [ + { + "alg": "SHA-256", + "content": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/requests@2.32.3", + "externalReferences": [ + { + "type": "website", + "url": "https://requests.readthedocs.io" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/requests@2.32.3", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Julian Berman ", + "group": "", + "name": "rpds-py", + "version": "0.20.0", + "description": "Python bindings to Rust's persistent data structures (rpds)", + "hashes": [ + { + "alg": "SHA-256", + "content": "3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/rpds-py@0.20.0", + "type": "library", + "bom-ref": "pkg:pypi/rpds-py@0.20.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Andi Albrecht ", + "group": "", + "name": "sqlparse", + "version": "0.5.1", + "description": "A non-validating SQL parser.", + "hashes": [ + { + "alg": "SHA-256", + "content": "773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4" + } + ], + "licenses": [ + { + "license": { + "id": "0BSD", + "url": "https://opensource.org/licenses/0BSD" + } + } + ], + "purl": "pkg:pypi/sqlparse@0.5.1", + "type": "library", + "bom-ref": "pkg:pypi/sqlparse@0.5.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Alex Grönholm ", + "group": "", + "name": "typeguard", + "version": "4.3.0", + "description": "Run-time type checker for Python", + "hashes": [ + { + "alg": "SHA-256", + "content": "4d24c5b39a117f8a895b9da7a9b3114f04eb63bade45a4492de49b175b6f7dfa" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/typeguard@4.3.0", + "type": "library", + "bom-ref": "pkg:pypi/typeguard@4.3.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "\"Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee\" ", + "group": "", + "name": "typing-extensions", + "version": "4.12.2", + "description": "Backported and Experimental Type Hints for Python 3.8+", + "hashes": [ + { + "alg": "SHA-256", + "content": "04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d" + } + ], + "licenses": [ + { + "license": { + "id": "PSF-2.0", + "url": "https://opensource.org/licenses/PSF-2.0" + } + } + ], + "purl": "pkg:pypi/typing-extensions@4.12.2", + "type": "library", + "bom-ref": "pkg:pypi/typing-extensions@4.12.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Python Software Foundation ", + "group": "", + "name": "tzdata", + "version": "2024.2", + "description": "Provider of IANA time zone data", + "hashes": [ + { + "alg": "SHA-256", + "content": "a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + } + ], + "licenses": [ + { + "license": { + "id": "Apache-2.0", + "url": "https://opensource.org/licenses/Apache-2.0" + } + } + ], + "purl": "pkg:pypi/tzdata@2024.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/python/tzdata" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/tzdata@2024.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Ian Stapleton Cordasco ", + "group": "", + "name": "uritemplate", + "version": "4.1.1", + "description": "Implementation of RFC 6570 URI Templates", + "hashes": [ + { + "alg": "SHA-256", + "content": "830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e" + } + ], + "licenses": [ + { + "expression": "OSI Approved OR BSD 3-Clause License or Apache License, Version 2.0" + } + ], + "purl": "pkg:pypi/uritemplate@4.1.1", + "externalReferences": [ + { + "type": "website", + "url": "https://uritemplate.readthedocs.org" + } + ], + "type": "library", + "bom-ref": "pkg:pypi/uritemplate@4.1.1", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Andrey Petrov ", + "group": "", + "name": "urllib3", + "version": "2.2.3", + "description": "HTTP library with thread-safe connection pooling, file post, and more.", + "hashes": [ + { + "alg": "SHA-256", + "content": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/urllib3@2.2.3", + "type": "library", + "bom-ref": "pkg:pypi/urllib3@2.2.3", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "Konsta Vesterinen ", + "group": "", + "name": "validators", + "version": "0.34.0", + "description": "Python Data Validation for Humans™", + "hashes": [ + { + "alg": "SHA-256", + "content": "c804b476e3e6d3786fa07a30073a4ef694e617805eb1946ceee3fe5a9b8b1321" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/validators@0.34.0", + "type": "library", + "bom-ref": "pkg:pypi/validators@0.34.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "David Evans", + "group": "", + "name": "whitenoise", + "version": "6.7.0", + "description": "Radically simplified static file serving for WSGI applications", + "hashes": [ + { + "alg": "SHA-256", + "content": "a1ae85e01fdc9815d12fa33f17765bc132ed2c54fa76daf9e39e879dd93566f6" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/whitenoise@6.7.0", + "type": "library", + "bom-ref": "pkg:pypi/whitenoise@6.7.0", + "evidence": { + "identity": { + "field": "purl", + "confidence": 1, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 1, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry.lock" + } + ] + } + } + }, + { + "author": "\"Jason R. Coombs\" ", + "group": "", + "name": "zipp", + "version": "3.20.2", + "description": "Backport of pathlib-compatible object wrapper for zip files", + "hashes": [ + { + "alg": "SHA-256", + "content": "a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350" + } + ], + "licenses": [ + { + "license": { + "id": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + } + ], + "purl": "pkg:pypi/zipp@3.20.2", + "type": "library", + "bom-ref": "pkg:pypi/zipp@3.20.2", + "evidence": { + "identity": { + "field": "purl", + "confidence": 0.8, + "methods": [ + { + "technique": "manifest-analysis", + "confidence": 0.8, + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + } + }, + "properties": [ + { + "name": "SrcFile", + "value": "/home/runner/work/SecObserve/SecObserve/backend/poetry_requirements.txt" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:pypi/secobserve@1.22.4", + "dependsOn": [ + "pkg:pypi/argon2-cffi@23.1.0", + "pkg:pypi/cvss@3.2", + "pkg:pypi/defusedcsv@2.0.0", + "pkg:pypi/django-cors-headers@4.5.0", + "pkg:pypi/django-csp@3.8", + "pkg:pypi/django-encrypted-model-fields@0.6.5", + "pkg:pypi/django-environ@0.11.2", + "pkg:pypi/django-filter@24.3", + "pkg:pypi/django-picklefield@3.2", + "pkg:pypi/django@5.1.2", + "pkg:pypi/djangorestframework@3.15.2", + "pkg:pypi/drf-spectacular-sidecar@2024.7.1", + "pkg:pypi/drf-spectacular@0.27.2", + "pkg:pypi/gunicorn@23.0.0", + "pkg:pypi/huey@2.5.2", + "pkg:pypi/inflect@7.4.0", + "pkg:pypi/jira@3.8.0", + "pkg:pypi/jsonpickle@3.3.0", + "pkg:pypi/openpyxl@3.1.5", + "pkg:pypi/packageurl-python@0.16.0", + "pkg:pypi/psycopg@3.2.3", + "pkg:pypi/py-ocsf-models@0.1.1", + "pkg:pypi/pymysql@1.1.1", + "pkg:pypi/requests@2.32.3", + "pkg:pypi/validators@0.34.0", + "pkg:pypi/whitenoise@6.7.0" + ] + }, + { + "ref": "pkg:pypi/argon2-cffi@23.1.0", + "dependsOn": [ + "pkg:pypi/argon2-cffi-bindings@21.2.0" + ] + }, + { + "ref": "pkg:pypi/argon2-cffi-bindings@21.2.0", + "dependsOn": [ + "pkg:pypi/cffi@1.17.1" + ] + }, + { + "ref": "pkg:pypi/asgiref@3.8.1", + "dependsOn": [ + "pkg:pypi/typing-extensions@4.12.2" + ] + }, + { + "ref": "pkg:pypi/attrs@24.2.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/certifi@2024.8.30", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/cffi@1.17.1", + "dependsOn": [ + "pkg:pypi/pycparser@2.22" + ] + }, + { + "ref": "pkg:pypi/charset-normalizer@3.4.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/cryptography@43.0.1", + "dependsOn": [ + "pkg:pypi/cffi@1.17.1" + ] + }, + { + "ref": "pkg:pypi/cvss@3.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/defusedcsv@2.0.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/defusedxml@0.7.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/django@5.1.2", + "dependsOn": [ + "pkg:pypi/asgiref@3.8.1", + "pkg:pypi/sqlparse@0.5.1", + "pkg:pypi/tzdata@2024.2" + ] + }, + { + "ref": "pkg:pypi/django-cors-headers@4.5.0", + "dependsOn": [ + "pkg:pypi/asgiref@3.8.1", + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/django-csp@3.8", + "dependsOn": [ + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/django-encrypted-model-fields@0.6.5", + "dependsOn": [ + "pkg:pypi/cryptography@43.0.1", + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/django-environ@0.11.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/django-filter@24.3", + "dependsOn": [ + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/django-picklefield@3.2", + "dependsOn": [ + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/djangorestframework@3.15.2", + "dependsOn": [ + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/dnspython@2.7.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/drf-spectacular@0.27.2", + "dependsOn": [ + "pkg:pypi/django@5.1.2", + "pkg:pypi/djangorestframework@3.15.2", + "pkg:pypi/inflection@0.5.1", + "pkg:pypi/jsonschema@4.23.0", + "pkg:pypi/pyyaml@6.0.2", + "pkg:pypi/uritemplate@4.1.1" + ] + }, + { + "ref": "pkg:pypi/drf-spectacular-sidecar@2024.7.1", + "dependsOn": [ + "pkg:pypi/django@5.1.2" + ] + }, + { + "ref": "pkg:pypi/email-validator@2.1.1", + "dependsOn": [ + "pkg:pypi/dnspython@2.7.0", + "pkg:pypi/idna@3.10" + ] + }, + { + "ref": "pkg:pypi/et-xmlfile@1.1.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/gunicorn@23.0.0", + "dependsOn": [ + "pkg:pypi/packaging@24.1" + ] + }, + { + "ref": "pkg:pypi/huey@2.5.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/idna@3.10", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/inflect@7.4.0", + "dependsOn": [ + "pkg:pypi/more-itertools@10.5.0", + "pkg:pypi/typeguard@4.3.0" + ] + }, + { + "ref": "pkg:pypi/inflection@0.5.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/jira@3.8.0", + "dependsOn": [ + "pkg:pypi/defusedxml@0.7.1", + "pkg:pypi/packaging@24.1", + "pkg:pypi/pillow@10.4.0", + "pkg:pypi/requests-oauthlib@2.0.0", + "pkg:pypi/requests-toolbelt@1.0.0", + "pkg:pypi/requests@2.32.3", + "pkg:pypi/typing-extensions@4.12.2" + ] + }, + { + "ref": "pkg:pypi/jsonpickle@3.3.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/jsonschema@4.23.0", + "dependsOn": [ + "pkg:pypi/attrs@24.2.0", + "pkg:pypi/jsonschema-specifications@2024.10.1", + "pkg:pypi/referencing@0.35.1", + "pkg:pypi/rpds-py@0.20.0" + ] + }, + { + "ref": "pkg:pypi/jsonschema-specifications@2024.10.1", + "dependsOn": [ + "pkg:pypi/referencing@0.35.1" + ] + }, + { + "ref": "pkg:pypi/more-itertools@10.5.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/oauthlib@3.2.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/openpyxl@3.1.5", + "dependsOn": [ + "pkg:pypi/et-xmlfile@1.1.0" + ] + }, + { + "ref": "pkg:pypi/packageurl-python@0.16.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/packaging@24.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pillow@10.4.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/psycopg@3.2.3", + "dependsOn": [ + "pkg:pypi/psycopg-binary@3.2.3", + "pkg:pypi/typing-extensions@4.12.2", + "pkg:pypi/tzdata@2024.2" + ] + }, + { + "ref": "pkg:pypi/psycopg-binary@3.2.3", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/py-ocsf-models@0.1.1", + "dependsOn": [ + "pkg:pypi/email-validator@2.1.1", + "pkg:pypi/pydantic@1.10.15" + ] + }, + { + "ref": "pkg:pypi/pycparser@2.22", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pydantic@1.10.15", + "dependsOn": [ + "pkg:pypi/typing-extensions@4.12.2" + ] + }, + { + "ref": "pkg:pypi/pyjwt@2.9.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pymysql@1.1.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pyyaml@6.0.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/referencing@0.35.1", + "dependsOn": [ + "pkg:pypi/attrs@24.2.0", + "pkg:pypi/rpds-py@0.20.0" + ] + }, + { + "ref": "pkg:pypi/requests@2.32.3", + "dependsOn": [ + "pkg:pypi/certifi@2024.8.30", + "pkg:pypi/charset-normalizer@3.4.0", + "pkg:pypi/idna@3.10", + "pkg:pypi/urllib3@2.2.3" + ] + }, + { + "ref": "pkg:pypi/requests-oauthlib@2.0.0", + "dependsOn": [ + "pkg:pypi/oauthlib@3.2.2", + "pkg:pypi/requests@2.32.3" + ] + }, + { + "ref": "pkg:pypi/requests-toolbelt@1.0.0", + "dependsOn": [ + "pkg:pypi/requests@2.32.3" + ] + }, + { + "ref": "pkg:pypi/rpds-py@0.20.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/sqlparse@0.5.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/typeguard@4.3.0", + "dependsOn": [ + "pkg:pypi/typing-extensions@4.12.2" + ] + }, + { + "ref": "pkg:pypi/typing-extensions@4.12.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/tzdata@2024.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/uritemplate@4.1.1", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/urllib3@2.2.3", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/validators@0.34.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/whitenoise@6.7.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/rapidfuzz@3.10.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pyproject-hooks@1.2.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/zipp@3.20.2", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/importlib-metadata@8.5.0", + "dependsOn": [ + "pkg:pypi/zipp@3.20.2" + ] + }, + { + "ref": "pkg:pypi/msgpack@1.1.0", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/cachecontrol@0.14.0", + "dependsOn": [ + "pkg:pypi/msgpack@1.1.0", + "pkg:pypi/requests@2.32.3" + ] + } + ] +} \ No newline at end of file diff --git a/backend/unittests/import_observations/services/test_import_observations.py b/backend/unittests/import_observations/services/test_import_observations.py index 055e079a3..98036fabd 100644 --- a/backend/unittests/import_observations/services/test_import_observations.py +++ b/backend/unittests/import_observations/services/test_import_observations.py @@ -582,6 +582,16 @@ def _file_upload_licenses( product.license_policy = License_Policy.objects.get(name="Standard") product.save() + license_policy_item = License_Policy_Item( + license_policy=License_Policy.objects.get(name="Standard"), + license_group=None, + license=None, + license_expression="(Apache-2.0 OR BSD-3-Clause) AND MIT", + unknown_license="", + evaluation_result=License_Policy_Evaluation_Result.RESULT_ALLOWED, + ) + license_policy_item.save() + file_upload_parameters = FileUploadParameters( product=product, branch=branch, @@ -656,6 +666,57 @@ def _file_upload_licenses( ), ) + self.assertEqual(license_components[9].name_version, "cryptography:43.0.1") + self.assertEqual(license_components[9].license, None) + self.assertEqual( + license_components[9].license_expression, + "LGPL-3.0-or-later OR BSD-3-Clause", + ) + self.assertEqual( + license_components[9].evaluation_result, + License_Policy_Evaluation_Result.RESULT_ALLOWED, + ) + self.assertEqual( + license_components[9].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_ALLOWED, + ), + ) + + self.assertEqual(license_components[10].name_version, "cvss:3.2") + self.assertEqual(license_components[10].license, None) + self.assertEqual( + license_components[10].license_expression, + "GPL-3.0-or-later AND BSD-3-Clause", + ) + self.assertEqual( + license_components[10].evaluation_result, + License_Policy_Evaluation_Result.RESULT_FORBIDDEN, + ) + self.assertEqual( + license_components[10].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_FORBIDDEN, + ), + ) + + self.assertEqual(license_components[11].name_version, "defusedcsv:2.0.0") + self.assertEqual(license_components[11].license, None) + self.assertEqual( + license_components[11].license_expression, + "(Apache-2.0 OR BSD-3-Clause) AND MIT", + ) + self.assertEqual( + license_components[11].evaluation_result, + License_Policy_Evaluation_Result.RESULT_ALLOWED, + ) + self.assertEqual( + license_components[11].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_ALLOWED, + ), + ) + # --- Third import with some changes --- license_policy = License_Policy.objects.get(name="Standard") @@ -753,6 +814,57 @@ def _file_upload_licenses( ), ) + self.assertEqual(license_components[7].name_version, "cryptography:43.0.1") + self.assertEqual(license_components[7].license, None) + self.assertEqual( + license_components[7].license_expression, + "LGPL-3.0-or-later OR GPL-3.0-or-later", + ) + self.assertEqual( + license_components[7].evaluation_result, + License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED, + ) + self.assertEqual( + license_components[7].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED, + ), + ) + + self.assertEqual(license_components[8].name_version, "cvss:3.2") + self.assertEqual(license_components[8].license, None) + self.assertEqual( + license_components[8].license_expression, + "LGPL-3.0-or-later AND BSD-3-Clause", + ) + self.assertEqual( + license_components[8].evaluation_result, + License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED, + ) + self.assertEqual( + license_components[8].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_REVIEW_REQUIRED, + ), + ) + + self.assertEqual(license_components[9].name_version, "defusedcsv:2.0.0") + self.assertEqual(license_components[9].license, None) + self.assertEqual( + license_components[9].license_expression, + "Apache-2.0 AND (BSD-3-Clause OR MIT)", + ) + self.assertEqual( + license_components[9].evaluation_result, + License_Policy_Evaluation_Result.RESULT_UNKNOWN, + ) + self.assertEqual( + license_components[9].numerical_evaluation_result, + License_Policy_Evaluation_Result.NUMERICAL_RESULTS.get( + License_Policy_Evaluation_Result.RESULT_UNKNOWN, + ), + ) + # --- Fourth import with ignoring the PiPy packages --- license_policy = License_Policy.objects.get(name="Standard") diff --git a/backend/unittests/licenses/api/test_serializers.py b/backend/unittests/licenses/api/test_serializers.py index c54411d89..bc1662257 100644 --- a/backend/unittests/licenses/api/test_serializers.py +++ b/backend/unittests/licenses/api/test_serializers.py @@ -148,7 +148,7 @@ def test_one_must_be_set(self): license_policy_item_serializer.validate(attrs) self.assertEqual( - "[ErrorDetail(string='One of license group, license or unknown license must be set', code='invalid')]", + "[ErrorDetail(string='One of license group, license, license expression or unknown license must be set', code='invalid')]", str(e.exception), ) @@ -157,6 +157,7 @@ def test_only_one_must_be_set(self): attrs = { "license_group": License_Group.objects.get(id=1), "license": License.objects.get(id=1), + "license_expression": "license_expression", "unknown_license": "unknown_license", } @@ -164,6 +165,6 @@ def test_only_one_must_be_set(self): license_policy_item_serializer.validate(attrs) self.assertEqual( - "[ErrorDetail(string='Only one of license group, license or unknown license must be set', code='invalid')]", + "[ErrorDetail(string='Only one of license group, license, license expression or unknown license must be set', code='invalid')]", str(e.exception), ) diff --git a/docs/getting_started/data_model.md b/docs/getting_started/data_model.md index 53881df81..8ee7877e4 100644 --- a/docs/getting_started/data_model.md +++ b/docs/getting_started/data_model.md @@ -106,7 +106,11 @@ The [Linux Foundation](https://www.linuxfoundation.org/) gathers a list of commo #### License Component -A `License Component` is a library or package used in a product that is licensed under a specific license and has an evaluation of the license according to a license policy. +A `License Component` is a library or package used in a product that is licensed under a specific license and has an evaluation of the license according to a license policy. Depending on the license information in the scan report, there are 3 different types of licenses: + +* a license with a known SPDX identifier +* a license expression, if the license expression in the scan report is valid [according to the SPDX specification](https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/) and consists only of known SPDX identifiers +* an unknown license string in all other cases #### License Component Evidence diff --git a/docs/usage/license_management.md b/docs/usage/license_management.md index 41454a622..18745d9e1 100644 --- a/docs/usage/license_management.md +++ b/docs/usage/license_management.md @@ -34,7 +34,7 @@ A License Policy for the Product can be set, when editing the product settings. ![Product set license policy](../assets/images/screenshot_product_license_policy.png){ width="80%" style="display: block; margin: 0 auto" } -If now License Policy is set, all licenses are evaluated as `Unkown`. If a License Policy is set, the licenses are evaluated according to the policy: +If no License Policy is set, all licenses are evaluated as `Unkown`. If a License Policy is set, the licenses are evaluated according to the policy: * **Allowed:** There is no problem using the component with that license. * **Forbidden:** Using the component with that license might lead to legal problems and the component cannot be used for the Product. @@ -42,6 +42,8 @@ If now License Policy is set, all licenses are evaluated as `Unkown`. If a Licen * **Unknown:** The license is not included in the License Policy. * **Ignored:** The component is not relevant for the license management. +License expressions are evaluated by their included licenses, if the operators are either all `AND` or all `OR`. If the operators are mixed or other operators are used, the expression is evaluated as `Unknown`, if there is no explicit rule for this license expression. + A good strategy is to start with an existing License Policy and when needed make a copy of it and adjust the rules to the needs of the Product. ## Managing License Policies @@ -64,7 +66,8 @@ The `Copy` button creates a new License Policy with the same rules, which can be A `License Policy` has a list of items, which are the rules of the policy. It can be * a rule for a **License Group** or -* a rule for a specific **License**, +* a rule for a specific **SPDX license**, +* a rule for a **license expression** or * a rule for an **unkown license** string, e.g. a license that is not in the SPDX list or a license expression. ![License policy item](../assets/images/screenshot_license_policy_item.png){ width="60%" style="display: block; margin: 0 auto" } @@ -77,7 +80,7 @@ Additionally a `License Policy` has a list of user members and a list of authori ## Managing License Groups -A `License Group` is a collection of licenses with similar license conditions. There is a predefined list of license groups, taken from the classification of the [Blue Oak Council](https://blueoakcouncil.org/). +A `License Group` is a collection of licenses with similar license conditions. There is a predefined list of license groups, taken from the classification of the [Blue Oak Council](https://blueoakcouncil.org/). Administrators can import license group from the ScanCode LicenseDB, see [License data import](../integrations/license_data.md#scancode-licensedb). As with `License Policies`, a `License Group` diff --git a/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx b/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx index f78d423c8..1e168ba24 100644 --- a/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx +++ b/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx @@ -61,6 +61,7 @@ const LicenseComponentEmbeddedList = ({ product, expand, purl_type }: LicenseCom ); } filters.push(); + filters.push(); filters.push(); filters.push( )} {!expand && } + {!expand && } {!expand && } {!expand && ( const [loading, setLoading] = useState(false); const [filterBranch, setFilterBranch] = useState(undefined); const [filterSPDXId, setFilterSPDXId] = useState(undefined); + const [filterLicenseExpression, setFilterLicenseExpression] = useState(undefined); const [filterUnknownLicense, setFilterUnknownLicense] = useState(undefined); const [filterEvaluationResult, setFilterEvaluationResult] = useState(undefined); const [filterPURLType, setFilterPURLType] = useState(undefined); @@ -61,6 +62,13 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => filters.push( setFilterSPDXId(e.target.value)} alwaysOn /> ); + filters.push( + setFilterLicenseExpression(e.target.value)} + alwaysOn + /> + ); filters.push( const filters = JSON.parse(storedFilters); setFilterBranch(filters.branch); setFilterSPDXId(filters.spdx_id); + setFilterLicenseExpression(filters.license_expression); setFilterUnknownLicense(filters.unknown_license); setFilterEvaluationResult(filters.evaluation_result); setFilterPURLType(filters.purl_type); @@ -107,12 +116,21 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => localStorage.removeItem("RaStore.license_components.datagrid.expanded"); get_data(); } - }, [filterBranch, filterSPDXId, filterUnknownLicense, filterEvaluationResult, filterPURLType]); // eslint-disable-line react-hooks/exhaustive-deps + }, [ + // eslint-disable-line react-hooks/exhaustive-deps + filterBranch, + filterSPDXId, + filterLicenseExpression, + filterUnknownLicense, + filterEvaluationResult, + filterPURLType, + ]); function storeFilters() { const filterStorage = { branch: filterBranch, spdx_id: filterSPDXId, + license_expression: filterLicenseExpression, unknown_license: filterUnknownLicense, evaluation_result: filterEvaluationResult, purl_type: filterPURLType, @@ -131,6 +149,9 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => if (filterSPDXId) { url += "&spdx_id=" + encodeURIComponent(filterSPDXId); } + if (filterLicenseExpression) { + url += "&license_expression=" + encodeURIComponent(filterLicenseExpression); + } if (filterUnknownLicense) { url += "&unknown_license=" + encodeURIComponent(filterUnknownLicense); } @@ -170,6 +191,7 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => filter: { branch: filterBranch, spdx_id: filterSPDXId, + license_expression: filterLicenseExpression, unknown_license: filterUnknownLicense, evaluation_result: filterEvaluationResult, purl_type: filterPURLType, @@ -204,6 +226,7 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => )} + diff --git a/frontend/src/licenses/license_components/LicenseComponentShow.tsx b/frontend/src/licenses/license_components/LicenseComponentShow.tsx index e076e916b..3ba72d5c6 100644 --- a/frontend/src/licenses/license_components/LicenseComponentShow.tsx +++ b/frontend/src/licenses/license_components/LicenseComponentShow.tsx @@ -68,12 +68,17 @@ export const LicenseComponentComponent = () => { )} + {component.license_expression && ( + + + + )} {component.unknown_license && ( )} - {!component.license && !component.unknown_license && ( + {!component.license && !component.license_expression && !component.unknown_license && ( No license diff --git a/frontend/src/licenses/license_policy_items/LicensePolicyItemAdd.tsx b/frontend/src/licenses/license_policy_items/LicensePolicyItemAdd.tsx index fc7e331ff..4fd76093e 100644 --- a/frontend/src/licenses/license_policy_items/LicensePolicyItemAdd.tsx +++ b/frontend/src/licenses/license_policy_items/LicensePolicyItemAdd.tsx @@ -31,12 +31,14 @@ const LicensePolicyItemAdd = ({ id }: LicensePolicyItemAddProps) => { const [license_group, setLicenseGroup] = useState(); const [license, setLicense] = useState(); + const [license_expression, setLicenseExpression] = useState(); const [unknown_license, setUnknownLicense] = useState(); const [evaluation_result, setEvaluationResult] = useState(); const resetState = () => { setLicenseGroup(undefined); setLicense(undefined); + setLicenseExpression(undefined); setUnknownLicense(undefined); setEvaluationResult(undefined); }; @@ -75,6 +77,7 @@ const LicensePolicyItemAdd = ({ id }: LicensePolicyItemAddProps) => { const data = { license_group: license_group, license: license, + license_expression: license_expression, unknown_license: unknown_license, evaluation_result: evaluation_result, }; @@ -82,6 +85,9 @@ const LicensePolicyItemAdd = ({ id }: LicensePolicyItemAddProps) => { }; const add_item = (data: any, close_dialog: boolean) => { + if (!data.license_expression) { + data.license_expression = ""; + } if (!data.unknown_license) { data.unknown_license = ""; } @@ -152,6 +158,12 @@ const LicensePolicyItemAdd = ({ id }: LicensePolicyItemAddProps) => { > setLicense(e)} /> + setLicenseExpression(e.target.value)} + /> { + if (!data.license_expression) { + data.license_expression = ""; + } if (!data.unknown_license) { data.unknown_license = ""; } const patch = { license_group: data.license_group, license: data.license, + license_expression: data.license_expression, unknown_license: data.unknown_license, evaluation_result: data.evaluation_result, }; @@ -115,6 +119,11 @@ const LicensePolicyItemEdit = ({ license_policy_id, license_policy_item_id }: Li > + , , + , , )} /> + {(is_superuser() || license_policy.is_manager) && ( From 8a46848c850a30dffbda7c3bed7db7418e0e4097 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 27 Nov 2024 15:39:06 +0000 Subject: [PATCH 24/30] feat: reload button for changed frontend (#2277) --- docker/frontend/prod/Dockerfile | 4 ++++ frontend/index.html | 1 + 2 files changed, 5 insertions(+) diff --git a/docker/frontend/prod/Dockerfile b/docker/frontend/prod/Dockerfile index 9aef102c1..fcf653bdc 100644 --- a/docker/frontend/prod/Dockerfile +++ b/docker/frontend/prod/Dockerfile @@ -16,6 +16,10 @@ COPY ./frontend ./ RUN sed -i 's/version_unknown/'"${VERSION}"'/g' ./src/commons/about/About.tsx && \ npm run build +# insert hash of assets to detect changes +RUN ASSET_HASH=$(sha256sum ./build/assets/* | sha256sum | cut -d ' ' -f 1) && \ + sed -i 's/hash_unknown/'"${ASSET_HASH}"'/g' ./build/index.html + WORKDIR /app/lib/runtime-env-cra RUN npm ci diff --git a/frontend/index.html b/frontend/index.html index a2794e988..3e657d6e3 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,7 @@ + SecObserve From b7563a905b509e5b301f816d539df84455d12099 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:44:02 +0100 Subject: [PATCH 25/30] fix(deps): update dependency mermaid to v11.4.1 (#2276) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 34 ++++++++++++++-------------------- frontend/package.json | 2 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 66f81fec9..5c78c73b3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,7 +19,7 @@ "axios": "1.7.8", "chart.js": "4.4.6", "markdown-to-jsx": "7.7.0", - "mermaid": "11.4.0", + "mermaid": "11.4.1", "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", "query-string": "9.1.1", @@ -3129,15 +3129,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "license": "MIT", - "dependencies": { - "@types/trusted-types": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -3253,7 +3244,8 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", @@ -4791,10 +4783,13 @@ } }, "node_modules/dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", - "license": "(MPL-2.0 OR Apache-2.0)" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.1.tgz", + "integrity": "sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/electron-to-chromium": { "version": "1.5.64", @@ -6712,16 +6707,15 @@ } }, "node_modules/mermaid": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.0.tgz", - "integrity": "sha512-mxCfEYvADJqOiHfGpJXLs4/fAjHz448rH0pfY5fAoxiz70rQiDSzUUy4dNET2T08i46IVpjohPd6WWbzmRHiPA==", + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.1.tgz", + "integrity": "sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.0.1", "@iconify/utils": "^2.1.32", "@mermaid-js/parser": "^0.3.0", "@types/d3": "^7.4.3", - "@types/dompurify": "^3.0.5", "cytoscape": "^3.29.2", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", @@ -6729,7 +6723,7 @@ "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.11", "dayjs": "^1.11.10", - "dompurify": "^3.0.11 <3.1.7", + "dompurify": "^3.2.1", "katex": "^0.16.9", "khroma": "^2.1.0", "lodash-es": "^4.17.21", diff --git a/frontend/package.json b/frontend/package.json index d63a3116a..9a66f8865 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,7 @@ "axios": "1.7.8", "chart.js": "4.4.6", "markdown-to-jsx": "7.7.0", - "mermaid": "11.4.0", + "mermaid": "11.4.1", "oidc-client-ts": "3.1.0", "prop-types": "15.8.1", "query-string": "9.1.1", From ad32297f77c88aba8641710394fa950caa979197 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 28 Nov 2024 14:43:39 +0000 Subject: [PATCH 26/30] chore: declutter license component lists (#2281) * chore: declutter license component lists * chore: codequality * feat: sort for detail list --- backend/application/licenses/api/filters.py | 47 +++-- .../application/licenses/api/serializers.py | 18 +- backend/application/licenses/api/views.py | 103 ++++++---- .../0010_license_component_license_name.py | 18 ++ .../migrations/0011_update_license_names.py | 49 +++++ backend/application/licenses/models.py | 1 + .../licenses/queries/license_component.py | 36 ++-- .../services/export_license_components.py | 3 +- .../licenses/services/license_component.py | 7 + .../licenses/services/license_policy.py | 21 +- .../test_authorization_license_components.py | 6 +- .../fixtures/unittests_license_fixtures.json | 2 + .../LicenseComponentEmbeddedList.tsx | 34 ++-- .../LicenseComponentOverview.tsx | 182 +++++++----------- .../LicenseComponentShow.tsx | 14 +- 15 files changed, 319 insertions(+), 222 deletions(-) create mode 100644 backend/application/licenses/migrations/0010_license_component_license_name.py create mode 100644 backend/application/licenses/migrations/0011_update_license_names.py diff --git a/backend/application/licenses/api/filters.py b/backend/application/licenses/api/filters.py index 92e64a8b2..4f11232e0 100644 --- a/backend/application/licenses/api/filters.py +++ b/backend/application/licenses/api/filters.py @@ -2,7 +2,6 @@ from django.utils import timezone from django_filters import ( - BooleanFilter, CharFilter, ChoiceFilter, FilterSet, @@ -28,18 +27,16 @@ class LicenseComponentFilter(FilterSet): name_version = CharFilter(field_name="name_version", lookup_expr="icontains") + license_name = CharFilter(field_name="license_name", lookup_expr="icontains") + license_name_exact = CharFilter(field_name="license_name") license_spdx_id = CharFilter(field_name="license__spdx_id", lookup_expr="icontains") - license_spdx_id_exact = CharFilter(field_name="license__spdx_id") license_expression = CharFilter( field_name="license_expression", lookup_expr="icontains" ) - license_expression_exact = CharFilter(field_name="license_expression") unknown_license = CharFilter(field_name="unknown_license", lookup_expr="icontains") - unknown_license_exact = CharFilter(field_name="unknown_license") age = ChoiceFilter( field_name="age", method="get_age", choices=Age_Choices.AGE_CHOICES ) - no_license = BooleanFilter(field_name="no_license", method="get_no_license") branch_name = CharFilter(field_name="branch__name") def get_age(self, queryset, field_name, value): # pylint: disable=unused-argument @@ -54,13 +51,6 @@ def get_age(self, queryset, field_name, value): # pylint: disable=unused-argume time_threshold = today - timedelta(days=int(days)) return queryset.filter(last_change__gte=time_threshold) - def get_no_license( - self, queryset, field_name, value - ): # pylint: disable=unused-argument - if value is True: - return queryset.filter(license=None, unknown_license="") - return queryset - ordering = ExtendedOrderingFilter( # tuple-mapping retains order fields=( @@ -69,17 +59,39 @@ def get_no_license( ("unknown_license", "unknown_license"), ( ( + "license_name", "numerical_evaluation_result", - "license__spdx_id", - "license_expression", - "unknown_license", + "name_version", + ), + "license_name", + ), + ( + ( + "numerical_evaluation_result", + "license_name", "name_version", ), "evaluation_result", ), - ("branch__name", "branch_name"), + ( + ( + "branch__name", + "license_name", + "numerical_evaluation_result", + "name_version", + ), + "branch_name", + ), ("name_version", "name_version"), - ("purl_type", "purl_type"), + ( + ( + "purl_type", + "numerical_evaluation_result", + "license_name", + "name_version", + ), + "purl_type", + ), ("last_change", "last_change"), ), ) @@ -89,6 +101,7 @@ class Meta: fields = [ "product", "branch", + "license_name", "license_spdx_id", "license_expression", "unknown_license", diff --git a/backend/application/licenses/api/serializers.py b/backend/application/licenses/api/serializers.py index 201e483fb..465df6e6f 100644 --- a/backend/application/licenses/api/serializers.py +++ b/backend/application/licenses/api/serializers.py @@ -99,6 +99,7 @@ class LicenseComponentSerializer(ModelSerializer): evidences: Optional[NestedLicenseComponentEvidenceSerializer] = ( NestedLicenseComponentEvidenceSerializer(many=True) ) + type = SerializerMethodField() title = SerializerMethodField() class Meta: @@ -136,14 +137,17 @@ def get_license_policy_id(self, obj: License_Component) -> int: return 0 - def get_title(self, obj: License_Component) -> str: + def get_type(self, obj: License_Component) -> str: if obj.license: - return f"{obj.license.spdx_id} ({obj.license.name})" + return "SPDX" if obj.license_expression: - return obj.license_expression + return "Expression" if obj.unknown_license: - return obj.unknown_license - return "No license" + return "Unknown" + return "" + + def get_title(self, obj: License_Component) -> str: + return f"{obj.license_name} / {obj.name_version}" class LicenseComponentListSerializer(LicenseComponentSerializer): @@ -170,10 +174,8 @@ class LicenseComponentBulkDeleteSerializer(Serializer): class LicenseComponentOverviewElementSerializer(Serializer): branch_name = CharField() - spdx_id = CharField() license_name = CharField() - license_expression = CharField() - unknown_license = CharField() + type = CharField() evaluation_result = CharField() num_components = IntegerField() diff --git a/backend/application/licenses/api/views.py b/backend/application/licenses/api/views.py index 384a2062d..062a6a4ad 100644 --- a/backend/application/licenses/api/views.py +++ b/backend/application/licenses/api/views.py @@ -1,6 +1,7 @@ from dataclasses import dataclass -from typing import Optional +from typing import Optional, Tuple +from django.db.models.query import QuerySet from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import OpenApiParameter, extend_schema from rest_framework.decorators import action @@ -112,10 +113,8 @@ @dataclass class LicenseComponentOverviewElement: branch_name: Optional[str] - spdx_id: Optional[str] - license_name: Optional[str] - license_expression: Optional[str] - unknown_license: Optional[str] + license_name: str + type: str evaluation_result: str num_components: int @@ -156,43 +155,36 @@ def license_overview(self, request): if not product_id: raise ValidationError("No product id provided") product = _get_product(product_id, Permissions.Product_View) - branch = self._get_branch(product, request.query_params.get("branch")) - spdx_id = request.query_params.get("spdx_id") - license_expression = request.query_params.get("license_expression") - unknown_license = request.query_params.get("unknown_license") - evaluation_result = request.query_params.get("evaluation_result") - purl_type = request.query_params.get("purl_type") - - license_overview_elements = get_license_component_licenses(product, branch) - if spdx_id: - license_overview_elements = license_overview_elements.filter( - license__spdx_id__icontains=spdx_id - ) - if license_expression: - license_overview_elements = license_overview_elements.filter( - license_expression__icontains=license_expression - ) - if unknown_license: - license_overview_elements = license_overview_elements.filter( - unknown_license__icontains=unknown_license - ) - if evaluation_result: - license_overview_elements = license_overview_elements.filter( - evaluation_result=evaluation_result - ) - if purl_type: - license_overview_elements = license_overview_elements.filter( - purl_type=purl_type - ) + filter_branch = self._get_branch(product, request.query_params.get("branch")) + order_by_1, order_by_2, order_by_3 = self._get_ordering( + request.query_params.get("ordering") + ) + + license_overview_elements = get_license_component_licenses( + product, filter_branch, order_by_1, order_by_2, order_by_3 + ) + license_overview_elements = self._filter_data( + request, license_overview_elements + ) results = [] for element in license_overview_elements: + if element["license__spdx_id"]: + license_name = element["license__spdx_id"] + element_type = "SPDX" + elif element["license_expression"]: + license_name = element["license_expression"] + element_type = "Expression" + elif element["unknown_license"]: + license_name = element["unknown_license"] + element_type = "Unknown" + else: + license_name = "No license information" + element_type = "" license_component_overview_element = LicenseComponentOverviewElement( branch_name=element["branch__name"], - spdx_id=element["license__spdx_id"], - license_name=element["license__name"], - license_expression=element["license_expression"], - unknown_license=element["unknown_license"], + license_name=license_name, + type=element_type, evaluation_result=element["evaluation_result"], num_components=element["id__count"], ) @@ -210,6 +202,43 @@ def license_overview(self, request): data=response_serializer.data, ) + def _get_ordering(self, ordering: str) -> Tuple[str, str, str]: + if ordering and ordering == "-branch_name": + return "-branch__name", "-license_name", "-numerical_evaluation_result" + if ordering and ordering == "branch_name": + return "branch__name", "license_name", "numerical_evaluation_result" + + if ordering and ordering == "-license_name": + return "-license_name", "-numerical_evaluation_result", "-branch__name" + if ordering and ordering == "license_name": + return "license_name", "numerical_evaluation_result", "branch__name" + + if ordering and ordering == "-evaluation_result": + return "-numerical_evaluation_result", "-license_name", "-branch__name" + + return "numerical_evaluation_result", "license_name", "branch__name" + + def _filter_data(self, request, license_overview_elements: QuerySet) -> QuerySet: + filter_license_name = request.query_params.get("license_name") + if filter_license_name: + license_overview_elements = license_overview_elements.filter( + license_name__icontains=filter_license_name + ) + + filter_evaluation_result = request.query_params.get("evaluation_result") + if filter_evaluation_result: + license_overview_elements = license_overview_elements.filter( + evaluation_result=filter_evaluation_result + ) + + filter_purl_type = request.query_params.get("purl_type") + if filter_purl_type: + license_overview_elements = license_overview_elements.filter( + purl_type=filter_purl_type + ) + + return license_overview_elements + def _get_branch(self, product: Product, pk: int) -> Optional[Branch]: if not pk: return None diff --git a/backend/application/licenses/migrations/0010_license_component_license_name.py b/backend/application/licenses/migrations/0010_license_component_license_name.py new file mode 100644 index 000000000..067487d61 --- /dev/null +++ b/backend/application/licenses/migrations/0010_license_component_license_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2024-11-27 17:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("licenses", "0009_license_component_license_expression_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="license_component", + name="license_name", + field=models.CharField(blank=True, max_length=255), + ), + ] diff --git a/backend/application/licenses/migrations/0011_update_license_names.py b/backend/application/licenses/migrations/0011_update_license_names.py new file mode 100644 index 000000000..a6e2b6df7 --- /dev/null +++ b/backend/application/licenses/migrations/0011_update_license_names.py @@ -0,0 +1,49 @@ +from django.core.paginator import Paginator +from django.db import migrations + + +def update_license_names(apps, schema_editor): + License_Component = apps.get_model("licenses", "License_Component") + license_components = License_Component.objects.filter(license_name="").order_by( + "id" + ) + + paginator = Paginator(license_components, 1000) + for page_number in paginator.page_range: + page = paginator.page(page_number) + updates = [] + + for license_component in page.object_list: + if license_component.license: + license_component.license_name = license_component.license.spdx_id + elif license_component.license_expression: + license_component.license_name = license_component.license_expression + elif license_component.unknown_license: + license_component.license_name = license_component.unknown_license + else: + license_component.license_name = "No license information" + + updates.append(license_component) + + License_Component.objects.bulk_update( + updates, + [ + "license_name", + ], + ) + + +class Migration(migrations.Migration): + dependencies = [ + ( + "licenses", + "0010_license_component_license_name", + ), + ] + + operations = [ + migrations.RunPython( + update_license_names, + reverse_code=migrations.RunPython.noop, + ), + ] diff --git a/backend/application/licenses/models.py b/backend/application/licenses/models.py index d6a0c95ac..49f990a1b 100644 --- a/backend/application/licenses/models.py +++ b/backend/application/licenses/models.py @@ -114,6 +114,7 @@ class License_Component(Model): cpe = CharField(max_length=255, blank=True) dependencies = TextField(max_length=32768, blank=True) + license_name = CharField(max_length=255, blank=True) license = ForeignKey( License, related_name="license_components", diff --git a/backend/application/licenses/queries/license_component.py b/backend/application/licenses/queries/license_component.py index ce8482704..550df8165 100644 --- a/backend/application/licenses/queries/license_component.py +++ b/backend/application/licenses/queries/license_component.py @@ -67,7 +67,11 @@ def get_license_components() -> QuerySet[License_Component]: def get_license_component_licenses( - product: Product, branch: Optional[Branch] + product: Product, + branch: Optional[Branch], + order_by_1: str, + order_by2: str, + order_by_3: str, ) -> QuerySet: license_components = get_license_components().filter( product=product, @@ -75,20 +79,18 @@ def get_license_component_licenses( if branch: license_components = license_components.filter(branch=branch) - return ( - license_components.values( - "branch__name", - "license__spdx_id", - "license__name", - "license_expression", - "unknown_license", - "evaluation_result", - ) - .annotate(Count("id")) - .order_by( - "numerical_evaluation_result", - "license__spdx_id", - "license_expression", - "unknown_license", - ) + license_components_overview = license_components.values( + "branch__name", + "license__spdx_id", + "license__name", + "license_expression", + "unknown_license", + "evaluation_result", + ).annotate(Count("id")) + + if order_by_1: + return license_components_overview.order_by(order_by_1, order_by2, order_by_3) + + return license_components_overview.order_by( + "numerical_evaluation_result", "license_name", "branch__name" ) diff --git a/backend/application/licenses/services/export_license_components.py b/backend/application/licenses/services/export_license_components.py index 37837c889..fb281eb62 100644 --- a/backend/application/licenses/services/export_license_components.py +++ b/backend/application/licenses/services/export_license_components.py @@ -34,8 +34,7 @@ def _get_license_components(product: Product) -> QuerySet: license_components = license_components.order_by( "numerical_evaluation_result", - "license__name", - "unknown_license", + "license_name", "name_version", ) diff --git a/backend/application/licenses/services/license_component.py b/backend/application/licenses/services/license_component.py index 0aaf2b3b9..a89326761 100644 --- a/backend/application/licenses/services/license_component.py +++ b/backend/application/licenses/services/license_component.py @@ -83,6 +83,7 @@ def process_license_components( existing_component.purl_type = unsaved_component.purl_type existing_component.cpe = unsaved_component.cpe existing_component.dependencies = unsaved_component.dependencies + existing_component.license_name = unsaved_component.license_name existing_component.license = unsaved_component.license existing_component.license_expression = unsaved_component.license_expression existing_component.unknown_license = unsaved_component.unknown_license @@ -200,6 +201,8 @@ def _prepare_license(component: License_Component) -> None: component.license_expression = "" component.unknown_license = "" + component.license_name = component.unsaved_license + if component.unsaved_license: component.license = get_license_by_spdx_id(component.unsaved_license) if not component.license: @@ -210,11 +213,15 @@ def _prepare_license(component: License_Component) -> None: ) if not expression_info.errors: component.license_expression = expression_info.normalized_expression + component.license_name = component.license_expression else: component.unknown_license = component.unsaved_license except Exception: component.unknown_license = component.unsaved_license + if not component.license_name: + component.license_name = "No license information" + def license_components_bulk_delete(product: Product, component_ids: list[int]) -> None: components = _check_components(product, component_ids) diff --git a/backend/application/licenses/services/license_policy.py b/backend/application/licenses/services/license_policy.py index 7e2068649..53df6a3da 100644 --- a/backend/application/licenses/services/license_policy.py +++ b/backend/application/licenses/services/license_policy.py @@ -180,7 +180,7 @@ def _get_license_policy(product: Product) -> Optional[License_Policy]: def _evaluate_license_expression( component: License_Component, evaluation_results: dict ) -> Optional[str]: - evaluation_result = None + evaluation_result = License_Policy_Evaluation_Result.RESULT_UNKNOWN try: licensing = get_spdx_licensing() @@ -195,18 +195,21 @@ def _evaluate_license_expression( licenses = [] for arg in parsed_expression.args: if isinstance(arg, LicenseSymbol): - my_license = get_license_by_spdx_id(arg.key) - if not my_license: + spdx_license = get_license_by_spdx_id(arg.key) + if not spdx_license: return evaluation_result - licenses.append(my_license) + licenses.append(spdx_license) else: - return evaluation_result + return evaluation_results.get( + f"expression_{component.license_expression}" + ) evaluation_result_set = set() - for my_license in licenses: - evaluation_result_set.add( - evaluation_results.get(f"spdx_{my_license.spdx_id}") - ) + for spdx_license in licenses: + if evaluation_results.get(f"spdx_{spdx_license.spdx_id}"): + evaluation_result_set.add( + evaluation_results.get(f"spdx_{spdx_license.spdx_id}") + ) if operator == "AND": evaluation_result = _evaluate_and_expression(evaluation_result_set) diff --git a/backend/unittests/access_control/api/test_authorization_license_components.py b/backend/unittests/access_control/api/test_authorization_license_components.py index cc2cd823e..48ae94593 100644 --- a/backend/unittests/access_control/api/test_authorization_license_components.py +++ b/backend/unittests/access_control/api/test_authorization_license_components.py @@ -16,14 +16,14 @@ def test_authorization_license_components_product_authorization_group_member(sel self._test_authorization_license_components() def _test_authorization_license_components(self): - expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}, {'id': 2, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'external license', 'identity_hash': 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007', 'upload_filename': '', 'name': 'external_component', 'version': '2.0.0', 'name_version': 'external_component:2.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'external license', 'evaluation_result': 'Review required', 'numerical_evaluation_result': 2, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 2, 'branch': None, 'license': None}]}" + expected_data = "{'count': 2, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'type': 'Unknown', 'title': 'internal license / internal_component:1.0.0', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_name': 'internal license', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}, {'id': 2, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'type': 'Unknown', 'title': 'external license / external_component:2.0.0', 'identity_hash': 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007', 'upload_filename': '', 'name': 'external_component', 'version': '2.0.0', 'name_version': 'external_component:2.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_name': 'external license', 'license_expression': '', 'unknown_license': 'external license', 'evaluation_result': 'Review required', 'numerical_evaluation_result': 2, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 2, 'branch': None, 'license': None}]}" self._test_api( APITest( "db_admin", "get", "/api/license_components/", None, 200, expected_data ) ) - expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}]}" + expected_data = "{'count': 1, 'next': None, 'previous': None, 'results': [{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'type': 'Unknown', 'title': 'internal license / internal_component:1.0.0', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'license_name': 'internal license', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}]}" self._test_api( APITest( "db_internal_write", @@ -34,7 +34,7 @@ def _test_authorization_license_components(self): expected_data, ) ) - expected_data = "{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'license_policy_name': '', 'license_policy_id': 0, 'evidences': [{'id': 1, 'name': 'internal_license_evidence_name'}], 'title': 'internal license', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'dependencies': '', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}" + expected_data = "{'id': 1, 'license_data': None, 'purl_namespace': '', 'branch_name': '', 'license_policy_name': '', 'license_policy_id': 0, 'evidences': [{'id': 1, 'name': 'internal_license_evidence_name'}], 'type': 'Unknown', 'title': 'internal license / internal_component:1.0.0', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'upload_filename': '', 'name': 'internal_component', 'version': '1.0.0', 'name_version': 'internal_component:1.0.0', 'purl': '', 'purl_type': '', 'cpe': '', 'dependencies': '', 'license_name': 'internal license', 'license_expression': '', 'unknown_license': 'internal license', 'evaluation_result': 'Allowed', 'numerical_evaluation_result': 1, 'created': '2022-12-15T17:10:35.513000+01:00', 'import_last_seen': '2022-12-15T17:10:35.513000+01:00', 'last_change': '2022-12-15T17:10:35.513000+01:00', 'product': 1, 'branch': None, 'license': None}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/fixtures/unittests_license_fixtures.json b/backend/unittests/fixtures/unittests_license_fixtures.json index f1cd02ae4..4f0106bac 100644 --- a/backend/unittests/fixtures/unittests_license_fixtures.json +++ b/backend/unittests/fixtures/unittests_license_fixtures.json @@ -13,6 +13,7 @@ "purl_type": "", "cpe": "", "dependencies": "", + "license_name": "internal license", "unknown_license": "internal license", "evaluation_result": "Allowed", "numerical_evaluation_result": 1, @@ -35,6 +36,7 @@ "purl_type": "", "cpe": "", "dependencies": "", + "license_name": "external license", "unknown_license": "external license", "evaluation_result": "Review required", "numerical_evaluation_result": 2, diff --git a/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx b/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx index 1e168ba24..a4a683a7b 100644 --- a/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx +++ b/frontend/src/licenses/license_components/LicenseComponentEmbeddedList.tsx @@ -39,6 +39,13 @@ const BulkActionButtons = (product: any) => ( ); +const licenseNameStyle = (type: string): string => { + if (type === "" || type === "Unknown") { + return "italic"; + } + return "normal"; +}; + const LicenseComponentEmbeddedList = ({ product, expand, purl_type }: LicenseComponentEmbeddedListProps) => { const showLicenseComponent = (id: any) => { return "../../../../license_components/" + id + "/show"; @@ -60,9 +67,7 @@ const LicenseComponentEmbeddedList = ({ product, expand, purl_type }: LicenseCom ); } - filters.push(); - filters.push(); - filters.push(); + filters.push(); filters.push( )} - {!expand && } - {!expand && } - {!expand && } + ( + {record.license_name} + )} + /> {!expand && ( { + if (type === "" || type === "Unknown") { + return "italic"; + } + return "normal"; +}; + const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => { const [data, setData] = useState(); const [count, setCount] = useState(0); const [loading, setLoading] = useState(false); - const [filterBranch, setFilterBranch] = useState(undefined); - const [filterSPDXId, setFilterSPDXId] = useState(undefined); - const [filterLicenseExpression, setFilterLicenseExpression] = useState(undefined); - const [filterUnknownLicense, setFilterUnknownLicense] = useState(undefined); - const [filterEvaluationResult, setFilterEvaluationResult] = useState(undefined); - const [filterPURLType, setFilterPURLType] = useState(undefined); const notify = useNotify(); function listFilters(product: any) { @@ -51,90 +53,66 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => filter={{ product: product.id }} alwaysOn > - setFilterBranch(e)} - /> + ); } - filters.push( - setFilterSPDXId(e.target.value)} alwaysOn /> - ); - filters.push( - setFilterLicenseExpression(e.target.value)} - alwaysOn - /> - ); - filters.push( - setFilterUnknownLicense(e.target.value)} - alwaysOn - /> - ); + filters.push(); filters.push( setFilterEvaluationResult(e)} alwaysOn /> ); filters.push( - setFilterPURLType(e)} - alwaysOn - /> + ); return filters; } + const filters = () => { + const storedListContext = localStorage.getItem("RaStore.license_components.overview"); + const listContextObject = storedListContext ? JSON.parse(storedListContext) : {}; + return listContextObject.filter ? listContextObject.filter : { branch: product.repository_default_branch }; + }; + + const sort = () => { + const storedListContext = localStorage.getItem("RaStore.license_components.overview"); + const listContextObject = storedListContext ? JSON.parse(storedListContext) : {}; + return listContextObject.sort + ? { field: listContextObject.sort, order: listContextObject.order } + : { field: "evaluation_result", order: "ASC" }; + }; + const listContext = useList({ + data, + isLoading: loading, + filter: filters(), + sort: sort(), + }); + useEffect(() => { - if (filterBranch === undefined) { - const storedFilters = localStorage.getItem("RaStore.license_components.overview"); - if (storedFilters) { - const filters = JSON.parse(storedFilters); - setFilterBranch(filters.branch); - setFilterSPDXId(filters.spdx_id); - setFilterLicenseExpression(filters.license_expression); - setFilterUnknownLicense(filters.unknown_license); - setFilterEvaluationResult(filters.evaluation_result); - setFilterPURLType(filters.purl_type); - } else { - setFilterBranch(product.repository_default_branch); - } - } else { - localStorage.removeItem("RaStore.license_components.datagrid.expanded"); - get_data(); - } - }, [ - // eslint-disable-line react-hooks/exhaustive-deps - filterBranch, - filterSPDXId, - filterLicenseExpression, - filterUnknownLicense, - filterEvaluationResult, - filterPURLType, - ]); - - function storeFilters() { - const filterStorage = { - branch: filterBranch, - spdx_id: filterSPDXId, - license_expression: filterLicenseExpression, - unknown_license: filterUnknownLicense, - evaluation_result: filterEvaluationResult, - purl_type: filterPURLType, + storeListContext(); + localStorage.removeItem("RaStore.license_components.datagrid.expanded"); + get_data(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [listContext.sort, listContext.filterValues]); + + function storeListContext() { + // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style + const filterStorage: { [key: string]: any } = {}; + const filter = { + branch: listContext.filterValues.branch, + license_name: listContext.filterValues.license_name, + evaluation_result: listContext.filterValues.evaluation_result, + purl_type: listContext.filterValues.purl_type, }; + filterStorage["filter"] = filter; + if (listContext.sort.field) { + filterStorage["sort"] = listContext.sort.field; + filterStorage["order"] = listContext.sort.order; + } localStorage.setItem("RaStore.license_components.overview", JSON.stringify(filterStorage)); } @@ -143,23 +121,24 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => let url = window.__RUNTIME_CONFIG__.API_BASE_URL + "/license_components/license_overview/?product=" + product.id; - if (filterBranch) { - url += "&branch=" + filterBranch; - } - if (filterSPDXId) { - url += "&spdx_id=" + encodeURIComponent(filterSPDXId); + + const filter = listContext.filterValues; + + if (filter.branch) { + url += "&branch=" + filter.branch; } - if (filterLicenseExpression) { - url += "&license_expression=" + encodeURIComponent(filterLicenseExpression); + if (filter.license_name) { + url += "&license_name=" + encodeURIComponent(filter.license_name); } - if (filterUnknownLicense) { - url += "&unknown_license=" + encodeURIComponent(filterUnknownLicense); + if (filter.evaluation_result) { + url += "&evaluation_result=" + encodeURIComponent(filter.evaluation_result); } - if (filterEvaluationResult) { - url += "&evaluation_result=" + encodeURIComponent(filterEvaluationResult); + if (filter.purl_type) { + url += "&purl_type=" + encodeURIComponent(filter.purl_type); } - if (filterPURLType) { - url += "&purl_type=" + encodeURIComponent(filterPURLType); + + if (listContext.sort.field) { + url += "&ordering=" + (listContext.sort.order === "ASC" ? "" : "-") + listContext.sort.field; } httpClient(url, { @@ -181,23 +160,9 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => } }); - storeFilters(); setLoading(false); } - const listContext = useList({ - data, - isLoading: loading, - filter: { - branch: filterBranch, - spdx_id: filterSPDXId, - license_expression: filterLicenseExpression, - unknown_license: filterUnknownLicense, - evaluation_result: filterEvaluationResult, - purl_type: filterPURLType, - }, - }); - return (
@@ -215,20 +180,21 @@ const LicenseComponentOverview = ({ product }: LicenseComponentOverviewProps) => } expandSingle > - {product && product.has_branches && ( - - )} - - - - - + {product && product.has_branches && } + ( + {record.license_name} + )} + /> + diff --git a/frontend/src/licenses/license_components/LicenseComponentShow.tsx b/frontend/src/licenses/license_components/LicenseComponentShow.tsx index 3ba72d5c6..10d9ea227 100644 --- a/frontend/src/licenses/license_components/LicenseComponentShow.tsx +++ b/frontend/src/licenses/license_components/LicenseComponentShow.tsx @@ -75,14 +75,20 @@ export const LicenseComponentComponent = () => { )} {component.unknown_license && ( - + )} {!component.license && !component.license_expression && !component.unknown_license && ( - - No license - + )} From a420545c61a06b2f2b524565054b71d6b75f81d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:01:52 +0100 Subject: [PATCH 27/30] fix(deps): update dependency pyjwt to v2.10.1 (#2279) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- backend/poetry.lock | 8 ++++---- backend/pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index 31140e560..70fc5cce9 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1942,13 +1942,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.10.0" +version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" files = [ - {file = "PyJWT-2.10.0-py3-none-any.whl", hash = "sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15"}, - {file = "pyjwt-2.10.0.tar.gz", hash = "sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c"}, + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, ] [package.extras] @@ -2543,4 +2543,4 @@ unittests = ["coverage", "django-coverage-plugin", "django-extensions"] [metadata] lock-version = "2.0" python-versions = ">= 3.10, < 3.13" -content-hash = "53a983749039fc198d75344e7582213bd37fb63eba195c634ac7afdbb45a53cb" +content-hash = "005ffaf714df6c69715a84a3d8f050f1febd1044c65d640119b9e5aff28cf605" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9e103bf6a..e130f1c49 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -30,7 +30,7 @@ drf-spectacular = "0.27.2" # https://github.com/tfranzel/drf-spectacular drf-spectacular-sidecar = "2024.11.1" # https://github.com/tfranzel/drf-spectacular-sidecar # Token authentication # ------------------------------------------------------------------------------ -PyJWT = "2.10.0" # https://github.com/jpadilla/pyjwt +PyJWT = "2.10.1" # https://github.com/jpadilla/pyjwt # HTTP requests # ------------------------------------------------------------------------------ requests = "2.32.3" # https://github.com/psf/requests From 743f67abbc543e9ac7f6d68ad7598f369d6cb0fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:22:50 +0100 Subject: [PATCH 28/30] chore(deps): update dependency @types/node to v22.10.1 (#2278) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- end_to_end_tests/package-lock.json | 8 ++++---- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index 428380c74..d2bdb16cb 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -9,7 +9,7 @@ "version": "1.22.4", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.10.0" + "@types/node": "22.10.1" } }, "node_modules/@playwright/test": { @@ -29,9 +29,9 @@ } }, "node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index d0382d8a1..6bd1b2d84 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -9,6 +9,6 @@ "author": "", "devDependencies": { "@playwright/test": "1.49.0", - "@types/node": "22.10.0" + "@types/node": "22.10.1" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5c78c73b3..10bb4e2fb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,7 +40,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.10.0", + "@types/node": "22.10.1", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", @@ -3179,9 +3179,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 9a66f8865..3131cec63 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,7 @@ "@microsoft/eslint-formatter-sarif": "3.1.0", "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/inflection": "1.13.2", - "@types/node": "22.10.0", + "@types/node": "22.10.1", "@types/prop-types": "15.7.13", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", From 96ac85dac1c29198f9a8e2d8c04b24bd320ac3aa Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 28 Nov 2024 19:43:41 +0000 Subject: [PATCH 29/30] fix: migration didn't update all license components (#2282) --- .../0012_update_license_names_fix.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 backend/application/licenses/migrations/0012_update_license_names_fix.py diff --git a/backend/application/licenses/migrations/0012_update_license_names_fix.py b/backend/application/licenses/migrations/0012_update_license_names_fix.py new file mode 100644 index 000000000..d86ef39c4 --- /dev/null +++ b/backend/application/licenses/migrations/0012_update_license_names_fix.py @@ -0,0 +1,47 @@ +from django.core.paginator import Paginator +from django.db import migrations + + +def update_license_names(apps, schema_editor): + License_Component = apps.get_model("licenses", "License_Component") + license_components = License_Component.objects.all().order_by("id") + + paginator = Paginator(license_components, 1000) + for page_number in paginator.page_range: + page = paginator.page(page_number) + updates = [] + + for license_component in page.object_list: + if license_component.license: + license_component.license_name = license_component.license.spdx_id + elif license_component.license_expression: + license_component.license_name = license_component.license_expression + elif license_component.unknown_license: + license_component.license_name = license_component.unknown_license + else: + license_component.license_name = "No license information" + + updates.append(license_component) + + License_Component.objects.bulk_update( + updates, + [ + "license_name", + ], + ) + + +class Migration(migrations.Migration): + dependencies = [ + ( + "licenses", + "0011_update_license_names", + ), + ] + + operations = [ + migrations.RunPython( + update_license_names, + reverse_code=migrations.RunPython.noop, + ), + ] From 351663f96645e24d0930de124716788afd4a5ae7 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 28 Nov 2024 20:31:11 +0000 Subject: [PATCH 30/30] chore: prepare for release 1.22.5 (#2283) --- backend/application/__init__.py | 2 +- backend/pyproject.toml | 2 +- .../parsers/cyclone_dx/files/changed/licenses_1.json | 8 ++++---- .../parsers/cyclone_dx/files/licenses_1.json | 8 ++++---- .../services/test_import_observations.py | 2 +- .../vex/api/files/csaf_given_vulnerability.json | 2 +- .../api/files/csaf_given_vulnerability_update.json | 2 +- .../vex/api/files/csaf_product_branches.json | 2 +- .../vex/api/files/csaf_product_given_branch.json | 2 +- .../vex/api/files/csaf_product_no_branch.json | 2 +- .../vex/api/files/csaf_product_no_branch_update.json | 2 +- .../vex/api/files/openvex_given_vulnerability.json | 2 +- .../files/openvex_given_vulnerability_update.json | 2 +- .../vex/api/files/openvex_product_branches.json | 2 +- .../vex/api/files/openvex_product_given_branch.json | 2 +- .../vex/api/files/openvex_product_no_branch.json | 2 +- .../api/files/openvex_product_no_branch_update.json | 2 +- .../vex/services/files/so_csaf_2024_0001_0001.json | 2 +- .../services/files/so_csaf_2024_0001_0001_short.json | 2 +- .../services/files/so_openvex_2024_0001_0001.json | 2 +- docker-compose-prod-mysql.yml | 4 ++-- docker-compose-prod-postgres.yml | 4 ++-- docs/getting_started/installation.md | 4 ++-- end_to_end_tests/package-lock.json | 4 ++-- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- so_configuration_sca_current.yml | 12 ++++++------ 28 files changed, 44 insertions(+), 44 deletions(-) diff --git a/backend/application/__init__.py b/backend/application/__init__.py index 58ddf1da3..e809b7c39 100644 --- a/backend/application/__init__.py +++ b/backend/application/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.22.4" +__version__ = "1.22.5" import pymysql diff --git a/backend/pyproject.toml b/backend/pyproject.toml index e130f1c49..17e879279 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "SecObserve" -version = "1.22.4" +version = "1.22.5" description = "SecObserve is an open source vulnerability management system for software development and cloud environments." license = "BSD-3-Clause" authors = [ diff --git a/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json b/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json index 858441b53..4275ee5d2 100644 --- a/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json +++ b/backend/unittests/import_observations/parsers/cyclone_dx/files/changed/licenses_1.json @@ -31,11 +31,11 @@ ], "component": { "name": "SecObserve", - "version": "1.22.4", + "version": "1.22.5", "description": "SecObserve is an open source vulnerability management system for software development and cloud environments.", "type": "application", - "bom-ref": "pkg:pypi/secobserve@1.22.4", - "purl": "pkg:pypi/secobserve@1.22.4" + "bom-ref": "pkg:pypi/secobserve@1.22.5", + "purl": "pkg:pypi/secobserve@1.22.5" }, "properties": [ { @@ -2786,7 +2786,7 @@ ], "dependencies": [ { - "ref": "pkg:pypi/secobserve@1.22.4", + "ref": "pkg:pypi/secobserve@1.22.5", "dependsOn": [ "pkg:pypi/argon2-cffi@23.1.0", "pkg:pypi/cvss@3.2", diff --git a/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json b/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json index 1356dfdef..7fbc42784 100644 --- a/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json +++ b/backend/unittests/import_observations/parsers/cyclone_dx/files/licenses_1.json @@ -31,11 +31,11 @@ ], "component": { "name": "SecObserve", - "version": "1.22.4", + "version": "1.22.5", "description": "SecObserve is an open source vulnerability management system for software development and cloud environments.", "type": "application", - "bom-ref": "pkg:pypi/secobserve@1.22.4", - "purl": "pkg:pypi/secobserve@1.22.4" + "bom-ref": "pkg:pypi/secobserve@1.22.5", + "purl": "pkg:pypi/secobserve@1.22.5" }, "properties": [ { @@ -2789,7 +2789,7 @@ ], "dependencies": [ { - "ref": "pkg:pypi/secobserve@1.22.4", + "ref": "pkg:pypi/secobserve@1.22.5", "dependsOn": [ "pkg:pypi/argon2-cffi@23.1.0", "pkg:pypi/cvss@3.2", diff --git a/backend/unittests/import_observations/services/test_import_observations.py b/backend/unittests/import_observations/services/test_import_observations.py index 98036fabd..fa73e5e39 100644 --- a/backend/unittests/import_observations/services/test_import_observations.py +++ b/backend/unittests/import_observations/services/test_import_observations.py @@ -542,7 +542,7 @@ def _file_upload_licenses( ) self.assertEqual(license_components[1].purl_type, "pypi") self.assertEqual(license_components[1].cpe, "") - dependencies = """SecObserve:1.22.4 --> argon2-cffi:23.1.0 + dependencies = """SecObserve:1.22.5 --> argon2-cffi:23.1.0 argon2-cffi:23.1.0 --> argon2-cffi-bindings:21.2.0""" self.assertEqual(license_components[1].dependencies, dependencies) self.assertEqual( diff --git a/backend/unittests/vex/api/files/csaf_given_vulnerability.json b/backend/unittests/vex/api/files/csaf_given_vulnerability.json index e3dbe3f05..844dfa2d7 100644 --- a/backend/unittests/vex/api/files/csaf_given_vulnerability.json +++ b/backend/unittests/vex/api/files/csaf_given_vulnerability.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0001", diff --git a/backend/unittests/vex/api/files/csaf_given_vulnerability_update.json b/backend/unittests/vex/api/files/csaf_given_vulnerability_update.json index f56f785a6..2a2e8c27e 100644 --- a/backend/unittests/vex/api/files/csaf_given_vulnerability_update.json +++ b/backend/unittests/vex/api/files/csaf_given_vulnerability_update.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0002", diff --git a/backend/unittests/vex/api/files/csaf_product_branches.json b/backend/unittests/vex/api/files/csaf_product_branches.json index 1f8cee76c..aa197cc7f 100644 --- a/backend/unittests/vex/api/files/csaf_product_branches.json +++ b/backend/unittests/vex/api/files/csaf_product_branches.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0001", diff --git a/backend/unittests/vex/api/files/csaf_product_given_branch.json b/backend/unittests/vex/api/files/csaf_product_given_branch.json index 85d6abab9..750766e83 100644 --- a/backend/unittests/vex/api/files/csaf_product_given_branch.json +++ b/backend/unittests/vex/api/files/csaf_product_given_branch.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0001", diff --git a/backend/unittests/vex/api/files/csaf_product_no_branch.json b/backend/unittests/vex/api/files/csaf_product_no_branch.json index ce6dc2092..f7e69e2af 100644 --- a/backend/unittests/vex/api/files/csaf_product_no_branch.json +++ b/backend/unittests/vex/api/files/csaf_product_no_branch.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0001", diff --git a/backend/unittests/vex/api/files/csaf_product_no_branch_update.json b/backend/unittests/vex/api/files/csaf_product_no_branch_update.json index 18ea78b8e..c36406a76 100644 --- a/backend/unittests/vex/api/files/csaf_product_no_branch_update.json +++ b/backend/unittests/vex/api/files/csaf_product_no_branch_update.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "CSAF_2024_0001_0002", diff --git a/backend/unittests/vex/api/files/openvex_given_vulnerability.json b/backend/unittests/vex/api/files/openvex_given_vulnerability.json index 211a84047..50ee003bf 100644 --- a/backend/unittests/vex/api/files/openvex_given_vulnerability.json +++ b/backend/unittests/vex/api/files/openvex_given_vulnerability.json @@ -47,6 +47,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 1 } \ No newline at end of file diff --git a/backend/unittests/vex/api/files/openvex_given_vulnerability_update.json b/backend/unittests/vex/api/files/openvex_given_vulnerability_update.json index b6c192997..8de179f96 100644 --- a/backend/unittests/vex/api/files/openvex_given_vulnerability_update.json +++ b/backend/unittests/vex/api/files/openvex_given_vulnerability_update.json @@ -37,6 +37,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 2 } \ No newline at end of file diff --git a/backend/unittests/vex/api/files/openvex_product_branches.json b/backend/unittests/vex/api/files/openvex_product_branches.json index ca32cc289..253383c70 100644 --- a/backend/unittests/vex/api/files/openvex_product_branches.json +++ b/backend/unittests/vex/api/files/openvex_product_branches.json @@ -70,6 +70,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 1 } \ No newline at end of file diff --git a/backend/unittests/vex/api/files/openvex_product_given_branch.json b/backend/unittests/vex/api/files/openvex_product_given_branch.json index 51e2cad6a..ccd1ab159 100644 --- a/backend/unittests/vex/api/files/openvex_product_given_branch.json +++ b/backend/unittests/vex/api/files/openvex_product_given_branch.json @@ -28,6 +28,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 1 } \ No newline at end of file diff --git a/backend/unittests/vex/api/files/openvex_product_no_branch.json b/backend/unittests/vex/api/files/openvex_product_no_branch.json index 007777ae9..6f6707505 100644 --- a/backend/unittests/vex/api/files/openvex_product_no_branch.json +++ b/backend/unittests/vex/api/files/openvex_product_no_branch.json @@ -63,6 +63,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 1 } \ No newline at end of file diff --git a/backend/unittests/vex/api/files/openvex_product_no_branch_update.json b/backend/unittests/vex/api/files/openvex_product_no_branch_update.json index 039856466..f55031aba 100644 --- a/backend/unittests/vex/api/files/openvex_product_no_branch_update.json +++ b/backend/unittests/vex/api/files/openvex_product_no_branch_update.json @@ -64,6 +64,6 @@ } ], "timestamp": "2020-01-01T04:30:00+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 2 } \ No newline at end of file diff --git a/backend/unittests/vex/services/files/so_csaf_2024_0001_0001.json b/backend/unittests/vex/services/files/so_csaf_2024_0001_0001.json index 57d0d4f5f..ab670210e 100644 --- a/backend/unittests/vex/services/files/so_csaf_2024_0001_0001.json +++ b/backend/unittests/vex/services/files/so_csaf_2024_0001_0001.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "so_2024_0001_0001", diff --git a/backend/unittests/vex/services/files/so_csaf_2024_0001_0001_short.json b/backend/unittests/vex/services/files/so_csaf_2024_0001_0001_short.json index 0ded5dda0..02d806177 100644 --- a/backend/unittests/vex/services/files/so_csaf_2024_0001_0001_short.json +++ b/backend/unittests/vex/services/files/so_csaf_2024_0001_0001_short.json @@ -18,7 +18,7 @@ "generator": { "engine": { "name": "SecObserve", - "version": "1.22.4" + "version": "1.22.5" } }, "id": "so_2024_0001_0001", diff --git a/backend/unittests/vex/services/files/so_openvex_2024_0001_0001.json b/backend/unittests/vex/services/files/so_openvex_2024_0001_0001.json index 49c14ebd4..3f6e8d1be 100644 --- a/backend/unittests/vex/services/files/so_openvex_2024_0001_0001.json +++ b/backend/unittests/vex/services/files/so_openvex_2024_0001_0001.json @@ -294,6 +294,6 @@ } ], "timestamp": "2024-07-14T11:17:57.668593+00:00", - "tooling": "SecObserve / 1.22.4", + "tooling": "SecObserve / 1.22.5", "version": 1 } \ No newline at end of file diff --git a/docker-compose-prod-mysql.yml b/docker-compose-prod-mysql.yml index 3685b7664..3dfdaae3a 100644 --- a/docker-compose-prod-mysql.yml +++ b/docker-compose-prod-mysql.yml @@ -35,7 +35,7 @@ services: - traefik frontend: - image: maibornwolff/secobserve-frontend:1.22.4 + image: maibornwolff/secobserve-frontend:1.22.5 container_name: "prod_secobserve_frontend" labels: - "traefik.enable=true" @@ -54,7 +54,7 @@ services: - traefik backend: - image: maibornwolff/secobserve-backend:1.22.4 + image: maibornwolff/secobserve-backend:1.22.5 container_name: "prod_secobserve_backend" labels: - "traefik.enable=true" diff --git a/docker-compose-prod-postgres.yml b/docker-compose-prod-postgres.yml index 31f0641a1..cfa57ca5d 100644 --- a/docker-compose-prod-postgres.yml +++ b/docker-compose-prod-postgres.yml @@ -35,7 +35,7 @@ services: - traefik frontend: - image: maibornwolff/secobserve-frontend:1.22.4 + image: maibornwolff/secobserve-frontend:1.22.5 container_name: "prod_secobserve_frontend" labels: - "traefik.enable=true" @@ -54,7 +54,7 @@ services: - traefik backend: - image: maibornwolff/secobserve-backend:1.22.4 + image: maibornwolff/secobserve-backend:1.22.5 container_name: "prod_secobserve_backend" labels: - "traefik.enable=true" diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md index 89ad47fd5..a9acf5723 100644 --- a/docs/getting_started/installation.md +++ b/docs/getting_started/installation.md @@ -45,7 +45,7 @@ services: - default frontend: - image: maibornwolff/secobserve-frontend:1.22.4 + image: maibornwolff/secobserve-frontend:1.22.5 labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`secobserve.localhost`)" @@ -62,7 +62,7 @@ services: - traefik backend: - image: maibornwolff/secobserve-backend:1.22.4 + image: maibornwolff/secobserve-backend:1.22.5 labels: - "traefik.enable=true" - "traefik.http.routers.backend.rule=Host(`secobserve-backend.localhost`)" diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index d2bdb16cb..8503e8d0d 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -1,12 +1,12 @@ { "name": "end_to_end_tests", - "version": "1.22.4", + "version": "1.22.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "end_to_end_tests", - "version": "1.22.4", + "version": "1.22.5", "devDependencies": { "@playwright/test": "1.49.0", "@types/node": "22.10.1" diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index 6bd1b2d84..46730d02a 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -1,6 +1,6 @@ { "name": "end_to_end_tests", - "version": "1.22.4", + "version": "1.22.5", "private": true, "description": "", "main": "index.js", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 10bb4e2fb..650f905cb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "secobserve", - "version": "1.22.4", + "version": "1.22.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secobserve", - "version": "1.22.4", + "version": "1.22.5", "license": "BSD-3-Clause", "dependencies": { "@emotion/react": "11.13.5", diff --git a/frontend/package.json b/frontend/package.json index 3131cec63..da72da9d2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "secobserve", - "version": "1.22.4", + "version": "1.22.5", "license": "BSD-3-Clause", "description": "SecObserve is an open source vulnerability management system for software development and cloud environments.", "private": true, diff --git a/so_configuration_sca_current.yml b/so_configuration_sca_current.yml index 2d8e12758..cfa11ea0c 100644 --- a/so_configuration_sca_current.yml +++ b/so_configuration_sca_current.yml @@ -1,18 +1,18 @@ trivy_image_backend_current: SCANNER: trivy_image - TARGET: "maibornwolff/secobserve-backend:1.22.4" + TARGET: "maibornwolff/secobserve-backend:1.22.5" FURTHER_PARAMETERS: "--pkg-types os --db-repository public.ecr.aws/aquasecurity/trivy-db:2" REPORT_NAME: "trivy_backend_image.json" SO_ORIGIN_SERVICE: "backend" - SO_BRANCH_NAME: "1.22.4" + SO_BRANCH_NAME: "1.22.5" trivy_image_frontend_current: SCANNER: trivy_image - TARGET: "maibornwolff/secobserve-frontend:1.22.4" + TARGET: "maibornwolff/secobserve-frontend:1.22.5" FURTHER_PARAMETERS: "--pkg-types os --db-repository public.ecr.aws/aquasecurity/trivy-db:2" REPORT_NAME: "trivy_frontend_image.json" SO_ORIGIN_SERVICE: "frontend" - SO_BRANCH_NAME: "1.22.4" + SO_BRANCH_NAME: "1.22.5" trivy_filesystem_backend_current: SCANNER: trivy_filesystem @@ -21,7 +21,7 @@ trivy_filesystem_backend_current: FURTHER_PARAMETERS: "--db-repository public.ecr.aws/aquasecurity/trivy-db:2" REPORT_NAME: "trivy_backend_poetry.json" SO_ORIGIN_SERVICE: "backend" - SO_BRANCH_NAME: "1.22.4" + SO_BRANCH_NAME: "1.22.5" trivy_filesystem_frontend_current: SCANNER: trivy_filesystem @@ -30,7 +30,7 @@ trivy_filesystem_frontend_current: FURTHER_PARAMETERS: "--db-repository public.ecr.aws/aquasecurity/trivy-db:2" REPORT_NAME: "trivy_frontend_npm.json" SO_ORIGIN_SERVICE: "frontend" - SO_BRANCH_NAME: "1.22.4" + SO_BRANCH_NAME: "1.22.5" importer: SO_UPLOAD: "true"